简体   繁体   中英

Why does Subject.doAs return the principal based on the logged in user instead of the switched subject?

I am trying to convert an existing api from a web application that was previously deployed in bea weblogic. I need to deploy this application now in JBoss EAP 7.

In my user login code, I am doing servlet authentication like so:

HttpServletRequest request = ServletActionContext.getRequest();
request.login("user1", "password");

testEJB= (TestEJB) LookupUtil.lookup("TestEJB");
System.out.println("logged in user: " + testEJB.getName()); //returns user1

Now the sessionContext in every EJB looked up by the container returns the logged in user, which is perfect except that some app functions need to switch user and do some privileged actions eg uploading of document.

I am switching user and performing the privileged action like so:

LoginContext loginContext = new LoginContext("TestLoginContext", new UsernamePasswordHandler("user2", "password"));
loginContext.login();
String newUser = (String) Subject.doAs(loginContext.getSubject(), new TestPrivilegedAction());
System.out.println("privileged User: " + newUser); //still returns user1

In my TestPrivilegedAction which implements PrivilegedAction, I have the following codes:

@Override
public Object run() {
    return this.getSwitchedUser();
}

private Object getSwitchedUser() {
    testEJB= (TestEJB) LookupUtil.lookup("TestEJB");
    System.out.println("logged in user: " + testEJB.getName());
}

Basically, the original api used when the app was deployed in weblogic are:

Authenticate.authenticate
Security.runAs

...then I replaced it with the following to make it work in JBoss:

LoginContext.login
Subject.doAs

So why now it still returns the logged in user (user1), even though the authentication succeeded and the subject is already set to user2? Ive been searching the web and trying to see if Im just missing some configurations but i'm really stuck with this now. I appreciate any feedback or suggestions.

After some time experimenting on the available APIs, I finally was able to solve my problem. I just want to put it here, just in case other people run into the same issue.

Basically, I reinvented the existing api used for weblogic server:

Authenticate.authenticate
Security.runAs

Here is my Authenticate class:

public class Authenticate {

    private static Subject originalSubject = null;

    public static void authenticate(Hashtable env, Subject subject) throws LoginException {
        try {           
            //retrieve the security context that contains the current subject (logged in user)
            SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
            SubjectInfo subjectInfo = securityContext.getSubjectInfo();

            //set the current subject as the original subject
            originalSubject = subjectInfo.getAuthenticatedSubject();

            //start authentication of the new subject
            CallbackHandler callbackHandler = new UsernamePasswordHandler((String) env.get(Context.SECURITY_PRINCIPAL), env.get(Context.SECURITY_CREDENTIALS));
            LoginContext loginContext = new LoginContext("JbossLoginContext", callbackHandler);
            loginContext.login();

            //set the new subject information to perform the privileged action
            subject.getPrincipals().addAll(loginContext.getSubject().getPrincipals());
            subjectInfo.setAuthenticatedSubject(loginContext.getSubject());
        } catch (LoginException e) {
            throw new LoginException();
        } catch (Exception e) {
            throw new Exception();
        }
    }

    public static void setOriginalSubject() {
        try {
            //if the login method is already invoked, replace the current subject with the original subject
            if(originalSubject != null) {
                SecurityContextAssociation.getSecurityContext().getSubjectInfo().setAuthenticatedSubject(originalSubject);
            }
        } catch (Exception e) {
            throw new Exception();
        }
    }
}

I created a wrapper class for the Subject.doAs which doesn't have the function to switch back the original subject. Here is how I did it:

public class Security {

    public static Object runAs(Subject subject, PrivilegedAction privilegedAction) {
        try {
            Object object = Subject.doAs(subject, privilegedAction);
            Authenticate.setOriginalSubject();
            return object;
        } catch (Exception e) {
            throw new Exception();
        }
    }
}

Now, notice that I still use the Subject.doAs method, then I call the Authenticate.setOriginalSubject to set the original subject back.

Everything works and I almost only had to update the package imports in the class files that use it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM