You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wildfly 15中Subject.doAs运行EJB不影响EJBContext问题求助

Solution: Fix Anonymous CallerPrincipal in EJBContext When Using Programmatic Login in WildFly

I've run into this exact issue before—when using standard Java SE Subject.doAs or even basic Elytron AuthenticationContext calls, WildFly's EJB container doesn't pick up the security context because it relies on its own internal thread-bound security context, not the generic Java SE one. Here's how to fix it for both traditional security and Elytron setups:

1. First, Fix a Critical Mismatch in Your Code

Looking at your code, your LoginContext uses the security domain "myDomain", but your EJB is annotated with @SecurityDomain("DemoApplicationDomain"). These must match for the security context to be recognized by the EJB container. Update either the LoginContext domain or the EJB's @SecurityDomain value to align.


2. Solution for Traditional WildFly Security Subsystem

Use WildFly's SecurityContextAssociation API to explicitly bind the authenticated subject to the thread's security context—this is what the EJB container looks for:

import org.jboss.security.SecurityContextAssociation;
import org.jboss.security.SecurityContextFactory;
import org.jboss.security.SecurityContext;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

public class RunnableHandlerImpl implements RunnableHandler {
    @Override
    public void runAsPrivileged(final ContextRunnable runnable) throws LoginException {
        LoginContext ctx = new LoginContext("DemoApplicationDomain", new MyCallbackHandler(runnable.getAuthToken()));
        ctx.login();
        Subject subject = ctx.getSubject();
        
        // Create and populate WildFly's security context
        SecurityContext securityContext = SecurityContextFactory.createSecurityContext();
        securityContext.setSubject(subject);
        
        // Save original context to restore later (critical for thread pool reuse)
        SecurityContext oldSecurityContext = SecurityContextAssociation.getSecurityContext();
        
        try {
            // Bind the authenticated context to the thread
            SecurityContextAssociation.setSecurityContext(securityContext);
            // Execute your runnable—EJB will now see the correct principal
            runnable.run();
        } finally {
            // Restore original context and clean up
            SecurityContextAssociation.setSecurityContext(oldSecurityContext);
            ctx.logout();
        }
    }
}

If you're using Elytron, use the native SecurityIdentity.runAs method—it's designed to properly propagate the security context to EJB calls:

import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityDomainManager;
import org.wildfly.security.auth.server.SecurityIdentity;
import javax.security.auth.login.LoginException;

public class RunnableHandlerImpl implements RunnableHandler {
    @Override
    public void runAsPrivileged(final ContextRunnable runnable) throws LoginException {
        // Get the Elytron security domain matching your EJB's @SecurityDomain
        SecurityDomain securityDomain = SecurityDomainManager.getInstance().getSecurityDomain("DemoApplicationDomain");
        if (securityDomain == null) {
            throw new LoginException("Elytron security domain not found");
        }

        // Authenticate to get the SecurityIdentity (adjust to use your AuthToken)
        SecurityIdentity securityIdentity = securityDomain.authenticate(
            runnable.getAuthToken().getUsername(), 
            runnable.getAuthToken().getPassword().toCharArray()
        );

        // Use SecurityIdentity's runAs to propagate context to EJB
        securityIdentity.runAs(() -> {
            try {
                runnable.run();
            } catch (Exception e) {
                throw new RuntimeException("Failed to run privileged task", e);
            }
            return null;
        });
    }
}

Key Notes to Avoid Pitfalls

  • Thread Context Cleanup: Always restore the original security context in a finally block—WildFly uses thread pools, and leaving the authenticated context bound can cause cross-request leaks.
  • EJB Reference Serialization: Your ContextRunnable serializes an EJB reference. While this works in the same JVM, if you ever need to pass this across nodes, replace the direct reference with a JNDI lookup inside the run() method instead.
  • Security Domain Configuration: Ensure your security domain (either traditional or Elytron) is properly configured in standalone.xml/domain.xml with the correct authentication modules and role mappings.

After applying one of these fixes, your EJBContext.getCallerPrincipal() and SessionContext.getCallerPrincipal() should return the authenticated user instead of "anonymous".

内容的提问来源于stack exchange,提问作者jlange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:48:22