javajakarta-eewildflypayarajakarta-ee-security-api

Why does this simple Jakarta Security example from Soteria work on Payara but not on WildFly?


I'm used to using WildFly for Java/Jakarta EE development and lately I wanted to update a project that is using JAAS for authentication/authorization to the new Jakarta Security API from Jakarta EE 9.1.

I couldn't make it work, so I decided to create the simplest example possible and experiment on different application servers. I took an example from Soteria (as I understand, the reference implementation for Jakarta Security) and created a new Jakarta EE project to deploy on my application servers. The code is available here.

The example includes a very simple identity store for a user reza with password secret1:

@ApplicationScoped
public class TestIdentityStore implements IdentityStore {
    public CredentialValidationResult validate(UsernamePasswordCredential usernamePasswordCredential) {

        if (usernamePasswordCredential.compareTo("reza", "secret1")) {
            return new CredentialValidationResult("reza", new HashSet<>(asList("foo", "bar")));
        }

        return INVALID_RESULT;
    }
}

A servlet contains the custom form authentication mechanism definition that redirects the user to /login.jsf if she's not authenticated. When authenticated, it displays the user name (principal name) and tests the user roles. There's also a logout feature:

@CustomFormAuthenticationMechanismDefinition(
    loginToContinue = @LoginToContinue(
        loginPage="/login.jsf",
        errorPage="" // DRAFT API - must be set to empty for now
    )
)

@WebServlet("/servlet")
@DeclareRoles({ "foo", "bar", "kaz" })
@ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))
public class Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String webName = null;
        if (request.getUserPrincipal() != null) {
            webName = request.getUserPrincipal().getName();
        }
        
        response.getWriter().write(
                "<html><body> This is a servlet <br><br>\n" +
        
                    "web username: " + webName + "<br><br>\n" +
                            
                    "web user has role \"foo\": " + request.isUserInRole("foo") + "<br>\n" +
                    "web user has role \"bar\": " + request.isUserInRole("bar") + "<br>\n" +
                    "web user has role \"kaz\": " + request.isUserInRole("kaz") + "<br><br>\n" + 

                        
                    "<form method=\"POST\">" +
                        "<input type=\"hidden\" name=\"logout\" value=\"true\"  >" +
                        "<input type=\"submit\" value=\"Logout\">" +
                    "</form>" +
                "</body></html>");
    }
    
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if ("true".equals(request.getParameter("logout"))) {
            request.logout();
            request.getSession().invalidate();
        }
        
        doGet(request, response);
    }
}

The login.xhtml page is rendered if the user is redirected to /login.jsf:

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:jsf="http://xmlns.jcp.org/jsf">

    <h:head/>
    
    <h:messages />
    
    <body>
        <p>
            Login to continue
        </p>
    
         <form jsf:id="form">
            <p>
                <strong>Username </strong> 
                <input jsf:id="username" type="text" jsf:value="#{loginBacking.username}" />
            </p>
            <p>
                <strong>Password </strong> 
                <input jsf:id="password" type="password" jsf:value="#{loginBacking.password}" />
            </p>
            <p>
                <input type="submit" value="Login" jsf:action="#{loginBacking.login}" />
            </p>
        </form>
    </body>
</html>

Finally, a JSF backing bean is responsible for dealing with the form and calling the Jakarta Securty API to perform authentication:

@Named
@RequestScoped
public class LoginBacking {
    @Inject
    private SecurityContext securityContext;

    @NotNull
    @Size(min = 3, max = 15, message="Username must be between 3 and 15 characters")
    private String username;
    
    @NotNull
    @Size(min = 5, max = 50, message="Password must be between 5 and 50 characters")
    private String password;
    
    public void login() {
        FacesContext context = FacesContext.getCurrentInstance();
        Credential credential = new UsernamePasswordCredential(username, new Password(password));
        
        AuthenticationStatus status = securityContext.authenticate(
            getRequest(context),
            getResponse(context), 
            withParams().credential(credential));
        
        if (status.equals(SEND_CONTINUE)) {
            // Authentication mechanism has send a redirect, should not
            // send anything to response from JSF now.
            context.responseComplete();
        } else if (status.equals(SEND_FAILURE)) {
            addError(context, "Authentication failed");
        }
        
    }
    
    private static HttpServletResponse getResponse(FacesContext context) {
        return (HttpServletResponse) context.getExternalContext().getResponse();
    }
    
