Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify state and concurrency expectations of Jakarta Authentication APIs #119

Open
darranl opened this issue Apr 30, 2021 · 4 comments
Open

Comments

@darranl
Copy link
Contributor

darranl commented Apr 30, 2021

This issue is to explore and clarify the state expectations of the Jakarta Authentication APIs and the parameters passed to those APIs.

This is to follow up on some discussions regarding state in the CallbackHandler but I think we should also consider some of the Authentication APIs where state may be shared.

@arjantijms
Copy link
Contributor

Jakarta Authentication is clear about the usage of the MessageInfo to share state between calls to a ServerAuthModule, but not super clear with respect to state in the CallbackHandler.

We have already seen that this leads to some portability issues; Soteria considers the CallbackHandler completely stateless and assumes all state is stored in either thread locals or in the Subject.

This brings us to a second state issue. The assumption now would be only "state is not in the CallbackHandler", but a step beyond that is saying "state must be in the Subject"

@arjantijms
Copy link
Contributor

(from #110 (comment))

Well would it be unreasonable to discuss some minimal requirements on the resulting Subject? It seems as though it would be useful to have some common expectations set for the resulting Subject.

From Soteria this is roughly what current implementations do:

private Principal getVendorCallerPrincipal(Principal principal, boolean isEjb) {
        switch (principal.getClass().getName()) {
            case "org.glassfish.security.common.PrincipalImpl": // GlassFish/Payara
                return getAuthenticatedPrincipal(principal, "ANONYMOUS", isEjb);
            case "weblogic.security.principal.WLSUserImpl": // WebLogic
                return getAuthenticatedPrincipal(principal, "<anonymous>", isEjb);
            case "com.ibm.ws.security.authentication.principals.WSPrincipal": // Liberty
                return getAuthenticatedPrincipal(principal, "UNAUTHENTICATED", isEjb);
            // JBoss EAP/WildFly convention 1 - single top level principal of the below type
            case "org.jboss.security.SimplePrincipal":
                return getAuthenticatedPrincipal(principal, "anonymous", isEjb);
            // JBoss EAP/WildFly convention 2 - the one and only principal in group called CallerPrincipal
            case "org.jboss.security.SimpleGroup":
                if (principal.getName().equals("CallerPrincipal") && principal.getClass().getName().equals("org.jboss.security.SimpleGroup")) {
                    Enumeration<? extends Principal> groupMembers = null;
                    try {
                        groupMembers = (Enumeration<? extends Principal>) Class.forName(className("org.jboss.security.SimpleGroup"))
                                .getMethod("members")
                                .invoke(principal);
                    } catch (Exception e) {

                    }

                    if (groupMembers != null && groupMembers.hasMoreElements()) {
                        return getAuthenticatedPrincipal(groupMembers.nextElement(), "anonymous", isEjb);
                    }
                }
                break;
            case "org.apache.tomee.catalina.TomcatSecurityService$TomcatUser": // TomEE
                try {
                    Principal tomeePrincipal = (Principal) Class.forName(className("org.apache.catalina.realm.GenericPrincipal"))
                            .getMethod("getUserPrincipal")
                            .invoke(
                                    Class.forName(className("org.apache.tomee.catalina.TomcatSecurityService$TomcatUser"))
                                            .getMethod("getTomcatPrincipal")
                                            .invoke(principal));

                    return getAuthenticatedPrincipal(tomeePrincipal, "guest", isEjb);
                } catch (Exception e) {

                }
                break;
        }

        if (CallerPrincipal.class.isAssignableFrom(principal.getClass())) {
            return principal;
        }

        return null;
    }

The easiest thing to say is perhaps that "some vendor specific representation of the caller principal and groups" must be present in the subject. The CallerPrincipalCallback or GroupPrincipalCallback are currently able to write these into the Subject. The test to see if they are stored correctly would be to have both these two callbacks being able to retrieve exactly what they wrote into it.

so say (pseudo code)

handle CallerPrincipalCallback subject write fooWritten

string fooRead = handle CallerPrincipalCallback subject read

assert fooRead == fooWritten

@darranl
Copy link
Contributor Author

darranl commented Apr 30, 2021

I am going to put together some examples, IMO there are some parts of the API to consider before we get to the CallbackHandler. For the CallbackHandler there are three areas state may be relevent:

  1. Request level state across calls to handle();
  2. Deployment level state in relation to configuration referenced by the CallbackHandler.
  3. Deployment level state in relation to selecting a different CallbackHandler implementation.

@darranl darranl changed the title Clarify state expectations of Jakarta Authentication APIs Clarify state and concurrency expectations of Jakarta Authentication APIs Apr 30, 2021
@arjantijms
Copy link
Contributor

@darranl time is running out quickly for Jakarta Authentication 3.0 and Jakarta EE 10. Do we still want to address something here for 3.0 though? I think at this point with about 2 weeks to go we can only really go for the low hanging fruit.

arjantijms added a commit that referenced this issue Feb 25, 2022
#119 Clarified state expectations of callbackhander for per-request state
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants