IllegalArgumentException: не найден обработчик для ключа 'javax.security.auth.Subject.container'

Я в основном слежу за этим учебником: https://www.ibm.com/developerworks/java/library/j-javaee8-security-api-4/index.html?ca=drs-

Моя среда разработки: TomEE 8.0 M1 Plume

pom.xml

    <dependency>
        <groupId>org.glassfish.soteria</groupId>
        <artifactId>javax.security.enterprise</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>8.0</version>
        <scope>provided</scope>
    </dependency>

ApplicationConfig:

@CustomFormAuthenticationMechanismDefinition(
        loginToContinue = @LoginToContinue(
                loginPage = "/login.xhtml",
                errorPage = "/login.xhtml?error",
                useForwardToLogin = true
        )
)

@ApplicationScoped
@Named
public class ApplicationConfig {
}

TestServlet:

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    @Inject
    SecurityContext securityContext;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        securityContext.isCallerInRole("admin");
    }
}

Зайдите на http://localhost:8080/test, я получаю следующее исключение:

    05-Dec-2018 16:38:39.132 SEVERE [http-nio-8080-exec-219] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [servlet.TestServlet] in context with path [] threw exception
 java.lang.IllegalArgumentException: No handler can be found for the key 'javax.security.auth.Subject.container'
    at javax.security.jacc.PolicyContext.getContext(PolicyContext.java:91)
    at org.glassfish.soteria.authorization.JACC$2.run(JACC.java:175)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.glassfish.soteria.authorization.JACC.getFromContext(JACC.java:173)
    at org.glassfish.soteria.authorization.JACC.getSubject(JACC.java:73)
    at org.glassfish.soteria.authorization.JACC.isCallerInRole(JACC.java:78)
    at org.glassfish.soteria.authorization.spi.impl.ReflectionAndJaccCallerDetailsResolver.isCallerInRole(ReflectionAndJaccCallerDetailsResolver.java:82)
    at org.glassfish.soteria.SecurityContextImpl.isCallerInRole(SecurityContextImpl.java:89)
    at servlet.TestServlet.doGet(TestServlet.java:20)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.openejb.server.httpd.EEFilter.doFilter(EEFilter.java:65)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:44)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:607)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

Я из Spring и Spring Security, но плохо знаком с CDI и EJB.

Не могли бы вы сказать мне, как настроить это handler или я что-то упустил?

Спасибо!

1 ответ

Ошибка вызвана тем, что TomEE не полностью реализует JACC, от которого зависит SPI авторизации по умолчанию ("ReflectionAndJaccCallerDetailsResolver") Soteria.

Обратите внимание, что TomEE фактически поддерживает JACC, но не полностью.

Здесь есть несколько вариантов (от простых до более сложных):

  1. Очевидное; дождитесь финала TomEE 8, который должен заставить это работать так или иначе (используя либо собственную реализацию EE Security, либо иным образом)
  2. Реализуйте SPI, который Soteria использует для авторизации, и вызовите собственные API-интерфейсы TomEE / Tomcat, чтобы сделать то же самое, что реализация по умолчанию теперь использует JACC.
  3. Внесите свой вклад в TomEE и внедрите недостающие биты в их реализацию JACC (или внесите вклад в Tomcat с реализацией только через Интернет). Для этого уже есть JIRA, см. TOMEE-1912

Я планировал предоставить пример для 2. и сделать SPI более очевидным в Soteria 1.1, но, к сожалению, пока не дошел до этого.

Другие вопросы по тегам