EJB без сохранения состояния не знает о ролях, объявленных в web.xml

На самом деле я столкнулся с проблемой распространения ролей, и мне нужна помощь. Я использую Glassfish 4.0 и развертываю войну, содержащую JAX-RS ресурс и EJB с удаленным и локальным представлением для целей тестирования.

Я объявил роли в своих дескрипторах развертывания web.xml и glassfish-web.xml, связанных с файловой областью в Glassfish. Эти роли правильно используются ресурсом JAX-RS, но EJB, похоже, их не видит.

Я покажу вам файлы, которые я использую, а затем результаты различных выходов вызовов, которые я тестировал до сих пор.

TL/DR: извините за очень длинный пост. Пожалуйста, перейдите к ЧАСТИ II / Тесту 2

ЧАСТЬ I: Код

Дескриптор развертывания glassfish-web.xml

<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
    <context-root>/war-test-4</context-root>
        <security-role-mapping>
        <role-name>test</role-name>
        <group-name>test</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>test2</role-name>
        <group-name>test2</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>authenticated</role-name>
        <group-name>authenticated</group-name>
    </security-role-mapping>
</glassfish-web-app>

Дескриптор развертывания web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    <display-name>war-test-4</display-name>
    <servlet>
        <description>JAX-RS Tools Generated - Do not modify</description>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
        <load-on-startup>1</load-on-startup>
        <security-role-ref>
            <description>Test</description>
            <role-name>test</role-name>
            <role-link>test</role-link>
        </security-role-ref>
        <security-role-ref>
            <description>Auth users</description>
            <role-name>authenticated</role-name>
            <role-link>authenticated</role-link>
        </security-role-ref>
        <security-role-ref>
            <description>Test2</description>
            <role-name>test2</role-name>
            <role-link>test2</role-link>
        </security-role-ref>
    </servlet>
    <servlet-mapping>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
        <url-pattern>/jaxrs/*</url-pattern>
    </servlet-mapping>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Admin Resources</web-resource-name>
            <description>Administration resources</description>
            <url-pattern>/jaxrs/*</url-pattern>
            <http-method>GET</http-method>
        </web-resource-collection>
        <auth-constraint>
            <description>TEST</description>
            <role-name>test</role-name>
            <role-name>test2</role-name>
            <role-name>authenticated</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>test-realm</realm-name>
    </login-config>
    <security-role>
        <description>Test</description>
        <role-name>test</role-name>
    </security-role>
    <security-role>
        <description>Auth users</description>
        <role-name>authenticated</role-name>
    </security-role>
    <security-role>
        <description>Test2</description>
        <role-name>test2</role-name>
    </security-role>
</web-app>

EJB без сохранения состояния SessionBeanTest.java

/**
 * Session Bean implementation class SessionBeanTest
 */
@Stateless(mappedName = "SessionBeanTest")
//@RolesAllowed({"authenticated"})
//@DeclareRoles({"authenticated","test","test2"})
public class SessionBeanTest implements SessionBeanRemote, SessionBeanLocal {

    @Resource
    private SessionContext sessionContext;

    @Override
    public String get() {
        return MessageFormat
                .format("EJB Call by :{0} authenticated? : {1} / test2 ? : {2} / test ? : {3}",
                        sessionContext.getCallerPrincipal().getName(),
                        sessionContext.isCallerInRole("authenticated"),
                        sessionContext.isCallerInRole("test2"), sessionContext.isCallerInRole("test"));
    }
}

Моя служба JAX-RS AccessTest.java

@Path("access")
//@DeclareRoles({/*"authenticated","test",*/"test2"})
@Stateless
public class AccessTest {

    @Inject
    private SessionBeanLocal testBean;
    @GET
    @Path("1")
    public Response test(@Context HttpServletRequest req){
        return Response.ok(MessageFormat
                .format("JAX-RS Call by :{0} authenticated? : {1} / test2 ? : {2} / test ? : {3}",
            req.getUserPrincipal().getName(),
                    req.isUserInRole("authenticated"),
                    req.isUserInRole("test2"),
                    req.isUserInRole("test"))).build();

    }

    @GET
    @Path("2")
    public Response test2(){
        return Response.ok(testBean.get()).build();
    }
}

