I know i can specify the roles in the resource using the annotations @RolesAllowed, but i can't understand how a user is associated to a specific role
The role information is stored in the DB. Assuming say you have a User
that models the USER and ROLES table in the DB
class User {
String username;
List<String> roles;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public List<String> getRoles() { return roles; }
public void setRoles(List<String> roles) { this.roles = roles; }
}
You would get the User
inside a Jersey filter. This is also where you would authenticate.
@Provider
@Priority(Priorities.AUTHENTICATION) // needs to happen before authorization
class AuthenticationFilter implements ContainerRequestFilter {
@Inject
private UserService userService; // this is your own service
@Override
public void filter(ContainerRequestContex context) {
// note, this is a lazy implementation of Basic auth.
// it doesn't do ant error checking. Please see
// link at bottom for better imlementation
String authzHeader = context.getHeaderString(HttpHeaders.AUTHORIZATION); // (1)
String decoded = Base64.decodeAsString(authzHeader);
String[] split = decoded.split(":");
User user = userService.getUser(split[0]); // (2)
if (user == null || !user.getPassword().equals(someHash(split[1])) { // (3)
throw new UnauthorizedException();
}
SecurityContext oldContext = context.getSecurityContext(); // (4)
context.setSecurityContext(new BasicSecurityConext(user, oldContext.isSecure()));
}
}
What you're doing here is:
- Parsing the Basic Auth Authorization header
- Getting the
User
with the username
- Doing your authentication
- Setting a new
SecurityContext
.
The BasicSecurityContext
is shown below. This is where you will associate roles with the user.
static class BasicSecurityContext implements SecurityContext {
private final User user;
private final boolean secure;
public BasicSecurityContext(User user, boolean secure) {
this.user = user;
this.secure = secure;
}
@Override
public Principal getUserPrincipal() {
return new Principal() {
@Override
public String getName() {
return user.getUsername();
}
};
}
@Override
public String getAuthenticationScheme() {
return SecurityContext.BASIC_AUTH;
}
@Override
public boolean isSecure() { return secure; }
@Override
public boolean isUserInRole(String role) {
return user.getRoles().contains(role);
}
}
If you look at the bottom at the isUserInRole
. What will happen is that Jersey will grab the @RolesAllowed
annotation from the resource method or class, grab the values, then pass them to the isUserInRole
. If it returns true
, then the user is authorized. In pseudo-code
@GET
@Path("/somepath")
@RolesAllowed({"USER", "SUPER_USER"})
public Response get() {}
...
RolesAllowed annotation = resourceMethod.getAnnotation(RolesAllowed.class);
String roles = annotation.value();
SecurityContext context = getSecurityContext();
for (String role: roles) {
if (context.isUserInRole(role)) {
return;
}
}
throw new ForbiddenException();
This is just pseudo-code, but it shows how Jersey handles the authorizaiton, using the @RolesAllowed
, the SecurityContext
, and how you implement the isUserInRole
.
This authorization feature is not automatically turned on. You need to turn it on yourself. To do so, simply register the RolesAllowedDynamicFeature
public JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(RolesAllowedDynamicFeature.class);
}
}
One thing to note here is that in all of the above, we are implementing our basic authentication and setting of the security context. There is nothing really wrong with this. But if you are using the servlet container authentication mechanism, Jersey will actually take the auth information from the HttpServletRequest
. The HttpServletRequest
has a getUserPrincipal()
method and a isUserInRole
method. Jersey will use these to delegate in the SecurityContext
. So if you are user the container authentication, then you don't really need to implement anything. You just need to register the RolesAllowedDynamicFeature
If you want to use your container's authentication mechanism, you should consult your server's documentation. After having set up a realm in with your server, you will then need to configure the web.xml
with the security information. There's an example in the link below. You should also find this information in the Java EE docs under the web security section.
See also: