Custom SecurityContext in JAX-RS
An article about how to override the default security-related information associated with a JAX-RS request using a custom SecurityContext.
Join the DZone community and get the full member experience.
Join For FreeAnd the JAX-RS juggernaut continues ….
This article briefly talks about how to override the default security-related information associated with a JAX-RS request (i.e., how to mess with the SecurityContext).
Wait... SecurityContext?
Think of it as a JAX-RS abstraction over HTTPServletRequest for security-related information only. This can be used for:
- figuring out how the caller was authenticated
- extracting authenticated Principal info
- role membership confirmation (programmatic authorization)
- and whether or not the request was initiated securely (over HTTPS)
OK, but why would I need a custom implementation?
It helps when you have a custom authentication mechanism not implemented using the standard Java EE security realm:
- your web container will not be aware of the authentication details
- as a result, the SecurityContext instance will not contain the subject, role, or other details (mentioned above)
- a typical example is token-based authentication, based on custom (app-specific) HTTP headers
@Priority(Priorities.AUTHENTICATION)
public class JWTAuthFilter implements ContainerRequestFilter{
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String authHeaderVal = requestContext.getHeaderString("Authorization");
//consume JWT i.e. execute signature validation
if(authHeaderVal.startsWith("Bearer")){
try {
validate(authHeaderVal.split(" ")[1]);
} catch (InvalidJwtException ex) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}else{
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
Your RESTful application would definitely want to make use of the authenticated caller. The JAX-RS request pipeline needs to be aware of the associated ‘security context’ and make use of it within its business logic
How to…
SecurityContext is an interface after all...
- just implement it
- then inject it (using @Context) and use it in your resource methods
@Priority(Priorities.AUTHENTICATION)
public class AuthFilterWithCustomSecurityContext implements ContainerRequestFilter {
@Context
UriInfo uriInfo;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String authHeaderVal = requestContext.getHeaderString("Auth-Token");
String subject = validateToken(authHeaderVal); //execute custom authentication
if (subject!=null) {
final SecurityContext securityContext = requestContext.getSecurityContext();
requestContext.setSecurityContext(new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return new Principal() {
@Override
public String getName() {
return subject;
}
};
}
@Override
public boolean isUserInRole(String role) {
List<Role> roles = findUserRoles(subject);
return roles.contains(role);
}
@Override
public boolean isSecure() {
return uriInfo.getAbsolutePath().toString().startsWith("https");
}
@Override
public String getAuthenticationScheme() {
return "Token-Based-Auth-Scheme";
}
});
}
}
}
Cheers!
Published at DZone with permission of Abhishek Gupta, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments