User Tools

Site Tools


java_security

This is an old revision of the document!


На главную

Реализация системы безопасности в Java

Всё нижеописанное исходит из предположения что в Sun хорошо подумали когда
проектировали пермишены, секьюрити-менеджер и всё с ними связанное.

О чём это вообще

В типичном веб-приложении далеко не каждый пользователь может менять любые данные. У кого-то есть доступ только на чтение, кто-то может менять только свои данные, кто-то только данные пользователей из определённой группы или находящиеся в определённом состоянии. Возникает задача разграничивания прав. Есть несколько вариантов её решения. Вариант первый - логика разрешения/запрещения жёстко задаётся в коде. Существует жёстко заданный набор групп с наборами правам. Этот подход работает только до тех пор пока не возникает необходимости изменить эти наборы. Другой подход связан с динамическим созданием групп и динамическим же назначением им прав. И логика по проверке просто проверяет, есть ли у текущего пользователя право на то действие, которое он пытается совершить.

Что защищать

Любые данные.

Зачем защищать

Чтобы разделять, кому что можно, а кому что нельзя делать.

Аутентификация

FIXME

Авторизация

Краткое описание проверки пермишена

В Java существует встроенный механизм прав.

Компоненты системы авторизации

  • SecurityManager - просто фасад над всей системой прав.
  • AccessControlContext - контекст с информацией о том, в каких ProtectionDomain'ах выполняется сейчас код.
  • ProtectionDomain - содержит информацию об URL'ах (возможно с сертификатами), из которых получен выполняющийся код, ClassLoader, через который этот код был получен и (внимание) коллекцию Principal'ов, от имени которых код выполняется.
  • Policy - хранилище пермишенов, которое определяет какие права у кого есть.

Внедрение своих правил авторизации

Principal

Скорее всего у вас в приложении есть класс User. Нужно будет написать реализацию Principal'а для него (Внимание! Не надо делать так чтобы ваш User реализовывал Principal'а, т.к. отсутствие юзера не означает отсутствие Principal'а).

Примерная реализация
public class UserPrincipal implements java.security.Principal {
  // ------------------------------ FIELDS ------------------------------
  /**
   * Константа для незарегистрированного пользователя.
   */
  private static final UserPrincipal nullUserPrincipal = new UserPrincipal (null);
  private final User user;
 
  // -------------------------- STATIC METHODS --------------------------
 
  public static UserPrincipal getPrincipal (final User user) {
    return user == null ? nullUserPrincipal : new UserPrincipal (user);
  }
 
  // --------------------------- CONSTRUCTORS ---------------------------
 
  protected UserPrincipal (final User user) {
    super ();
    this.user = user;
  }
 
  // ------------------------ CANONICAL METHODS ------------------------
 
  public boolean equals (final Object obj) {
    if (obj == null || !(obj instanceof UserPrincipal)) {
      return false;
    }
    final UserPrincipal o = (UserPrincipal) obj;
    final User myUser = this.getUser ();
    final User oUser = o.getUser ();
    if (myUser == null && oUser == null) {
      return true;
    } else if (myUser != null && oUser != null) {
      return myUser.equals (oUser);
    } else {
      return false;
    }
  }
 
  public int hashCode () {
    return this.getClass ().hashCode () + (this.user == null ? 13 : this.user.hashCode ());
  }
 
  // ------------------------ INTERFACE METHODS ------------------------
 
  // --------------------- Interface Nullable ---------------------
 
  public boolean isNull () {
    return this.user == null;
  }
 
  // --------------------- Interface Principal ---------------------
 
  public String getName () {
    return this.getClass ().getName () + " " + (this.user == null ? "unregistered" : this.getUser ().getUserId ());
  }
 
  // -------------------------- OTHER METHODS --------------------------
 
  public User getUser () {
    return this.user;
  }
}

Policy

Policy - это как раз то, куда надо всовывать свой код, чтобы делать проверку прав по своей базе, а не по стандартной реализации в policy-файле. Делается это просто - пишется свой класс, наследующийся от Policy (внимание, если в вашем приложении права могут динамически изменяться, то надо переопределять метод implies, т.к. в стандартной реализации он активно занимается кэшированием пермишенов.

ВНИМАНИЕ Считается, что право разрешено, если оно разрешено для ВСЕХ ProtectionDomain'ов, находящихся в AccessControlContext'е вызывающего кода.

Собираем вместе

Установка Policy
Policy.setPolicy (new MyPolicy ());
Включение SecurityManager'а
if (System.getSecurityManager () != null) {
  System.setSecurityManager (new SecurityManager ());
}
Вызов защищённого кода
try {
  final Subject subject = ...;
  final T result = Subject.doAs (subject, new PrivilegedExceptionAction<T>() {
    public Object run () throws IOException, ServletException {
      //выполнить какой-то код, защищённый правами.
    }
  });
} catch (PrivilegedActionException e) {
  ...
}
SecurityUtils

Пара методов для удобства.

public final class SecurityUtils {
  public static boolean hasPermission (final Permission permission) {
    try {
      checkPermission (permission);
      return true;
    } catch (final SecurityException e) {
      return false;
    }
  }
 
  public static void checkPermission (final Permission permission) throws SecurityException {
    if (System.getSecurityManager () != null) {
      System.getSecurityManager ().checkPermission (permission);
    }
  }
}

Альтернативы

Permissions Evangelizm

FIXME

java_security.1171021822.txt.gz · Last modified: 2019/06/12 16:12 (external edit)