Reputation: 212
I tried following this tutorial and implemented the Provider class as given in the example.
@Provider
@Secured
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
private static final String REALM = "example";
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 {
// Validate the token
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
// The 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 response
// The WWW-Authenticate header is sent along with the response
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED)
.header(HttpHeaders.WWW_AUTHENTICATE,
AUTHENTICATION_SCHEME + " realm=\"" + REALM + "\"")
.build());
}
private void validateToken(String token) throws Exception {
// Check if the token was issued by the server and if it's not expired
// Throw an Exception if the token is invalid
//TODO validate against database
if(!token.equals("exampleString")) {
throw new AuthenticationException("Invalid token.");
}
}
}
This Provider class is also recognized by the server, which can be seen in the logs:
Dez 25, 2017 6:47:09 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFORMATION: Root resource classes found:
class com.jwt.service.AuthenticationEndpoint
class com.jwt.service.HelloWorldService
Dez 25, 2017 6:47:09 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFORMATION: Provider classes found:
class com.jwt.service.AuthenticationFilter
I created an Interface for the annotation:
@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured {
}
And also annotated my REST endpoint.
@GET
@Path("/secured")
@Secured
public Response getUserSecured() {
return Response.status(200).entity("Secured getUser is called").build();
}
Even though my Provider class is recognized, it still does not do anything when the annotated method is called. Instead of outputting the unauthorized status code, "Secured getUser is called" is returned, even though no authentification is send.
Does someone have an idea why the filter method of my Provider class is never called?
Upvotes: 0
Views: 761
Reputation: 1377
com.sun.jersey.api
package (visible in the provided logs) is Jersey 1 while the tutorial you are following deals with jersey 2.
Upgrade to Jersey 2 and it will work.
Upvotes: 1