    private static HttpServletRequest getRequest(FacesContext context) {
        return (HttpServletRequest) context.getExternalContext().getRequest();
    }
    
    private static void addError(FacesContext context, String message) {
        context.addMessage(null, new FacesMessage(SEVERITY_ERROR, message, null));
    }

    /* Getters and setters. */
}

As I said, it works as expected on Payara, but on WildFly I get the following exception:

ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /jakarta-security-example/login.jsf: jakarta.servlet.ServletException: java.lang.IllegalStateException: java.io.IOException: java.io.IOException: ELY01177: Authorization failed.
    at jakarta.faces.api//jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:699)
    at jakarta.faces.api//jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:437)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.security.elytron-web.undertow-server@1.10.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
    at org.wildfly.security.elytron-base@1.17.1.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
    at org.wildfly.security.elytron-base@1.17.1.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
    at org.wildfly.security.elytron-base@1.17.1.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
    at org.wildfly.security.elytron-web.undertow-server@1.10.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.core@2.2.12.Final//io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:53)
    at io.undertow.core@2.2.12.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:59)
    at io.undertow.core@2.2.12.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at org.wildfly.security.elytron-web.undertow-server-servlet@1.10.0.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
    at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow@25.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow@25.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
    at io.undertow.core@2.2.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:280)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow@25.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
    at org.wildfly.extension.undertow@25.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
    at org.wildfly.extension.undertow@25.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
    at org.wildfly.extension.undertow@25.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:260)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100)
    at io.undertow.core@2.2.12.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
    at io.undertow.core@2.2.12.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at org.jboss.xnio@3.8.4.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: jakarta.faces.el.EvaluationException: java.lang.IllegalStateException: java.io.IOException: java.io.IOException: ELY01177: Authorization failed.
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.application.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:77)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.application.ActionListenerImpl.getNavigationOutcome(ActionListenerImpl.java:75)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:64)
    at jakarta.faces.api//jakarta.faces.component.UICommand.broadcast(UICommand.java:213)
    at jakarta.faces.api//jakarta.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:852)
    at jakarta.faces.api//jakarta.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1329)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:56)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.lifecycle.Phase.doPhase(Phase.java:72)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:159)
    at jakarta.faces.api//jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:681)
    ... 52 more
Caused by: java.lang.IllegalStateException: java.io.IOException: java.io.IOException: ELY01177: Authorization failed.
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.jaspic.Jaspic.handleCallbacks(Jaspic.java:184)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.jaspic.Jaspic.notifyContainerAboutLogin(Jaspic.java:157)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.HttpMessageContextImpl.notifyContainerAboutLogin(HttpMessageContextImpl.java:261)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.HttpMessageContextImpl.notifyContainerAboutLogin(HttpMessageContextImpl.java:239)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.CustomFormAuthenticationMechanism.validateRequest(CustomFormAuthenticationMechanism.java:53)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.CustomFormAuthenticationMechanism$Proxy$_$$_WeldSubclass.validateRequest$$super(Unknown Source)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.TerminalAroundInvokeInvocationContext.proceedInternal(TerminalAroundInvokeInvocationContext.java:51)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:78)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.cdi.LoginToContinueInterceptor.processContainerInitiatedAuthentication(LoginToContinueInterceptor.java:182)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.cdi.LoginToContinueInterceptor.validateRequest(LoginToContinueInterceptor.java:98)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.cdi.LoginToContinueInterceptor.intercept(LoginToContinueInterceptor.java:76)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.NonTerminalAroundInvokeInvocationContext.proceedInternal(NonTerminalAroundInvokeInvocationContext.java:66)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:78)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.cdi.AutoApplySessionInterceptor.intercept(AutoApplySessionInterceptor.java:65)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeAroundInvoke(InterceptorMethodHandler.java:84)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeInterception(InterceptorMethodHandler.java:72)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.invoke(InterceptorMethodHandler.java:56)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:79)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:68)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.CustomFormAuthenticationMechanism$Proxy$_$$_WeldSubclass.validateRequest(Unknown Source)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
    at deployment.jakarta-security-example.war//jakarta.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism$1347370719$Proxy$_$$_WeldClientProxy.validateRequest(Unknown Source)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.jaspic.HttpBridgeServerAuthModule.validateRequest(HttpBridgeServerAuthModule.java:90)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.jaspic.DefaultServerAuthContext.validateRequest(DefaultServerAuthContext.java:53)
    at org.wildfly.security.elytron-web.undertow-server-servlet@1.10.0.Final//org.wildfly.elytron.web.undertow.server.servlet.ServletSecurityContextImpl.authenticate(ServletSecurityContextImpl.java:182)
    at org.wildfly.security.elytron-web.undertow-server-servlet@1.10.0.Final//org.wildfly.elytron.web.undertow.server.servlet.ServletSecurityContextImpl.authenticate(ServletSecurityContextImpl.java:99)
    at io.undertow.servlet@2.2.12.Final//io.undertow.servlet.spec.HttpServletRequestImpl.authenticate(HttpServletRequestImpl.java:475)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.jaspic.Jaspic.authenticate(Jaspic.java:91)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.SecurityContextImpl.authenticate(SecurityContextImpl.java:82)
    at deployment.jakarta-security-example.war//org.glassfish.soteria.test.LoginBacking.login(LoginBacking.java:59)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.glassfish.jakarta.el@4.0.0//com.sun.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:152)
    at org.glassfish.jakarta.el@4.0.0//com.sun.el.parser.AstValue.invoke(AstValue.java:261)
    at org.glassfish.jakarta.el@4.0.0//com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:237)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.module.web.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.module.web.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.module.web.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.core@4.0.2.Final//org.jboss.weld.module.web.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:70)
    at com.sun.jsf-impl@3.0.0.SP04//com.sun.faces.application.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:67)
    ... 61 more
