Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

Bug 901076 (JBPAPP6-1332)

Summary: CLONE - WebJASPIAuthenticator ignores GroupPrincipalCallback but requires PasswordValidationCallback
Product: [JBoss] JBoss Enterprise Application Platform 6 Reporter: Josef Cacek <jcacek>
Component: Security, WebAssignee: Stefan Guilhen <sguilhen>
Status: CLOSED CURRENTRELEASE QA Contact: Josef Cacek <jcacek>
Severity: high Docs Contact:
Priority: high    
Version: 6.0.0CC: arjan.tijms, chamorro.j, fnasser, jcacek
Target Milestone: ---   
Target Release: TBD EAP 6   
Hardware: Unspecified   
OS: Unspecified   
URL: http://jira.jboss.org/jira/browse/JBPAPP6-1332
Whiteboard: authentication jaspi jaspic
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-12-15 17:01:51 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
JBPAPP-10255.patch none

Description Josef Cacek 2012-10-18 08:38:46 UTC
Steps to Reproduce: 1. Install a {{ServerAuthModule}} that contains the following code: 

{code}
    @Override
    public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException {
       
        CallerPrincipalCallback callerPrincipalCallback = new CallerPrincipalCallback(clientSubject, "test");
        GroupPrincipalCallback groupPrincipalCallback = new GroupPrincipalCallback(clientSubject, new String[] {"somerole"});
        
        try {
            handler.handle( new Callback[] {callerPrincipalCallback, groupPrincipalCallback});
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnsupportedCallbackException e) {
            e.printStackTrace();
        }

        return AuthStatus.SUCCESS;
    }
{code}

2. Access a protected resource
project_key: JBPAPP6

In JBoss AS 7.1.1, if a user provided {{ServerAuthModule}} provides a {{GroupPrincipalCallback}}, then this is ignored by {{WebJASPIAuthenticator}}. The provided handler copies the {{GroupPrincipalCallback}}, but the authenticator then does nothing with it. Simulteanously, if the {{ServerAuthModule}} does not provide a {{PasswordValidationCallback}} to the handler, then this will result in a null pointer exception in the authenticator.

Regarding the ignored {{GroupPrincipalCallback}}, the problem seems to be in the following code:

