Valve authentication & EJBContext/SessionContext principal propagation
robatsu Feb 12, 2014 6:38 PMI have a very straightforward problem that I haven't been able to answer. We use a valve with our own custom authenticator class to authenticate the HttpRequest, and set a principal there. This principal is not then automatically available in the EJB context via EJBContext.getCallerPrincipal - we continue to just get anonymous there. I need to know how to propagate the principle we generate to the ejb context. We are on AS 7.1.1.
Here is some of our config and code:
The valve is configured on our RestEasy endpoints. In jboss-web.xml, we have:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<context-root>rest/${rest.version.api}</context-root>
<security-domain>sp</security-domain>
<valve>
<class-name>com.sheerid.authenticator.OAuthSPRedirectFormAuthenticator</class-name>
</valve>
</jboss-web>
In OAuthSPRedirectFormAuthenticator.java:
public class OAuthSPRedirectFormAuthenticator extends ServiceProviderAuthenticator {
private static final String HEADER_AUTHORIZATION = "Authorization";
private static final Pattern PATTERN_BEARER_TOKEN = Pattern.compile("Bearer (.+)");
private final Logger logger = Logger.getLogger(this.getClass());
@Override
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig loginConfig) throws IOException {
String authHeader = getAuthHeader(request);
if (authHeader != null) {
Matcher tokenMatcher = PATTERN_BEARER_TOKEN.matcher(authHeader);
if (tokenMatcher.matches()) {
String token = tokenMatcher.group(1);
User user = getUserService().findUserByAccessToken(token);
if (user != null) {
final String userName = user.getUsername();
request.setUserPrincipal(generatePrincipal(request, userName, RoleUtils.generateRoles(user)));
((HttpServletRequest) request).setAttribute(SheerIDConstants.ACCOUNT_ID, user.getAccountId());
((HttpServletRequest) request).setAttribute(SheerIDConstants.USER_ID, user.getId());
((HttpServletRequest) request).setAttribute(SheerIDConstants.ACCESS_TOKEN, token);
SecurityClient client;
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
}
}
return super.authenticate(request, response, loginConfig);
}
private static Principal generatePrincipal(Request request, String name, Set<UserRole> roles) { | |
List<String> userRoles = new ArrayList<String>(); | |
userRoles.addAll(UserRole.toStringSet(roles)); | |
return new GenericPrincipal(request.getContext().getRealm(), name, null, userRoles); |
}
And, by the way, even though we create a GenericPrincipal, our SessionContext in the ejb's returns a principal of class SimplePrinciple from sessionContext.getCallerPrincipal() that has a name of "anonymous". Our beans are typically annotated as:
@Stateless
@SecurityDomain(value="sp")
@EJB(name = "java:global/UserServiceBean", beanInterface = UserServiceRemote.class)
@DeclareRoles({UserRole.ROLE_NAME_ACCOUNT_OWNER,
UserRole.ROLE_NAME_STAFF,
UserRole.ROLE_NAME_USER,
UserRole.ROLE_NAME_USER_ADMIN})
public class UserServiceBean extends AbstractSessionBean implements UserServiceRemote{
.......
Again, any help in getting this working would be very much appreciated. It seems like it should be really simple, but I haven't been able to find the key to this one.