Почему Subject.doAs возвращает участника на основе зарегистрированного пользователя вместо переключенного субъекта?

Я пытаюсь преобразовать существующий API-интерфейс из веб-приложения, которое ранее было развернуто в bea weblogic. Мне нужно развернуть это приложение сейчас в JBoss EAP 7.

В моем коде входа пользователя я делаю аутентификацию сервлета следующим образом:

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

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

Теперь sessionContext в каждом EJB-объекте, который просматривает контейнер, возвращает зарегистрированного пользователя, что идеально, за исключением того, что некоторые функции приложения должны переключать пользователя и выполнять некоторые привилегированные действия, например, загрузку документа.

Я переключаю пользователя и выполняю привилегированное действие следующим образом:

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

В моей TestPrivilegedAction, которая реализует PrivilegedAction, у меня есть следующие коды:

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

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

По сути, исходный API, используемый при развертывании приложения в Weblogic:

Authenticate.authenticate
Security.runAs

... затем я заменил его на следующее, чтобы оно работало в JBoss:

LoginContext.login
Subject.doAs

Так почему же он по-прежнему возвращает зарегистрированного пользователя (user1), даже если аутентификация прошла успешно и субъект уже настроен на user2? Я искал в Интернете и пытался узнать, не пропускаю ли я какие-то конфигурации, но я действительно застрял с этим сейчас. Я ценю любые отзывы или предложения.

1 ответ

После некоторого времени экспериментирования с доступными API, я наконец смог решить свою проблему. Я просто хочу поместить это здесь, на случай, если другие люди столкнутся с той же проблемой.

По сути, я заново изобрел существующий API, используемый для сервера weblogic:

Authenticate.authenticate
Security.runAs

Вот мой класс аутентификации:

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();
        }
    }
}

Я создал класс-обертку для Subject.doAs, у которого нет функции для переключения назад к исходной теме. Вот как я это сделал:

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();
        }
    }
}

Теперь обратите внимание, что я все еще использую метод Subject.doAs, а затем вызываю Authenticate.setOriginalSubject, чтобы вернуть исходную тему.

Все работает, и мне почти нужно было обновить импорт пакетов в файлах классов, которые его используют.

Другие вопросы по тегам