Как вы, наверное, заметили, я прокомментировал аннотации @DeclareRoles и @RolesAllowed как в моем EJB, так и в моем ресурсе JAX-RS. У меня также есть 2 URI в моей службе JAX-RS. Один напрямую предоставляет пользователю информацию и роли, а другой использует EJB для получения той же информации. Оба должны возвращать один и тот же результат, если пользователь вошел в систему.

ЧАСТЬ II: Тесты

Теперь, используя тестер веб-сервиса (Paw на Mac, на основе Curl, очень полезно!), я получаю доступ к обоим URI:

Тест 1: Ни один пользователь не вошел в систему

Вывод для URI /jaxrs/access/1 без пользователя

HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.0  Java/Oracle Corporation/1.7)

Вывод для URI /jaxrs/access/2 без пользователя

HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.0  Java/Oracle Corporation/1.7)

Пока вроде работает по плану, для доступа к ресурсу требуется аутентифицированный пользователь. Но взгляните на второй тест...

Тест 2: пользователь со всеми ролями вошел в систему

Вывод для URI /jaxrs/access/1 со всеми ролями пользователя

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.0  Java/Oracle Corporation/1.7)

JAX-RS Call by :testadmin authenticated? : true / test2 ? : true / test ? : true

Вывод для URI /jaxrs/access/2 со всеми ролями пользователя

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.0  Java/Oracle Corporation/1.7)

EJB Call by :testadmin authenticated? : **false** / test2 ? : **false** / test ? : **false**

Это та часть, которую я не понимаю. Роли, объявленные в web.xml и glassfish-web.xml, не распространяются на EJB, который находится в том же проекте WAR.

Тест 3: раскомментирование аннотации @DeclareRoles в коде

Независимо от того, раскомментирую ли я @DeclareRoles({"authenticated"}) в своем EJB или в моей службе JAX-RS, я получаю следующий вывод:

Вывод для URI /jaxrs/access/1 со всеми ролями пользователя, @DeclareRoles без комментариев

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.0  Java/Oracle Corporation/1.7)

JAX-RS Call by :testadmin authenticated? : true / test2 ? : true / test ? : true

Вывод для URI /jaxrs/access/2 со всеми ролями пользователя, @DeclareRoles без комментариев

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.0  Java/Oracle Corporation/1.7)

EJB Call by :testadmin authenticated? : **true** / test2 ? : **false** / test ? : **false**

Только те роли, которые я объявляю, видны EJB, но служба JAX-RS видит их все

ЧАСТЬ III: Удаленный вызов EJB

У меня также есть чистый Java-клиент для тестирования. Вот :

public class Main {

    public static void main(String[] args) throws Exception {
        getRemoteService();
    }