{code:title=WebJASPIAuthenticator#authenticate}
// ...
       if (result) {
            PasswordValidationCallback pvc = cbh.getPasswordValidationCallback();
            CallerPrincipalCallback cpc = cbh.getCallerPrincipalCallback();

            // get the client principal from the callback.
            Principal clientPrincipal = cpc.getPrincipal();
            if (clientPrincipal == null) {
                clientPrincipal = new SimplePrincipal(cpc.getName());
            }

            // if the client principal is not a jboss generic principal, we need to build one before registering.
            if (!(clientPrincipal instanceof JBossGenericPrincipal))
                clientPrincipal = this.buildJBossPrincipal(clientSubject, clientPrincipal);
{code}

{{buildJBossPrincipal()}} looks at the "Roles" group in the Subject, but this hasn't been set by either the handler or other code based on what the GroupPrincipalCallback contains.

I wonder if changing this into the following would be more correct:

{code:title=WebJASPIAuthenticator#authenticate}
// ...
       if (result) {
            PasswordValidationCallback pvc = cbh.getPasswordValidationCallback();
            CallerPrincipalCallback cpc = cbh.getCallerPrincipalCallback();
            GroupPrincipalCallback gpc = cbh.getGroupPrincipalCallback(); // ADDED

            // get the client principal from the callback.
            Principal clientPrincipal = cpc.getPrincipal();
            if (clientPrincipal == null) {
                clientPrincipal = new SimplePrincipal(cpc.getName());
            }

            // if the client principal is not a jboss generic principal, we need to build one before registering.
            if (!(clientPrincipal instanceof JBossGenericPrincipal))
                clientPrincipal = this.buildJBossPrincipal(clientSubject, clientPrincipal, gpc); // ADDED gpc PARAMETER
{code}

With {{buildJBossPrincipal()}} implemented as:

{code:title=WebJASPIAuthenticator#buildJBossPrincipal}
    protected Principal buildJBossPrincipal(Subject subject, Principal principal, GroupPrincipalCallback groupPrincipalCallback) {

        List<String> roles = new ArrayList<String>();
        // look for roles in the subject first.
        for (Principal p : subject.getPrincipals()) {
            if (p instanceof Group && p.getName().equals("Roles")) {
                Enumeration<? extends Principal> members = ((Group) p).members();
                while (members.hasMoreElements())
                    roles.add(members.nextElement().getName());
            }
        }
        
        // START ADDED
        if (groupPrincipalCallback != null && groupPrincipalCallback.getGroups() != null) {
            for (String group : groupPrincipalCallback.getGroups()) {
                roles.add(group);
            }
        }
        // END ADDED

        // if the subject didn't contain any roles, look for the roles declared in the deployment descriptor.
        JBossWebRealm realm = (JBossWebRealm) this.getContainer().getRealm();
        Set<String> descriptorRoles = realm.getPrincipalVersusRolesMap().get(principal.getName());
        if (roles.isEmpty() && descriptorRoles != null)
            roles.addAll(descriptorRoles);

        // build and return the JBossGenericPrincipal.
        return new JBossGenericPrincipal(realm, principal.getName(), null, roles, principal, null, null, null, subject);

    }
{code}

As for the PasswordValidationCallback, WebJASPIAuthenticator now contains the following code in {{authenticate()}}:

{code:title=WebJASPIAuthenticator#authenticate}
this.register(request, response, clientPrincipal, authMethod, pvc.getUsername(),
    new String(pvc.getPassword()));
{code}

The {{register()}} method considers both username and password as optional, but because there's no null check on {{pvc}}, the above line will throw a NPE in case no PasswordValidationCallback is provided. This could perhaps be changed into something like the following:

{code:title=WebJASPIAuthenticator#authenticate}
this.register(request, response, clientPrincipal, authMethod, pvc != null ? pvc.getUsername() : null,
    pvc != null && pvc.getPassword() != null ? new String(pvc.getPassword()) : null);
{code}

Comment 1 Josef Cacek 2012-10-18 08:38:46 UTC
Link: Added: This issue Cloned from AS7-5735


Comment 2 Josef Cacek 2012-10-18 08:39:31 UTC
Workflow: Removed: GIT Pull Request workflow  Added: jira
Security: Added: Public
Docs QE Status: Added: NEW


Comment 3 Josef Cacek 2012-10-18 08:41:11 UTC
Additional info and discussion in https://access.redhat.com/support/cases/00712002

Comment 4 arjan tijms 2012-11-02 12:06:02 UTC
Josef, that link doesn't seem to work (anymore). Is there a new link available?

Comment 5 Josef Cacek 2012-11-02 12:28:41 UTC
Arjan, the link works, but it points to the Red Hat customer support portal, where the user needs to have permissions.

Comment 7 arjan tijms 2012-11-02 14:38:15 UTC
I see. Any chance you can cross-post relevant items from that discussion over here?

Comment 10 Josef Cacek 2012-11-08 14:57:11 UTC
Attachment: Added: JBPAPP-10255.patch


Comment 11 arjan tijms 2012-11-10 11:24:23 UTC
The patch look good Josef, thanks!

One extra question, what's exactly EAP 6.0.1 ER 2? Is that an engineering release that's only released internally?

Comment 12 Anne-Louise Tangring 2012-11-13 20:54:54 UTC
Docs QE Status: Removed: NEW 


Comment 13 arjan tijms 2012-12-13 14:03:35 UTC
Josef, sorry to bother again, but is there a chance you could post some of the discussion from the customer support portal here, or summarize what was discussed there?

Also, is it correct that this patch will be generally available to users in JBoss AS 7.2 and JBoss EAP 6.0.2?

Comment 14 Josef Cacek 2012-12-13 14:23:51 UTC
Arjan, the ER really means internal engineering release. 
The patch was the main output of the support request.
Current AS7 sources already includes the fix, so it should be in the next versions.

You can build and try the current version yourself:
{code}
git clone https://github.com/jbossas/jboss-as.git
cd jboss-as
./build.sh clean install
{code}
You can find the new version in the build/target subdirectory then.

Comment 15 arjan tijms 2012-12-13 17:45:31 UTC
Thanks Josef!

Yes, I noticed that the sources contained the fix and I had already patched my own JBoss locally before that ;) I was interested in the availability of this in a downloadable version, so I could use this when answering questions about this topic (e.g. http://stackoverflow.com/questions/719708/java-web-application-using-a-custom-realm/13860940#13860940) and in blogs.

The discussion was mainly interesting for me to see if people had any concerns, remarks, questions etc before excepting the patch. If there were any, these might again be interesting to mention in blog posts and possible in spec requests such as this one: http://java.net/jira/browse/JAVAEE_SPEC-9

Comment 16 Josef Cacek 2013-02-22 13:19:04 UTC
Changing status to ON_QA. This should be already implemented in EAP 6.1.

Comment 18 Josef Cacek 2013-03-22 12:17:33 UTC
Verified in EAP 6.1.0.ER3