User Tools

Site Tools


java_security

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Last revisionBoth sides next revision
java_security [2007/02/09 12:24] slonopotamusjava_security [2007/04/10 10:39] slonopotamus
Line 1: Line 1:
-[[start|На главную]] 
  
-====== Реализация системы безопасности в Java ====== 
-  Всё нижеописанное исходит из предположения что в Sun хорошо подумали когда 
-  проектировали пермишены, секьюрити-менеджер и всё с ними связанное. 
- 
- 
-===== О чём это вообще ===== 
-В типичном веб-приложении далеко не каждый пользователь может менять любые данные. У кого-то есть доступ только на чтение, кто-то может менять только свои данные, кто-то только данные пользователей из определённой группы или находящиеся в определённом состоянии. Возникает задача разграничивания прав. Есть несколько вариантов её решения. Вариант первый - логика разрешения/запрещения жёстко задаётся в коде. Существует жёстко заданный набор групп с наборами правам. Этот подход работает только до тех пор пока не возникает необходимости изменить эти наборы. Другой подход связан с динамическим созданием групп и динамическим же назначением им прав. И логика по проверке просто проверяет, есть ли у текущего пользователя право на то действие, которое он пытается совершить. 
-==== Что защищать ==== 
-Любые данные. 
-==== Зачем защищать ==== 
-Чтобы разделять, кому что можно, а кому что нельзя делать. 
- 
- 
-===== Аутентификация ===== 
-==== Несортированный трэш ==== 
-<code java> 
-    //Authorization init 
-    Policy.setPolicy(new Policy() 
-    { 
-      public boolean implies(final ProtectionDomain domain, final Permission permission) 
-      { 
-        for (final Principal principal : domain.getPrincipals()) { 
-          if (principal instanceof MyPrincipal) { 
-            //получить откуда-то коллекцию прав принципала и вызвать для них implies, передав в качестве аргумента проверяемый пермишен. 
-          } 
-        } 
-        return false; 
-      } 
-    }); 
-    //Authentication init 
-    final Configuration orig = Configuration.getConfiguration(); 
-    Configuration.setConfiguration(new Configuration() 
-    { 
-      public AppConfigurationEntry[] getAppConfigurationEntry(final String name) 
-      { 
-        return (name.equals("MY_APP")) ? 
-            new AppConfigurationEntry[]{ 
-                new AppConfigurationEntry( 
-                    "com.myApp.security.MyLoginModule", //наша реализация LoginModule. 
-                    AppConfigurationEntry.LoginModuleControlFlag.REQUISITE, 
-                    Collections.<String, Object>emptyMap() 
-                ) 
-            } : orig.getAppConfigurationEntry(name); 
-      } 
- 
-      public void refresh() 
-      { 
-        orig.refresh(); 
-      } 
-    }); 
-    System.setSecurityManager(new SecurityManager()); 
-    //Аутентификация 
-    final String name = "login"; 
-    final String password = "password"; 
-    final LoginContext ctx = new LoginContext("MY_APP", new CallbackHandler() 
-    { 
-      public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException 
-      { 
-        for (final Callback cb : callbacks) 
-        { 
-          if (cb instanceof NameCallback) 
-          { 
-            ((NameCallback) cb).setName(name); 
-          } 
-          else if (cb instanceof PasswordCallback) 
-          { 
-            ((PasswordCallback) cb).setPassword(password.toCharArray()); 
-          } 
-          else 
-          { 
-            throw new UnsupportedCallbackException(cb); 
-          } 
-        } 
-      } 
-    }); 
-    ctx.login(); 
-    //выполнение кода в контексте аутентифицированного пользователя 
-    Subject.doAs(ctx.getSubject(), new PrivilegedAction<Object>() 
-    { 
-      public Object run() 
-      { 
-        //Do something 
-        return null; 
-      } 
-    }); 
-    ctx.logout(); 
-</code> 
- 
-===== Авторизация ===== 
- 
-==== Краткое описание проверки пермишена ==== 
-В Java существует [[http://java.sun.com/j2se/1.5.0/docs/guide/security/spec/security-specTOC.fm.html|встроенный механизм прав]]. 
- 
-  * Проверяется, не равен ли ''null'''у ''System#getSecurityManager()''. 
-    * Если равен, то считается что действие разрешено делать. 
-  * Вызывается [[http://java.sun.com/j2se/1.5.0/docs/api/java/lang/SecurityManager.html#checkPermission(java.security.Permission)|SecurityManager#checkPermission(java.security.Permission)]] 
-  * Берётся текущий ''AccessControlContext'' и вызывается у него метод [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/AccessControlContext.html#checkPermission(java.security.Permission)|AccessControlContext#checkPermission(java.security.Permission)]] 
-  * ''AccessControlContext'' итерейтится по содержащимся в нём ''ProtectionDomain'''ам и у них вызывается метод [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/ProtectionDomain.html#implies(java.security.Permission)|ProtectionDomain#implies(java.security.Permission)]] 
-  * Берётся текущая ''Policy'', у которой вызывается метод [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/Policy.html#implies(java.security.ProtectionDomain, java.security.Permission)|Policy#implies(java.security.ProtectionDomain, java.security.Permission)]] с данным ''ProtectionDomain''ом. 
- 
-==== Компоненты системы авторизации ==== 
- 
-  * [[http://java.sun.com/j2se/1.5.0/docs/api/java/lang/SecurityManager.html|SecurityManager]] - просто фасад над всей системой прав. 
-  * [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/AccessControlContext.html|AccessControlContext]] - контекст с информацией о том, в каких ''ProtectionDomain'''ах выполняется сейчас код. 
-  * [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/ProtectionDomain.html|ProtectionDomain]] - содержит информацию об URL'ах (возможно с сертификатами), из которых получен выполняющийся код, ''ClassLoader'', через который этот код был получен и (**внимание**) коллекцию [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/Principal.html|Principal]]'ов, от имени которых код выполняется. 
-  * [[http://java.sun.com/j2se/1.5.0/docs/api/java/security/Policy.html|Policy]] - хранилище пермишенов, которое определяет какие права у кого есть. 
- 
- 
-==== Внедрение своих правил авторизации ==== 
- 
- 
-=== Principal === 
- 
-Скорее всего у вас в приложении есть класс ''User''. Нужно будет написать реализацию ''Principal'''а для него (Внимание! Не надо делать так чтобы ваш ''User'' реализовывал ''Principal'''а, т.к. отсутствие юзера не означает отсутствие ''Principal'''а). 
- 
-== Примерная реализация == 
-<code java> 
-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; 
-  } 
-} 
-</code> 
- 
- 
-=== Policy === 
-''Policy'' - это как раз то, куда надо всовывать свой код, чтобы делать проверку прав по своей базе, а не по стандартной реализации в policy-файле. Делается это просто - пишется свой класс, наследующийся от ''Policy'' (внимание, если в вашем приложении права могут динамически изменяться, то надо переопределять метод ''implies'', т.к. в стандартной реализации он активно занимается кэшированием пермишенов. 
- 
-> **ВНИМАНИЕ** Считается, что право разрешено, если оно разрешено для **ВСЕХ** ProtectionDomain'ов, находящихся в ''AccessControlContext'''е вызывающего кода. 
- 
- 
- 
-=== Собираем вместе === 
- 
-== Установка Policy == 
-<code java> 
-Policy.setPolicy (new MyPolicy ()); 
-</code> 
- 
-== Включение SecurityManager'а == 
-<code java> 
-if (System.getSecurityManager () != null) { 
-  System.setSecurityManager (new SecurityManager ()); 
-} 
-</code> 
- 
-== Вызов защищённого кода == 
-<code java> 
-try { 
-  final Subject subject = ...; 
-  final T result = Subject.doAs (subject, new PrivilegedExceptionAction<T>() { 
-    public Object run () throws IOException, ServletException { 
-      //выполнить какой-то код, защищённый правами. 
-    } 
-  }); 
-} catch (PrivilegedActionException e) { 
-  ... 
-} 
-</code> 
- 
-== SecurityUtils == 
-Пара методов для удобства. 
- 
-<code java> 
-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); 
-    } 
-  } 
-} 
-</code> 
- 
- 
-===== Альтернативы ===== 
-  * [[http://acegisecurity.org/|Acegi Security]] 
-FIXME 
- 
-===== Permissions Evangelizm ===== 
-FIXME 
- 
-====== JAAS vs Acegi Security ====== 
- 
-===== Java Security (JAAS) ===== 
-{{jsf-ru:plus.gif}} Является стандартом, поддерживается большим количеством технологий (EJB, Servlets, etc) 
- 
-{{jsf-ru:plus.gif}} Простой API 
- 
-{{jsf-ru:plus.gif}} Хорошо документирован 
- 
-{{jsf-ru:minus.gif}} Довольно скудная базовая функциональность 
- 
-{{jsf-ru:minus.gif}} Ограниченное встроенное кэширование (не предполагает изменения набора прав в процессе работы приложения), в случае отключения которого необходимо реализовывать кэширование на уровне приложения 
- 
-{{jsf-ru:minus.gif}} Отсутствуют теги для проверки прав к различным элементам интерфейса (однако возможно их написание) 
- 
-{{jsf-ru:minus.gif}} Политики принятия решений необходимо реализовывать вручную 
- 
-{{jsf-ru:minus.gif}} В некоторых случаях контейнеро-зависим (однако возможно написание контейнеро-независимого кода) 
- 
- 
-===== Acegi Security ===== 
- 
-{{jsf-ru:plus.gif}} Хорошо документирован 
- 
-{{jsf-ru:plus.gif}} Простая интеграция со Spring 
- 
-{{jsf-ru:plus.gif}} Встроенные аудиты 
- 
-{{jsf-ru:plus.gif}} Встроенные интерцепторы (например, для удаления из коллекций недоступных объектов) 
- 
-{{jsf-ru:plus.gif}} Различные политики принятия решений (если все полиси разрешают, если хоть одна полиси разрешает, на основе голосования и очков) 
- 
-{{jsf-ru:plus.gif}} Встроенные теги для проверки прав к различным элементам интерфейса (правда примитивные) 
- 
-{{jsf-ru:plus.gif}} Встроенное кэширование 
- 
-{{jsf-ru:plus.gif}} Контейнеро-независим 
- 
-{{jsf-ru:plus.gif}} Встроенная поддержка опции «запомнить меня» 
- 
-{{jsf-ru:minus.gif}} Многократно более сложный API 
- 
-{{jsf-ru:minus.gif}} Не специфицирован 
- 
-При этом следует учитывать, что имеется возможность оборачивать использование сторонним кодом JAAS’а в обращения к Acegi и наоборот. Так же необходимо понимать, что права виртуальной машины (доступ к файлам, сокетам, работа с класслоадерами и т.д. проверяются через JAAS, поэтому при использовании Acegi в любом случае будет необходимо направлять в него обращения к JAAS). 
java_security.txt · Last modified: 2019/06/12 16:08 by 127.0.0.1