    public static void getRemoteService() throws Exception {
        String host = "127.0.0.1";
        String port = "3700";
        Properties props = new Properties();
        props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
        props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
        props.setProperty("java.naming.factory.state", "com.sun.cobra.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
        props.setProperty("org.omg.CORBA.ORBInitialHost", host);
        props.setProperty("org.omg.CORBA.ORBInitialPort", port);

        Context amInitial = null;
        amInitial = new InitialContext(props);
        ProgrammaticLogin programmaticLogin = new ProgrammaticLogin();
        programmaticLogin.login("testuser2", "password");
        SessionBeanRemote service = (SessionBeanRemote) amInitial.lookup("SessionBeanTest");
        System.out.println(service.get());
        programmaticLogin.logout();
        programmaticLogin.login("testadmin", "password");
        System.out.println(service.get());
    }
}

Этот клиент использует интерфейс ProgrammaticLogin для входа в систему и использования EJB с CORBA. Я не планирую использовать его, кроме как для тестирования.

Сначала клиент войдет под пользователем с ограниченными правами, затем под пользователем со всеми ролями. Вот результаты теста с использованием этого клиента:

Тест 1: Тестирование удаленного EJB с комментарием @DeclareRoles

EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false
EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false

Тест 2: Тестирование удаленного EJB с раскомментированным @DeclareRoles({"authenticated","test","test2"})

EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false
EJB Call by :ANONYMOUS authenticated? : false / test2 ? : false / test ? : false

Здесь пользователи также не аутентифицированы. Но когда я добавляю аннотацию @RolesAllowed к EJB, я получаю следующее:

Тест 3: Тестирование удаленного EJB с добавленными @DeclareRoles и @RolesAllowed({"authenticated"})

EJB Call by :testuser2 authenticated? : true / test2 ? : true / test ? : false
EJB Call by :testadmin authenticated? : true / test2 ? : true / test ? : true

Это все, что я тестировал до сих пор. Я не понимаю, почему роли, объявленные в дескрипторах развертывания, правильно используются службой JAX-RS, но не компонентом Stateless EJB. Мне нужна ваша помощь в этом, я на самом деле не помещаю стандартные аннотации ролей в каждый EJB.


person mrik974    schedule 20.02.2014    source источник
comment
Привет @ mrik974, ты нашел какое-нибудь решение для распространения ролей и проблемы анонимности?   -  person PHP Avenger    schedule 05.07.2014
comment
Нет, и это все еще очень раздражает меня. Мне пришлось двигаться вперед, но если кто-нибудь найдет решение, я буду очень рад попробовать его.   -  person mrik974    schedule 07.07.2014
comment
Это так сильно расстраивает, и нет никакой помощи доступны на всех. На все такие вопросы, которые я нашел в Интернете, нет ответа :(   -  person PHP Avenger    schedule 07.07.2014
comment
Привет, ребята, у вас есть решения? У меня такая же проблема с GlassFish 4.1. Я даже пытался добавить стеклянную рыбу-ejb-jar.xml, но это тоже не помогло.   -  person Zhao Yi    schedule 25.11.2014


Ответы (2)


Мне ничего не известно ни об одном из EJB 3.2 и спецификации Java EE 7, обязывающие или по крайней мере, рекомендуя контейнеры совместимых реализаций для поддержки объявлений ролей безопасности других. Напротив, эти документы, на мой взгляд, намекают на то, что такие объявления ограничены — по крайней мере, с точки зрения кода «пользовательского пространства» — внутри операционной среды, в которой они были определены.

Что касается ваших наблюдений:

  • GlassFish – это JSR-115- (< em>JACC-) совместимый сервер приложений. В соответствии с §§ 3.1.1–3.1.5, §§ 4.2–4.3 этой спецификации роли, объявленные с помощью элементов web.xml и ejb-jar.xml или эквивалентных аннотаций, должны быть «переведены» в WebRoleRefPermission и EJBRoleRefPermission соответственно поставщиком JACC по умолчанию; таким образом, они несопоставимы. Эти и несколько других специфичных для Java EE Permission доступны, по крайней мере, теоретически, из кода «пользовательского пространства», например. как показано здесь (этот подход все еще работает для меня на GlassFish 4.1).
  • JAX-RS в Java EE --т.е. В частности, Jersey находится поверх инфраструктуры сервлетов. В основном это причина для SecurityContext.isUserInRole(String) и HttpServletRequest.isUserInRole(String) эквивалентен в этом сценарии. Однако для другой гипотетической независимой от сервлетов реализации это было бы не так, и снова потребовалось бы определять роли безопасности дважды.

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

Кроме того, я полностью согласен с тем, что большая нехватка ресурсов на средства безопасности платформы, то есть в частности на JACC и JASPIC, удручает; По крайней мере, я ожидаю, что отдельная глава по каждому из них будет включена в официальное руководство. Если бы не Арьян Таймс обширный коллекция из в-глубина статьи По этому вопросу многие из нас до сих пор остались бы в неведении. Можно только надеяться, что новый JSR-375 поможет изменить это -- и многое другое -- без (надеюсь!) изобретения велосипеда и/или наложения всего поверх Servlet Filters.

person Uux    schedule 13.06.2015
comment
Вы совершенно правы. Но, как вы сказали, это действительно противоречит здравому смыслу... Спасибо за ссылку на блог Арьяна Тийма! - person mrik974; 16.06.2015

Подсказка, как сделать ваш файл web.xml немного короче. Следующее не нужно для сервлета:

<security-role-ref>
    <description>Test2</description>
        <role-name>test2</role-name>
        <role-link>test2</role-link>
</security-role-ref>

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

Ваш тест очень похож на этот: https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic/ejb-propagation

На GlassFish 4.1 (на одну версию выше, чем вы используете) этот тест прошел, если мне не изменяет память.

person dexter meyers    schedule 17.06.2015