My Jakarta Application class is:
@ApplicationPath("/app")
@RolesAllowed("admin")
public class Application extends ResourceConfig {
public Application() {
System.out.println("!!!!!! Insights starts !!!!!....");
packages("com.company.application.ws");
register(RolesAllowedDynamicFeature.class);
register(SecurityFilter.class);
register(AuthenticationExceptionMapper.class);
}
}
My authorization filter is:
@Provider
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {
@Inject
jakarta.inject.Provider<UriInfo> uriInfo;
// @Inject
// private UserService userService;
private static final String REALM = "My App";
@Override
public void filter(ContainerRequestContext filterContext) throws IOException {
User user = authenticate(filterContext);
filterContext.setSecurityContext(new Authorizer(user));
}
private User authenticate(ContainerRequestContext filterContext) {
// Extract authentication credentials
String authentication = filterContext.getHeaderString(HttpHeaders.AUTHORIZATION);
if (authentication == null) {
throw new AuthenticationException("Authentication credentials are required", REALM);
}
if (!authentication.startsWith("Basic ")) {
return null;
// additional checks should be done here
// "Only HTTP Basic authentication is supported"
}
authentication = authentication.substring("Basic ".length());
String[] values = new String(DatatypeConverter.parseBase64Binary(authentication), StandardCharsets.US_ASCII).split(":");
if (values.length < 2) {
throw new WebApplicationException(400);
// "Invalid syntax for username and password"
}
String username = values[0];
String password = values[1];
if ((username == null) || (password == null)) {
throw new WebApplicationException(400);
// "Missing username or password"
}
// Validate the extracted credentials
User user;
if (username.equals("admin") && password.equals("1234")) {
user = new User("admin", "admin");
System.out.println("admin AUTHENTICATED");
} else if (username.equals("user") && password.equals("123")) {
user = new User("user", "user");
System.out.println("user AUTHENTICATED");
} else {
System.out.println("USER NOT AUTHENTICATED");
throw new AuthenticationException("Invalid username or password\r\n", REALM);
}
return user;
}
public class Authorizer implements SecurityContext {
private final User user;
private final Principal principal;
public Authorizer(final User user) {
this.user = user;
this.principal = () -> user.username;
}
@Override
public Principal getUserPrincipal() {
return this.principal;
}
@Override
public boolean isUserInRole(String role) {
return (role.equals(user.role));
}
@Override
public boolean isSecure() {
return "https".equals(uriInfo.get().getRequestUri().getScheme());
}
@Override
public String getAuthenticationScheme() {
return SecurityContext.BASIC_AUTH;
}
}
public static class User {
public String username;
public String role;
public User(String username, String role) {
this.username = username;
this.role = role;
}
}
}
the issue is that the RolesAllowedDynamicFeature
filter is never triggered. I have put the RolesAllowed
at the Application, class and method level but it never triggers. The isUserInRole
method is never called. This is a Java only program with no web.xml
.
What other config is required to make it work?
Update:
I made a local copy of RolesAllowedDynamicFeature
and registered it instead of the Jersey one. The RolesAllowedDynamicFeature.configure
is getting triggered and also the RolesAllowedRequestFilter(String[] rolesAllowed)
constructor but the RolesAllowedRequestFilter.filter
and RolesAllowedRequestFilter.isAuthenticated
are never called.