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, Web | Assignee: | Stefan Guilhen <sguilhen> | ||||
| Status: | CLOSED CURRENTRELEASE | QA Contact: | Josef Cacek <jcacek> | ||||
| Severity: | high | Docs Contact: | |||||
| Priority: | high | ||||||
| Version: | 6.0.0 | CC: | 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: |
|
||||||
Link: Added: This issue Cloned from AS7-5735 Workflow: Removed: GIT Pull Request workflow Added: jira Security: Added: Public Docs QE Status: Added: NEW Additional info and discussion in https://access.redhat.com/support/cases/00712002 Josef, that link doesn't seem to work (anymore). Is there a new link available? Arjan, the link works, but it points to the Red Hat customer support portal, where the user needs to have permissions. I see. Any chance you can cross-post relevant items from that discussion over here? Attachment: Added: JBPAPP-10255.patch 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? Docs QE Status: Removed: NEW 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? 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.
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 Changing status to ON_QA. This should be already implemented in EAP 6.1. Verified in EAP 6.1.0.ER3 |
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}