JASPIC Wildfly 9 validateRequest с сеансом
На основе этого примера Jaspic я написал следующее validateRequest
метод для ServerAuthModule
:
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject,
Subject serviceSubject) throws AuthException {
boolean authenticated = false;
final HttpServletRequest request =
(HttpServletRequest) messageInfo.getRequestMessage();
final String token = request.getParameter("token");
TokenPrincipal principal = (TokenPrincipal) request.getUserPrincipal();
Callback[] callbacks = new Callback[] {
new CallerPrincipalCallback(clientSubject, (TokenPrincipal) null) };
if (principal != null) {
callbacks = new Callback[] {
new CallerPrincipalCallback(clientSubject, principal) };
authenticated = true;
} else {
if (token != null && token.length() == Constants.tokenLength) {
try {
principal = fetchUser(token);
} catch (final Exception e) {
throw (AuthException) new AuthException().initCause(e);
}
callbacks = new Callback[]
{
new CallerPrincipalCallback(clientSubject, principal),
new GroupPrincipalCallback(clientSubject,
new String[] { "aRole" })
};
messageInfo.getMap().put("javax.servlet.http.registerSession", "TRUE");
authenticated = true;
}
}
if (authenticated) {
try {
handler.handle(callbacks);
} catch (final Exception e) {
throw (AuthException) new AuthException().initCause(e);
}
return SUCCESS;
}
return AuthStatus.SEND_FAILURE;
}
Это работает, как и ожидалось, для первого вызова EJB с @RolesAllowed("aRole")
но для следующего звонка это не работает вообще. Wildfly отрицает это с этим сообщением об ошибке:
ERROR [org.jboss.as.ejb3.invocation] (default task-4) WFLYEJB0034: EJB Invocation
failed on component TestEJB for method public java.lang.String
com.jaspic.security.TestEJB.getPrincipalName():
javax.ejb.EJBAccessException: WFLYSEC0027: Invalid User
Если я угадаю правильно, ошибка происходит в:org.jboss.as.security.service.SimpleSecurityManager
строка 367 исходного кода wilfly из-за строки 405, в которой credential
проверено, но, кажется, null
,
Это похоже на Wildfly 8/9/10CR (другие версии не тестировались).
Опять же, я не уверен, что я делаю это неправильно или это та же ошибка, что и https://issues.jboss.org/browse/WFLY-4626? И это вообще ошибка, или это ожидаемое поведение?
1 ответ
Это звучит как ошибка для меня, а также личность вызывающего абонента (звонящий / группа Principal
s) кажется сохраненным при последующих вызовах к сети, но не к контейнеру EJB. Мои собственные классы JASPIC (которые правильно работают в GlassFish 4.1) не работают по той же причине в WildFly 9.0.2.Final и 10.0.0.CR4 при использовании вместе с простым сервлетом и SLSB, даже если последний отмечен @PermitAll
,
Поскольку я сам незнаком с внутренностями безопасности WildFly, я не могу помочь вам в этом. Если вы не сможете исправить это, единственный обходной путь на уровне SAM, о котором я могу подумать, в настоящее время состоит в том, чтобы не использовать javax.servlet.http.registerSession
свойство обратного вызова, которое, казалось бы, вызывает проблему, но вместо этого имеет CallbackHandler
зарегистрировать оба абонента Principal
и его группы на каждом validateRequest(...)
призывание. Если это применимо к вашему случаю использования, вы можете приложить эту информацию к HttpSession
чтобы немного ускорить процесс; в противном случае повторите с нуля. Так, например:
public class Sam implements ServerAuthModule {
// ...
@Override
public AuthStatus validateRequest(MessageInfo mi, Subject client, Subject service) throws AuthException {
boolean authenticated = false;
boolean attachAuthnInfoToSession = false;
final String callerSessionKey = "authn.caller";
final String groupsSessionKey = "authn.groups";
final HttpServletRequest req = (HttpServletRequest) mi.getRequestMessage();
TokenPrincipal tp = null;
String[] groups = null;
String token = null;
HttpSession hs = req.getSession(false);
if (hs != null) {
tp = (TokenPrincipal) hs.getAttribute(callerSessionKey);
groups = (String[]) hs.getAttribute(groupsSessionKey);
}
Callback[] callbacks = null;
if (tp != null) {
callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
authenticated = true;
}
else if (isValid(token = req.getParameter("token"))) {
tp = newTokenPrincipal(token);
groups = fetchGroups(tp);
callbacks = new Callback[] { new CallerPrincipalCallback(client, tp), new GroupPrincipalCallback(client, groups) };
authenticated = true;
attachAuthnInfoToSession = true;
}
if (authenticated) {
try {
handler.handle(callbacks);
if (attachAuthnInfoToSession && ((hs = req.getSession(false)) != null)) {
hs.setAttribute(callerSessionKey, tp);
hs.setAttribute(groupsSessionKey, groups);
}
}
catch (IOException | UnsupportedCallbackException e) {
throw (AuthException) new AuthException().initCause(e);
}
return AuthStatus.SUCCESS;
}
return AuthStatus.SEND_FAILURE;
}
// ...
@Override
public void cleanSubject(MessageInfo mi, Subject subject) throws AuthException {
// ...
// just to be safe
HttpSession hs = ((HttpServletRequest) mi.getRequestMessage()).getSession(false);
if (hs != null) {
hs.invalidate();
}
}
private boolean isValid(String token) {
// whatever
return ((token != null) && (token.length() == 10));
}
private TokenPrincipal newTokenPrincipal(String token) {
// whatever
return new TokenPrincipal(token);
}
private String[] fetchGroups(TokenPrincipal tp) {
// whatever
return new String[] { "aRole" };
}
}
Я протестировал вышеупомянутое на вышеупомянутых версиях WildFly и вышеупомянутым способом (то есть с единственным сервлетом, ссылающимся на один SLSB, помеченный @DeclareRoles
/ уровень метода @RolesAllowed
) и похоже на работу как положено. Очевидно, я не могу гарантировать, что этот подход не потерпит неудачу другими неожиданными способами.
Смотрите также: