Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Защита Enterprise-бинов

Enterprise-бины — это компоненты Java EE, которые реализуют технологию EJB. Enterprise-бины выполняются в контейнере EJB, среде выполнения на сервере GlassFish. Несмотря на прозрачность для разработчика приложений, контейнер EJB предоставляет сервисы системного уровня, такие как транзакции и безопасность, для своих Enterprise-бинов, которые составляют ядро ​​транзакционных приложений Java EE.

Методы Enterprise-бина могут быть защищены одним из следующих способов.

  • Декларативная безопасность (предпочтительно). Выражает требования безопасности компонента приложения, используя дескрипторы развёртывания или аннотации. Наличие аннотации в бизнес-методе класса Enterprise-бина, в которой указываются разрешения метода, — это всё, что необходимо для защиты метода и проверки подлинности в некоторых ситуациях. В этом разделе обсуждается этот простой и эффективный метод защиты Enterprise-бинов.

    Из-за некоторых ограничений, связанных с упрощённым методом защиты Enterprise-бинов, в некоторых случаях может потребоваться использовать дескриптор развёртывания для указания информации о безопасности. Для работы решения на сервере необходимо настроить механизм проверки подлинности. Метод аутентификации сервера GlassFish по умолчанию — базовая аутентификация.

    В этом руководстве объясняется, как вызвать аутентификацию по имени пользователя и паролю путём аннотирования бизнес-методов корпоративного приложения с указанием разрешений для методов.

    Чтобы упростить задачу развёртывания, разработчик приложения может определить роли безопасности. Роль безопасности — это группа разрешений, которые должны иметь пользователи приложения определённого типа для успешного использования приложения. Например, в приложении для расчёта заработной платы некоторые пользователи захотят просматривать свою собственную информацию о заработной плате (сотрудник), некоторым необходимо будет просматривать информацию о заработной плате других (менеджер), а некоторые должны будут иметь возможность изменять информацию о заработной плате других (отдел заработной платы). Разработчик приложения будет определять потенциальных пользователей приложения и какие методы будут им доступны. Затем разработчик приложения будет аннотировать классы или методы Enterprise-бинов, указывая типы пользователей, которым разрешён доступ к этим методам. Использование аннотаций для указания авторизованных пользователей описано в Указание авторизованных пользователей путём объявления ролей безопасности.

    Когда одна из аннотаций используется для определения разрешений метода, установщик автоматически потребует аутентификацию по имени пользователя и паролю. При таком типе аутентификации пользователю предлагается ввести имя пользователя и пароль, которые будут сравниваться с базой данных известных пользователей. Если пользователь найден и пароль совпадает, назначенные ему роли будут сравниваться с ролями, которым разрешён доступ к методу. Если пользователь прошёл проверку подлинности и обнаружил, что у него есть роль, которой разрешён доступ к этому методу, данные будут возвращены пользователю.

    Использование декларативной безопасности обсуждается в Защита Enterprise-бинов с использованием декларативной безопасности.

  • Программная безопасность: для Enterprise-бина — код, встроенный в бизнес-метод, который используется для программного доступа к идентификационной информации вызывающего субъекта и который использует эту информацию для принятия решений по вопросам безопасности. Программная безопасность полезна, когда одной декларативной безопасности недостаточно для реализации модели безопасности приложения.

    В общем случае управление безопасностью должно осуществляться контейнером таким образом, чтобы это было прозрачно для бизнес-методов Enterprise-бинов. Программные API безопасности, описанные в этой главе, следует использовать только в тех редких ситуациях, когда бизнес-методам Enterprise-бина требуется доступ к информации о контексте безопасности, например, когда вы хотите предоставить доступ на основе времени суток или других нетривиальных проверка состояния для конкретной роли.

    Программная безопасность обсуждается в Защита Enterprise-бинов с использованием программной безопасности.

