I am following this answer: Best practice for REST token-based authentication with JAX-RS and Jersey to implement the REST API authentication. But the JAX-RS Authentication Filter is not triggered via @Secured annotation.
I finished until the part Securing your REST endpoints by adding @Secured
on the method.
This is how I am doing this.
Secured.java
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured { }
AuthenticationFilter.java
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
private static final String AUTHENTICATION_SCHEME = "Bearer";
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the Authorization header from the request
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// Validate the Authorization header
if (!isTokenBasedAuthentication(authorizationHeader)) {
abortWithUnauthorized(requestContext);
return;
}
// Extract the token from the Authorization header
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
try {
validateToken(token);
} catch (Exception e) {
abortWithUnauthorized(requestContext);
}
}
private boolean isTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// Authentication scheme comparison must be case-insensitive
return (authorizationHeader != null &&
authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " "));
}
private void abortWithUnauthorized(ContainerRequestContext requestContext) {
// Abort the filter chain with a 401 status code
// The "WWW-Authenticate" is sent along with the response
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME)
.build());
}
private void validateToken(String token) throws Exception {
// Check if it was issued by the server and if it's not expired
// Throw an Exception if the token is invalid
}
MyApis.java
@Path("api")
public class MyApis {
@GET
@Secured
@Path("me")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, X500Name> whoAmI() {
return ImmutableMap.of("me", legalName);
}
// other APIs
}
When I call /api/me
, I can get the response directly without any authentication header provided. It seems like the filter is not triggered or not registered properly.
I have seen this question JAX RS, my filter is not working, but it does not solve my problem.
And how I understand the following is that web.xml
is not needed right?
This solution uses only the JAX-RS 2.0 API, avoiding any vendor specific solution. So, it should work with the most popular JAX-RS 2.0 implementations, such as Jersey, RESTEasy and Apache CXF.
It's important mention that if you are using a token-based authentication, you are not relying on the standard Java EE web application security mechanisms offered by the servlet container and configurable via application's web.xml descriptor.