Caused by: java.io.IOException: java.io.IOException: ELY01177: Authorization failed.
    at org.wildfly.security.jakarta.authentication@2.0.0.Beta1//org.wildfly.security.auth.jaspi.impl.JaspiAuthenticationContext$1.handle(JaspiAuthenticationContext.java:112)
    at org.glassfish.soteria@1.0.1-jbossorg-1//org.glassfish.soteria.mechanisms.jaspic.Jaspic.handleCallbacks(Jaspic.java:178)
    ... 122 more
Caused by: java.io.IOException: ELY01177: Authorization failed.
    at org.wildfly.security.jakarta.authentication@2.0.0.Beta1//org.wildfly.security.auth.jaspi.impl.JaspiAuthenticationContext$1.handleOne(JaspiAuthenticationContext.java:189)
    at org.wildfly.security.jakarta.authentication@2.0.0.Beta1//org.wildfly.security.auth.jaspi.impl.JaspiAuthenticationContext$1.lambda$handle$0(JaspiAuthenticationContext.java:101)
    at org.wildfly.security.jakarta.authentication@2.0.0.Beta1//org.wildfly.security.auth.jaspi.impl.SecurityActions.doPrivileged(SecurityActions.java:39)
    at org.wildfly.security.jakarta.authentication@2.0.0.Beta1//org.wildfly.security.auth.jaspi.impl.JaspiAuthenticationContext$1.handle(JaspiAuthenticationContext.java:100)
    ... 123 more

Note that my project doesn't contain the jboss-web.xml file from Soteria's example, but If I add it the authentication fails every time (even if I input the correct username and password) when using the login page. If I open http://localhost:8080/jakarta-security-example/servlet directly I get:

This is a servlet

web username: null

web user has role "foo": false
web user has role "bar": false
web user has role "kaz": false

And if I click the logout button I get: jakarta.servlet.ServletException: UT010062: No SecurityContext available.

Tried to find answers on Google, but couldn't, so I'm hoping someone here in Stack Overflow might know what's wrong and help me. Thanks!


Solution

  • Solution

    The WildFly server needs additional configuration:

    1. Edit the other Application Security Domain, enter image description here set the Integrated JASPI property to off. enter image description here

    2. Reload the server enter image description here

    There is also a script for this on: https://github.com/wildfly/quickstart/tree/main/ee-security#configure-the-server

    Why? What is Integrated JASPI?

    From https://docs.wildfly.org/25/WildFly_Elytron_Security.html#Elytron_and_Java_EE_Security

    The EE Security API is built on JASPI. Within JASPI we support two different modes of operation 'integrated', and 'non-integrated'. In integrated mode any identity being established during authentication is expected to exist in the associated security domain. With the EE Security APIs however it is quite likely an alternative store will be in use so configuration the mapping to use 'non-integrated' JASPI allows for identities to be dynamically created as required.