В некоторых материалах этой главы предполагается, что вы уже прочитали главу 35 «Enterprise-бины», главу 36 «Начало работы с Enterprise-бинами» и главу 50 «Введение в безопасность в платформе Java EE».

В этом разделе обсуждается защита приложения Java EE, в котором один или несколько модулей, таких как файлы EJB JAR, упакованы в файл EAR, файл архива, в котором находится приложение. Аннотации безопасности будут использоваться в файлах классов программирования Java для указания авторизованных пользователей и базовой аутентификации или имени пользователя/пароля.

Enterprise-бины часто предоставляют бизнес-логику веб-приложения. В этих случаях упаковка Enterprise-бина в модуль WAR веб-приложения упрощает развёртывание и организацию приложения. Enterprise-бины могут быть упакованы в модуль WAR как файлы классов Java или в файл JAR, который входит в состав модуля WAR. Когда страница сервлета или JavaServer Faces обрабатывает веб-интерфейс, и приложение упаковывается в модуль WAR в виде файла класса Java, безопасность приложения может быть обработана в файле web.xml приложения. EJB в файле WAR может иметь свой собственный дескриптор развёртывания, ejb-jar.xml, если требуется. Защита веб-приложений с использованием web.xml обсуждается в главе 51 «Начало работы по защите веб-приложений».

В следующих разделах описываются декларативные и программные механизмы безопасности, которые можно использовать для защиты ресурсов Enterprise-бина. К защищённым ресурсам относятся методы Enterprise-бинов, которые вызываются из клиентских приложений, веб-компонентов или других Enterprise-бинов.

Для получения дополнительной информации по этой теме прочитайте спецификацию Enterprise JavaBeans 3.2. Этот документ можно загрузить с http://jcp.org/en/jsr/detail?id=345. В главе 12 этой спецификации «Управление безопасностью» обсуждается управление безопасностью Enterprise-бинов.

Защита Enterprise-бинов с использованием декларативной безопасности

Декларативная безопасность позволяет разработчику приложения указывать, каким пользователям разрешён доступ и к каким методам Enterprise-бинов, аутентифицировать этих пользователей с помощью базовой аутентификации. Зачастую человек, разрабатывающий корпоративное приложение, и человек, отвечающий за развёртывание приложения, — разные люди. Разработчик приложения, который использует декларативную безопасность для определения разрешений методов и механизмов аутентификации, передаёт установщику представление безопасности Enterprise-бинов, содержащихся в EJB JAR. При передаче представления безопасности установщику, он/она использует эту информацию для задания разрешений метода для ролей безопасности. Если не передать представление бевзопасности, установщику придётся самостоятельно разобраться, что делает каждый бизнес-метод, чтобы задать разрешения на их выполнение конкретным пользователям.

Представление безопасности состоит из набора ролей безопасности, семантической группировки разрешений, которые должны иметь пользователи определённого типа для доступа к приложению. Роли безопасности должны быть логическими ролями, представляющими тип пользователя. Вы можете определить разрешения метода для каждой роли безопасности. Разрешение метода — это разрешение для вызова определённой группы методов бизнес-интерфейса Enterprise-бина, домашнего интерфейса, интерфейса компонента и/или конечных точек веб-сервиса. После определения разрешений метода для проверки личности пользователя будет использоваться аутентификация по имени пользователя и паролю.

Важно помнить, что роли безопасности используются для определения логического представления безопасности приложения. Их не следует путать с группами пользователей, пользователями, принципалами и другими понятиями, существующими в GlassFish Server. Обратите внимание, что API безопасности Java EE требует, чтобы именам участников группы по умолчанию соответствовали одноимённые роли, но разные реализации стандарта могут разрешать настройку другого значения по умолчанию. В GlassFish Server вам не нужно выполнять никаких дополнительных шагов для назначения ролей, определённых в приложении, пользователям, группам и принципалам, которые являются компонентами пользовательской базы данных в области безопасности file. Это отображение по умолчанию устанавливается в Консоли администрирования сервера GlassFish, как описано в Назначение ролей пользователям и группам.

