Почему 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, чтобы вернуть исходную тему.
Все работает, и мне почти нужно было обновить импорт пакетов в файлах классов, которые его используют.