[jboss-jira] [JBoss JIRA] (SECURITY-746) EJB SecurityContextInterceptor attempts JAAS login which doesn't work for JASPIC authentications

Arjan t (JIRA) issues at jboss.org
Mon Feb 23 10:51:51 EST 2015


    [ https://issues.jboss.org/browse/SECURITY-746?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13042863#comment-13042863 ] 

Arjan t commented on SECURITY-746:
----------------------------------

This is still a problem in WildFly 8.2, even though that one has some alignment with the security domain of the web module (see WFLY-3102).

The code in Picketbox has changed a bit from the report, but still after JASPIC has successfully authenticated in the web tier and then calls a method on a protected EJB, {{org.jboss.as.ejb3.security.SecurityContextInterceptor}} still tries to authenticate with {{org.jboss.as.security.service.SimpleSecurityManager}}. 

This now happens here:

{code:java}
public class SecurityContextInterceptor implements Interceptor {
    private final PrivilegedAction<Void> pushAction;
    private final PrivilegedAction<Void> popAction;

    public SecurityContextInterceptor(final SecurityContextInterceptorHolder holder) {
        this.pushAction = new PrivilegedAction<Void>() {
            @Override
            public Void run() {
                holder.securityManager.push(holder.securityDomain);
                try {
                    if (holder.skipAuthentication == false) {
                        holder.securityManager.authenticate(holder.runAs, holder.runAsPrincipal, holder.extraRoles);
                    }
                    if (holder.principalVsRolesMap != null) {
                        SecurityRolesAssociation.setSecurityRoles(holder.principalVsRolesMap);
                    }
                } catch (Throwable t) {
{code}

{{holder.securityManager.authenticate}} will be called.  This now contains the following code:

{code:java}
    private boolean authenticate(SecurityContext context, Subject subject) {
        SecurityContextUtil util = context.getUtil();
        SubjectInfo subjectInfo = getSubjectInfo(context);
        if (subject == null) {
            subject = new Subject();
        }
        Principal principal = util.getUserPrincipal();
        Principal auditPrincipal = principal;
        Object credential = util.getCredential();
        Identity unauthenticatedIdentity = null;

        boolean authenticated = false;
        if (principal == null) {
            unauthenticatedIdentity = getUnauthenticatedIdentity();
            subjectInfo.addIdentity(unauthenticatedIdentity);
            auditPrincipal = unauthenticatedIdentity.asPrincipal();
            subject.getPrincipals().add(auditPrincipal);
            authenticated = true;
        } else {
            subject.getPrincipals().add(principal);
        }

        if (authenticated == false) {
            AuthenticationManager authenticationManager = context.getAuthenticationManager();
            authenticated = authenticationManager.isValid(principal, credential, subject);
        }
{code}

The 2nd line {{SubjectInfo subjectInfo = getSubjectInfo(context);}} will retrieve the authenticated identity as established by the JASPIC auth module, but instead of using it, it will call {{authenticationManager.isValid(principal, credential, subject);}}, which will call through to a JAAS login module.

This will now cause the following exception:

{noformat}
javax.ejb.EJBAccessException: JBAS013323: Invalid User
	at org.jboss.as.ejb3.security.SecurityContextInterceptor$1.run(SecurityContextInterceptor.java:66) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.as.ejb3.security.SecurityContextInterceptor$1.run(SecurityContextInterceptor.java:46) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:92) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
{noformat}



> EJB SecurityContextInterceptor attempts JAAS login which doesn't work for JASPIC authentications
> ------------------------------------------------------------------------------------------------
>
>                 Key: SECURITY-746
>                 URL: https://issues.jboss.org/browse/SECURITY-746
>             Project: PicketBox 
>          Issue Type: Feature Request
>            Reporter: arjan tijms
>            Assignee: Stefan Guilhen
>              Labels: authentication, ejb, jaspi, jaspic, security, security-context
>
> After a user has successfully authenticated with JASPIC it's not possible to access any method in a secured EJB bean, irrespective of the actual security constraints.
> The problem is that when an EJB is "secured" an extra interceptor is added to the chain: {{org.jboss.as.ejb3.security.SecurityContextInterceptor.SecurityContextInterceptor}}.
> This interceptor calls {{org.jboss.as.security.service.SimpleSecurityManager.push}}, which tries to establish a new stacked security context by attempting a login to a JAAS login module associated with the security domain.
> However, when the caller authenticated via a JASPIC auth module, there isn't necessarily such a JAAS login module (the JASPIC auth module is not required to call a JAAS login module, and even if it did it may not be the JAAS login module JBoss knows about).
> The problematic part in {{SimpleSecurityManager}}:
> {code}
> public void push(final String securityDomain, final String runAs, final String runAsPrincipal, final Set<String> extraRoles) {
>         boolean contextPushed = false;
>         boolean securityContextEstablished = false;
>         final SecurityContext previous = SecurityContextAssociation.getSecurityContext();
>         try {
>             contexts.push(previous);
>             contextPushed = true;
>             SecurityContext current = establishSecurityContext(securityDomain);
>             securityContextEstablished = true;
>             if (previous != null) {
>                 current.setSubjectInfo(previous.getSubjectInfo());
>                 current.setIncomingRunAs(previous.getOutgoingRunAs());
>             }
>             RunAs currentRunAs = current.getIncomingRunAs();
>             boolean trusted = currentRunAs != null && currentRunAs instanceof RunAsIdentity;
>             if (trusted == false) {
>               
>                 boolean authenticated = false;
>                 if (SecurityActions.remotingContextIsSet()) {
>                     // ...
>                 }
>                 // If we have a trusted identity no need for a re-auth.                
>                 if (authenticated == false) {
>                     // THIS WILL EVENTUALLY ATTEMPT A JAAS LOGIN WHICH FAILS
>                     authenticated = authenticate(current, null);
>                 }
> {code}
> The (condensed) stack that will lead to an exception is the following:
> {noformat}
> javax.security.auth.login.FailedLoginException: PBOX000070: Password invalid/Password required
> org.jboss.security.authentication.JBossCachedAuthenticationManager.defaultLogin(Principal, Object)
> org.jboss.security.authentication.JBossCachedAuthenticationManager.proceedWithJaasLogin(Principal, Object, Subject)
> org.jboss.security.authentication.JBossCachedAuthenticationManager.isValid(Principal, Object, Subject)
> org.jboss.as.security.service.SimpleSecurityManager.authenticate(SecurityContext, Subject)
> org.jboss.as.security.service.SimpleSecurityManager.push(String, String, String, Set<String>)
> org.jboss.as.ejb3.security.SecurityContextInterceptor.SecurityContextInterceptor(SecurityContextInterceptorHolder)
> {noformat}
> Since the {{SimpleSecurityManager}} is already doing a check to see if the call is remote or not, I wonder if it could not simply accept the existing security context as-is for local calls (not even start a new context) or just consider the existing security context as trusted for local calls just like a {{RunAS}} identity.
> Note that this depends on SECURITY-744 and SECURITY-745, since otherwise there is no valid security context at all.



--
This message was sent by Atlassian JIRA
(v6.3.11#6341)


More information about the jboss-jira mailing list