В следующих разделах показано, как разработчик приложения использует декларативную безопасность для защиты приложения или для создания представления безопасности для передачи установщику.

Указание авторизованных пользователей путём объявления ролей безопасности

В этом разделе обсуждается, как использовать аннотации для указания разрешений для методов класса EJB. Для получения дополнительной информации об этих аннотациях см. Общие аннотации для спецификации платформы Java по ссылке http://jcp.org/en/jsr/detail?id=250.

Разрешения методов могут быть указаны для класса, бизнес-методов класса или для обоих. Права доступа к методу могут быть указаны для метода класса компонента для переопределения значения полномочий метода, указанного для всего класса компонента. Следующие аннотации используются для указания разрешений метода.

  • @DeclareRoles: указывает все роли, которые будет использовать приложение, включая роли, которые не указаны в аннотации @RolesAllowed. Набор ролей безопасности, используемых приложением, представляет собой сумму ролей безопасности, определённых в аннотациях @DeclareRoles и @RolesAllowed.

    Аннотация @DeclareRoles указывается в классе компонента, где она служит для объявления ролей, которые можно проверить (например, путём вызова isCallerInRole) из методов аннотированного класса. При объявлении названия роли, используемой в качестве параметра для метода isCallerInRole(String roleName), объявленное имя должно совпадать со значением параметра.

    В следующем примере кода демонстрируется использование аннотации @DeclareRoles:

    @DeclareRoles("BusinessAdmin")
    public class Calculator {
        ...
    }

    Синтаксис объявления нескольких ролей показан в следующем примере:

    @DeclareRoles({"Administrator", "Manager", "Employee"})
  • @RolesAllowed("список-ролей"): определяет роли безопасности, которым разрешён доступ к методам в приложении. Эта аннотация может быть указана для класса или для одного или нескольких методов. При указании на уровне класса аннотация применяется ко всем методам в классе. При указании в методе аннотация применяется только к этому методу и переопределяет любые значения, указанные на уровне класса.

    Чтобы указать, что никакие роли не авторизованы для доступа к методам в приложении, используйте аннотацию @DenyAll. Чтобы указать, что пользователь в любой роли авторизован для доступа к приложению, используйте аннотацию @PermitAll.

    При использовании вместе с аннотацией @DeclareRoles комбинированный набор ролей безопасности используется приложением.

    В следующем примере кода демонстрируется использование аннотации @RolesAllowed:

    @DeclareRoles({"Administrator", "Manager", "Employee"})
    public class Calculator {
    
        @RolesAllowed("Administrator")
        public void setNewRate(int rate) {
            ...
        }
    }
  • @PermitAll: указывает, что всем ролям безопасности разрешено выполнять указанный метод или методы. Пользователь не проверяется в базе данных, чтобы убедиться, что он/она имеет право доступа к этому приложению.

    Эта аннотация может быть указана для класса или для одного или нескольких методов. Указание этой аннотации для класса означает, что она применяется ко всем методам класса. Указание его на уровне метода означает, что оно применяется только к этому методу.

    В следующем примере кода демонстрируется использование аннотации @PermitAll:

    import javax.annotation.security.*;
    @RolesAllowed("RestrictedUsers")
    public class Calculator {
    
        @RolesAllowed("Administrator")
        public void setNewRate(int rate) {
            //...
        }
        @PermitAll
        public long convertCurrency(long amount) {
            //...
        }
    }
  • @DenyAll: указывает, что никакие роли безопасности не могут выполнять указанный метод или методы. Это означает, что эти методы исключены из выполнения в контейнере Java EE.

    В следующем примере кода демонстрируется использование аннотации @DenyAll:

    import javax.annotation.security.*;
    @RolesAllowed("Users")
    public class Calculator {
        @RolesAllowed("Administrator")
        public void setNewRate(int rate) {
            //...
        }
        @DenyAll
        public long convertCurrency(long amount) {
            //...
        }
    }

