Search code examples
wildflyjaas

How to dynamically modify an authenticated user's security roles post authentication in Wildfly 10/ JB EAP 7?


I am running a JEE application on Wildfly 10 / JBoss EAP 7.0.8 in which a user is authenticated via a JAAS login module. My security-domain is defined as follows:

           <security-domain name="webapp" cache-type="default">
                <authentication>
                    <login-module code="org.sso.keycloak.KeycloakLoginModule" flag="optional" module="deployment.ear">
                        <module-option name="keycloak-config-file" value="${keycloak.config}"/>
                    </login-module>
                    <login-module code="security.jboss.ServerLoginModule" flag="requisite" module="deployment.ear">
                        <module-option name="password-stacking" value="useFirstPass"/>
                        <module-option name="unauthenticatedIdentity" value="nobody"/>
                    </login-module>
                </authentication>
            </security-domain>

My login module then calculates the roles for the given user and returns it via the getRoleSets() method which is part of the LoginModule.

The authentication process works properly, however I now have a requirement where I need to change an authenticated user's role once they have already been authentication.

If I try to call request.login() a second time for an already authenticated user, it throws an exception that the user is already logged in.

Retrieving the Principal from the request object does not give me access to his roles or groups. Nor have I been able to find a way to retrieve the information from the SecurityContext.

How can I modify/add roles for a user which has already been authenticated?


Solution

  • After digging around for quite a bit, I have come up with a solution that is functional, however I am not so sure that it is clean. None the less I am posting it here if anyone else needs inspiration in the future.

    I am disturbed that there isn't a cleaner mechanism in which to do this. Furthermore, I am not sure if this may cause concurrency issues when multiple threads/EJB requests are being made in parallel. Additionally, I have no tested nor validated against clustered deployments to ensure that the security roles/context is properly propagated/updated between all the different nodes.

    RedHat recommends against the practice and does not support it for JBoss platforms.

           // get the group containing the security roles from the user's current security context
            Optional<Group> rolesGroup = SecurityContextAssociation.getSubject().getPrincipals(Group.class).stream().filter(p->"Roles".equals(p.getName())).findFirst();
            if( rolesGroup.isPresent()){
                Group roles = rolesGroup.get();
                // remove all security roles from the current security context
                Collections.list(roles.members()).stream().forEach(principal -> roles.removeMember(principal) );
                // add the user's newly calculated security roles back into the user's security context
                Arrays.stream(newRoles).forEach( roleName -> roles.addMember(new SimplePrincipal(roleName)));
            }