В следующем фрагменте кода демонстрируется использование аннотации @DeclareRoles с методом isCallerInRole. В этом примере аннотация @DeclareRoles объявляет роль, которую Enterprise-бин PayrollBean использует для проверки безопасности с помощью isCallerInRole("payroll") чтобы убедиться, что вызывающий субъект имеет право изменять данные о зарплате:

@DeclareRoles("payroll")
@Stateless public class PayrollBean implements Payroll {
    @Resource SessionContext ctx;

    public void updateEmployeeInfo(EmplInfo info) {

        oldInfo = ... read from database;

        // Поле зарплаты могут изменять только субъекты,
        // имеющие роль  "payroll"
        Principal callerPrincipal = ctx.getCallerPrincipal();
        if (info.salary != oldInfo.salary && !ctx.isCallerInRole("payroll")) {
            throw new SecurityException(...);
        }
        ...
    }
    ...
}

В следующем примере кода показано использование аннотации @RolesAllowed:

@RolesAllowed("admin")
public class SomeClass {
    public void aMethod () {...}
    public void bMethod () {...}
    ...
}

@Stateless public class MyBean extends SomeClass implements A  {

    @RolesAllowed("HR")
    public void aMethod () {...}

    public void cMethod () {...}
    ...
}

В этом примере, предполагая, что aMethod, bMethod и cMethod являются методами бизнес-интерфейса A, значениями разрешений для методов aMethod и bMethod являются @RolesAllowed("HR") и @RolesAllowed("admin") соответственно. Разрешения для метода cMethod не указаны.

Для ясности: аннотации не наследуются самим дочерним классом. Вместо этого аннотации применяются к методам родительского класса, которые наследуются дочерним классом.

Указание механизма аутентификации и безопасного соединения

Когда указаны разрешения метода, GlassFish Server будет использовать базовую аутентификацию по имени пользователя и паролю.

Чтобы использовать другой тип аутентификации или требовать защищённого соединения с использованием SSL, укажите эту информацию в дескрипторе развёртывания приложения.

Защита Enterprise-бинов с использованием программной безопасности

Программная безопасность — код, встроенный в бизнес-метод, используется для программного контроля доступа к идентификационной информации вызывающего субъекта и использует эту информацию для принятия решений по вопросам безопасности в самом методе.

В общем случае управление безопасностью должно осуществляться контейнером таким образом, чтобы это было прозрачно для бизнес-методов Enterprise-бина. В этом разделе описывается SecurityContext API и связанные с безопасностью методы EJBContext API. Более новый SecurityContext API дублирует некоторые функции EJBContext API, потому что он предназначен для обеспечения согласованного API для всех контейнеров. Эти API безопасности следует использовать только в тех редких ситуациях, когда бизнес-методам Enterprise-бинов требуется доступ к информации о контексте безопасности.

Интерфейс SecurityContext, как указано в спецификации API безопасности Java EE, определяет три метода, которые позволяют провайдеру бина получать доступ к информации о безопасности вызывающего Enterprise-бин субъекта:

  • getCallerPrincipal() извлекает Principal, который представляет имя аутентифицированного вызывающего субъекта. Это специфичное для контейнера представление вызывающего принципала, и тип может отличаться от типа вызывающего принципала, первоначально установленного HttpAuthenticationMechanism. Этот метод возвращает null для неаутентифицированного пользователя. Обратите внимание, что это поведение отличается от поведения метода EJBContext.getCallerPrincipal(), который возвращает определённого разработчиком принципала для анонимного субъекта.

  • Метод getPrincipalsByType() извлекает всех участников данного типа из аутентифицированного субъекта. Этот метод возвращает пустой Set, если вызывающий субъект не прошёл проверку подлинности или если запрошенный тип не найден.

    Если присутствуют и вызывающий принципал контейнера, и вызывающий принципал приложения, значение, возвращаемое getName(), одинаково для обоих принципалов.

  • isCallerInRole() принимает аргумент String, представляющий роль, подлежащую проверке. Спецификация не определяет способ определения роли, но результат должен быть таким же, как если бы был сделан соответствующий вызов, специфичный для контейнера (например, EJBContext.isCallerInRole()), и должен быть в соответствии с результатом, подразумеваемым спецификациями, которые предписывают поведение отображения ролей.

Интерфейс javax.ejb.EJBContext предоставляет два метода, которые позволяют разработчику компонента получить доступ к информации о безопасности вызывающего Enterprise-бин субъекта.

  • getCallerPrincipal позволяет методам Enterprise-бина получать имя текущего вызывающего принципала. Методы могут, например, использовать имя в качестве ключа к информации в базе данных. Этот метод никогда не возвращает null. Вместо этого он возвращает (специфичный для поставщика) принципала со специальным именем пользователя, чтобы указать анонимного/неаутентифицированного пользователя. Обратите внимание, что это поведение отличается от поведения метода SecurityContext.getCallerPrincipal(), который возвращает значение null для неаутентифицированного вызывающего субъекта.

    В следующем примере кода показано использование метода getCallerPrincipal:

    @Stateless public class EmployeeServiceBean implements EmployeeService {
        @Resource SessionContext ctx;
        @PersistenceContext EntityManager em;
    
        public void changePhoneNumber(...) {
            ...
            // получение принципала вызывающего субъекта
            callerPrincipal = ctx.getCallerPrincipal();
    
            // получение имени вызывающего субъекта
            callerKey = callerPrincipal.getName();
    
            // использование callerKey в качестве первичного ключа для извлечения EmployeeRecord
            EmployeeRecord myEmployeeRecord =
                em.find(EmployeeRecord.class, callerKey);
    
            // обновление номера телефона
            myEmployeeRecord.setPhoneNumber(...);
    
            ...
        }
    }

    В этом примере Enterprise-бин получает имя текущего вызывающего принципала и использует его в качестве первичного ключа для получения объекта EmployeeRecord. В этом примере предполагается, что приложение было развёрнуто так, что текущий вызывающий принципал содержит первичный ключ, используемый для идентификации сотрудников (например, номер сотрудника).

  • isCallerInRole позволяет разработчику кодировать проверки безопасности, которые нельзя легко определить с помощью разрешений метода. Такая проверка может ограничить выполнение запроса заданной ролью или зависеть от информации, хранящейся в базе данных.

    Код Enterprise-бина может использовать метод isCallerInRole, чтобы проверить, назначена ли текущему вызывающему субъекту данная роль безопасности. Роли безопасности определяются разработчиком компонентов или компоновщиком приложений и присваиваются администратором развёртывания субъектам или основным группам, существующим в операционной среде.

    Следующий пример кода иллюстрирует использование метода isCallerInRole:

    @Stateless public class PayrollBean implements Payroll {
         @Resource SessionContext ctx;
    
         public void updateEmployeeInfo(EmplInfo info) {
    
             oldInfo = ... read from database;
    
             // Поле зарплаты могут изменять только субъекты,
             // имеющие роль "payroll"
             if (info.salary != oldInfo.salary &&
                 !ctx.isCallerInRole("payroll")) {
                     throw new SecurityException(...);
             }
             ...
         }
         ...
     }

Таким образом, программная защита может быть использована для динамического управления доступом к методу, например, чтобы ограничить доступ в определённое время суток. Приложение, в котором используются методы getCallerPrincipal и isCallerInRole, описан в Пример converter-secure: программная защита Enterprise-бина.

Передача идентификационной информации (Run-As)

Вы можете указать, следует ли использовать выполнения методов Enterprise-бина от имени вызывающего субъекта или от имени какого-то другого субъекта. Рисунок 52-1 иллюстрирует эту концепцию.

Рисунок 52-1 Передача идентификационной информации

Схема передачи идентификационной информации от клиента через промежуточный контейнер целевому контейнеру

На этом рисунке клиентское приложение выполняет вызов метода Enterprise-бина в промежуточном контейнере EJB. Этот метод Enterprise-бина, в свою очередь, вызывает метод Enterprise-бина в целевом контейнере. Идентификационная информация во время первого вызова является идентификатором вызывающего субъекта. Идентификатором субъекта для второго вызова может быть один из следующих.

  • По умолчанию идентификатор вызывающего промежуточный компонент субъекта передаётся целевому Enterprise-бину. Эта техника используется, когда целевой контейнер доверяет промежуточному контейнеру.

  • Другой, специфичный идентификатор передаётся целевому Enterprise-бину. Эта техника используется, когда целевой контейнер ожидает доступ с использованием определённого идентификатора.

Чтобы передать идентификатор на целевой Enterprise-бин, настройте передаваемый идентификатор для компонента, как описано в Настройке передачи идентификационной информации. Запуск Enterprise-бина на выполнение от имени другого субъекта не влияет на идентификаторы текущих вызывающих субъектов, то есть на идентификаторы субъектов, которым разрешён доступ к методам текущего Enterprise-бина. Указание запуска от имени другого субъекта устанавливает идентификатор субъекта, который будет использоваться Enterprise-бином при выполнении вызовов.

Указание запуска от имени другого субъекта применяется ко всему Enterprise-бину, включая все методы бизнес-интерфейса Enterprise-бина, локальные и удалённые интерфейсы, интерфейс компонента и интерфейсы конечных точек веб-сервиса, методы слушателя сообщений бина, управляемого сообщениями, метод тайм-аута Enterprise-бина и все внутренние методы компонента, которые могут вызываться.

Настройка передачи идентификационной информации

Вы можете настроить выполнение Enterprise-бина от имени другого субъекта с помощью аннотации @RunAs, которая определяет роль приложения во время выполнения в контейнере Java EE. Аннотация может быть указана для класса, что позволяет разработчикам выполнять приложение под определённой ролью. Для роли должно быть установлено соответствие с пользователем/​​группой в области безопасности контейнера. Аннотация @RunAs указывает имя роли в параметре.

Следующий код демонстрирует использование аннотации @RunAs:

@RunAs("Admin")
public class Calculator {
    //....
}

Если указанные роли связаны с несколькими пользователями в GlassFish Server, требуется установить для роли принципала.

Доверие между контейнерами

Если Enterprise-бин разработан так, что для вызова целевого компонента используется либо оригинальный вызывающий субъект, либо другой, предустановленный субъект, то целевой компонент будет получать только передаваемую ему информацию субъекта. Целевой компонент не будет получать никаких данных аутентификации.

Целевой контейнер не может аутентифицировать переданного субъекта. Однако, поскольку переданный субъект используется при проверках авторизации (например, разрешение на доступ к методу или вызов метода isCallerInRole), необходимо иметь уверенность, что подлинность субъекта подтверждена. Поскольку данных для аутентификации передаваемого субъекта нет, целевой компонент должен доверять вызывающему контейнеру в том, что тот передаёт ему информацию корректно аутентифицированного субъекта.

По умолчанию сервер GlassFish настроен на доверие к идентификационной информации, которая передаётся из разных контейнеров. Поэтому не требуется предпринимать каких-либо особых шаги для установления доверительных отношений.

Развёртывание защищённых Enterprise-бинов

Установщик отвечает за обеспечение безопасности скомпонованного приложения после его развёртывания в целевой среде выполнения. Если представление безопасности было предоставлено установщику с использованием аннотаций безопасности и/или дескриптора развёртывания, представление безопасности сопоставляется с механизмами и политиками, используемыми доменом безопасности в целевой среде выполнения, в данном случае GlassFish Server. Если представление безопасности не предоставлено, установщик должен установить соответствующую политику безопасности для приложения Enterprise-бина.

Информация о развёртывании зависит от веб-сервера или сервера приложений.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)