So either you configured this provider in openejb-jar.xml or JWTAuthenticationFilter is not a CDI bean
Romain Manni-Bucau @rmannibucau <https://twitter.com/rmannibucau> | Blog <http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> | LinkedIn <https://www.linkedin.com/in/rmannibucau> | Tomitriber <http://www.tomitribe.com> 2015-04-09 15:55 GMT+02:00 Alex Soto <[email protected]>: > mm strange look: > > @ApplicationScoped > public class UserService { > } > > @Provider > @Priority(Priorities.AUTHENTICATION) > public class JWTAuthenticationFilter implements ContainerRequestFilter { > > private static final List<Class<? extends Annotation>> > securityAnnotations = > Arrays.asList(DenyAll.class, PermitAll.class, RolesAllowed.class); > > @Context > ResourceInfo resourceInfo; > > @Context > HttpServletRequest servletRequest; > > @Context > UriInfo uriInfo; > > @Inject > UserService userservice; > > @Override > public void filter(ContainerRequestContext request) throws IOException > { > } > > and userService is null. > > El dj., 9 abr., 2015 a les 15:53, Alex Soto (<[email protected]>) va > escriure: > > > I am going to take another look to the code to see what's happening :S > > > > El dj., 9 abr., 2015 a les 15:47, Romain Manni-Bucau (< > > [email protected]>) va escriure: > > > > cdi works: > >> https://git-wip-us.apache.org/repos/asf?p=tomee.git;a=blob;f > >> =server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ > >> CDIProviderContainerRequestFilterTest.java;h=6c180 > >> 2c9e2e825172f550d7793450a81899cfa46;hb=d08f37411b41e19a3e5c2ff1c1620a > >> cb27c94d5b > >> > >> > >> Romain Manni-Bucau > >> @rmannibucau <https://twitter.com/rmannibucau> | Blog > >> <http://rmannibucau.wordpress.com> | Github <https://github.com/ > >> rmannibucau> | > >> LinkedIn <https://www.linkedin.com/in/rmannibucau> | Tomitriber > >> <http://www.tomitribe.com> > >> > >> 2015-04-09 11:38 GMT+02:00 Romain Manni-Bucau <[email protected]>: > >> > >> > Well not using ejb is surely the current way. They will be reserved > for > >> > scheduling in todays apps i guess. > >> > Le 9 avr. 2015 10:06, "Alex Soto" <[email protected]> a écrit : > >> > > >> >> Ok then I need to implement in two different ways. :( This is > >> something to > >> >> improve (I think Java EE 8 is on that way) because security is > >> something > >> >> transversal so it should be global, not having to implement several > >> pieces > >> >> in several places. > >> >> > >> >> Well thanks then last option is my option :) > >> >> > >> >> El dj., 9 abr., 2015 a les 10:02, Romain Manni-Bucau (< > >> >> [email protected]>) > >> >> va escriure: > >> >> > >> >> > Hi > >> >> > > >> >> > Le 9 avr. 2015 09:15, "Alex Soto" <[email protected]> a écrit : > >> >> > > > >> >> > > Hello, I am trying to create an application where I can mix Java > EE > >> >> > > security annotations in JAX-RS endpoints. I am using current > TomEE > >> 2 > >> >> > > Snapshot and basically I am creating two ContainerRequestFilter. > >> >> > > One for authentication and another for authorization. > >> >> > > > >> >> > > @Provider > >> >> > > @Priority(Priorities.AUTHENTICATION) > >> >> > > public class JWTAuthenticationFilter implements > >> >> ContainerRequestFilter { > >> >> > > > >> >> > > private static final List<Class<? extends Annotation>> > >> >> > > securityAnnotations = > >> >> > > Arrays.asList(DenyAll.class, PermitAll.class, > >> >> > RolesAllowed.class); > >> >> > > > >> >> > > @Context > >> >> > > private ResourceInfo resourceInfo; > >> >> > > > >> >> > > private UserService userservice = new UserService(); > >> >> > > > >> >> > > @Override > >> >> > > public void filter(ContainerRequestContext request) throws > >> >> > IOException { > >> >> > > if (isSecuredResource()) { > >> >> > > > >> >> > > String token = request.getHeaderString("x-acc > >> ess-token"); > >> >> > > > >> >> > > try { > >> >> > > String username = getUsernameFromToken(token); > >> >> > > final User user = userservice.findUser(username); > >> >> > > > >> >> > > request.setSecurityContext(new SecurityContext() > { > >> >> > > > >> >> > > @Override > >> >> > > public boolean isUserInRole(String role) { > >> >> > > return user.isUserInRole(role); > >> >> > > } > >> >> > > > >> >> > > @Override > >> >> > > public boolean isSecure() { > >> >> > > return false; > >> >> > > } > >> >> > > > >> >> > > @Override > >> >> > > public Principal getUserPrincipal() { > >> >> > > return user; > >> >> > > } > >> >> > > > >> >> > > @Override > >> >> > > public String getAuthenticationScheme() { > >> >> > > return SecurityContext.BASIC_AUTH; > >> >> > > } > >> >> > > }); > >> >> > > > >> >> > > } catch (java.text.ParseException | JOSEException | > >> >> > > NullPointerException e) { > >> >> > > request.abortWith(Response.status(404).build()); > >> >> > > } > >> >> > > } > >> >> > > } > >> >> > > > >> >> > > private boolean isSecuredResource() { > >> >> > > > >> >> > > for (Class<? extends Annotation> securityClass : > >> >> > > securityAnnotations) { > >> >> > > if (resourceInfo.getResourceMethod(). > >> isAnnotationPresent( > >> >> > > securityClass)) { > >> >> > > return true; > >> >> > > } > >> >> > > } > >> >> > > > >> >> > > for (Class<? extends Annotation> securityClass : > >> >> > > securityAnnotations) { > >> >> > > if (resourceInfo.getResourceClass(). > >> isAnnotationPresent( > >> >> > > securityClass)) { > >> >> > > return true; > >> >> > > } > >> >> > > } > >> >> > > > >> >> > > return false; > >> >> > > } > >> >> > > > >> >> > > private String getUsernameFromToken(String token) > >> >> > > throws java.text.ParseException, JOSEException { > >> >> > > > >> >> > > SignedJWT signedJWT = SignedJWT.parse(token); > >> >> > > JWSVerifier verifier = new MACVerifier(SharedSecret. > >> >> > getSecret()); > >> >> > > > >> >> > > if (signedJWT.verify(verifier)) { > >> >> > > return signedJWT.getJWTClaimsSet().getSubject(); > >> >> > > } else { > >> >> > > throw new JOSEException("Firm is not verified."); > >> >> > > } > >> >> > > } > >> >> > > } > >> >> > > > >> >> > > > >> >> > > note that I am creating a custom security context and for > >> >> authorization: > >> >> > > > >> >> > > @Provider > >> >> > > @Priority(Priorities.AUTHORIZATION) > >> >> > > public class RolesAllowedFilter implements > ContainerRequestFilter { > >> >> > > > >> >> > > private static final Response NOT_FOUND = Response.status( > >> >> > > Response.Status.NOT_FOUND).entity("{\"message\": \"Resource > >> Not > >> >> > > Found\"}").build(); > >> >> > > > >> >> > > @Context > >> >> > > private ResourceInfo resourceInfo; > >> >> > > > >> >> > > @Override > >> >> > > public void filter(ContainerRequestContext requestContext) > >> >> > > throws IOException { > >> >> > > Method resourceMethod = resourceInfo.getResourceMethod(); > >> >> > > > >> >> > > // DenyAll on the method take precedence over RolesAllowed > and > >> >> > PermitAll > >> >> > > if (resourceMethod.isAnnotationPresent(DenyAll.class)) { > >> >> > > requestContext.abortWith(NOT_FOUND); > >> >> > > return; > >> >> > > } > >> >> > > > >> >> > > // RolesAllowed on the method takes precedence over PermitAll > >> >> > > RolesAllowed ra = > >> >> resourceMethod.getAnnotation(RolesAllowed.class); > >> >> > > if(assertRole(requestContext, ra)) { > >> >> > > return; > >> >> > > } > >> >> > > > >> >> > > // PermitAll takes precedence over RolesAllowed on the class > >> >> > > if (resourceMethod.isAnnotationPresent(PermitAll.class)) { > >> >> > > // Do nothing. > >> >> > > return; > >> >> > > } > >> >> > > > >> >> > > if > >> >> > > (resourceInfo.getResourceClass().isAnnotationPresent(DenyAll.class)) > >> >> > > { > >> >> > > requestContext.abortWith(NOT_FOUND); > >> >> > > } > >> >> > > > >> >> > > // RolesAllowed on the class takes precedence over PermitAll > >> >> > > ra = > >> >> > resourceInfo.getResourceClass().getAnnotation(RolesAllowed.class); > >> >> > > if(assertRole(requestContext, ra)) { > >> >> > > return; > >> >> > > } > >> >> > > } > >> >> > > > >> >> > > private boolean assertRole(ContainerRequestContext > >> requestContext, > >> >> > > RolesAllowed ra) { > >> >> > > > >> >> > > if (ra != null) { > >> >> > > String[] roles = ra.value(); > >> >> > > for (String role : roles) { > >> >> > > if > (requestContext.getSecurityContext().isUserInRole(role)) > >> { > >> >> > > return true; > >> >> > > } > >> >> > > } > >> >> > > requestContext.abortWith(NOT_FOUND); > >> >> > > } > >> >> > > return false; > >> >> > > } > >> >> > > } > >> >> > > > >> >> > > And the business code: > >> >> > > > >> >> > > @Stateless > >> >> > > @Path("/app") > >> >> > > public class UiApplication { > >> >> > > > >> >> > > @Inject > >> >> > > UserService userService; > >> >> > > > >> >> > > @Inject > >> >> > > MovieService moviesService; > >> >> > > > >> >> > > @POST > >> >> > > @Consumes(MediaType.APPLICATION_JSON) > >> >> > > @Produces(MediaType.APPLICATION_JSON) > >> >> > > public Response login(JsonObject jsonObject) throws > >> JOSEException > >> >> { > >> >> > > > >> >> > > JsonString username = (JsonString) > >> jsonObject.get("username"); > >> >> > > JsonString password = (JsonString) > >> jsonObject.get("password"); > >> >> > > > >> >> > > if (authenticate(username.getString(), > >> password.getString())) { > >> >> > > > >> >> > > String token = createToken(username.getString(), " > >> example.com > >> >> "); > >> >> > > > >> >> > > JsonObject responseDocument = Json.createObjectBuilder() > >> >> > > .add("user", Json.createObjectBuilder().add("username", > >> >> > > username).build()) > >> >> > > .add("token", token) > >> >> > > .build(); > >> >> > > > >> >> > > return Response.ok(responseDocument).build(); > >> >> > > > >> >> > > } > >> >> > > > >> >> > > return Response.status(Status.NOT_FOUND).build(); > >> >> > > > >> >> > > } > >> >> > > > >> >> > > @GET > >> >> > > @Produces(MediaType.APPLICATION_JSON) > >> >> > > @RolesAllowed("admin") > >> >> > > public Response movies() { > >> >> > > return Response.ok("{\"message\":\"a\"}").build(); > >> >> > > } > >> >> > > > >> >> > > private boolean authenticate(String username, String > password) > >> { > >> >> > > return this.userService.findUser(username, password); > >> >> > > } > >> >> > > > >> >> > > private String createToken(String subject, String issuer) > >> throws > >> >> > > JOSEException { > >> >> > > > >> >> > > JWSSigner signer = new MACSigner(SharedSecret.getSecret()); > >> >> > > > >> >> > > JWTClaimsSet claimsSet = new JWTClaimsSet(); > >> >> > > claimsSet.setSubject(subject); > >> >> > > claimsSet.setIssueTime(new Date()); > >> >> > > claimsSet.setIssuer(issuer); > >> >> > > > >> >> > > SignedJWT signedJWT = new SignedJWT(new > >> >> > > JWSHeader(JWSAlgorithm.HS256), claimsSet); > >> >> > > signedJWT.sign(signer); > >> >> > > > >> >> > > return signedJWT.serialize(); > >> >> > > > >> >> > > } > >> >> > > > >> >> > > } > >> >> > > > >> >> > > If I run in this way it doesn't work because the endpoint is also > >> an > >> >> EJB > >> >> > > and because security context of EJB is not shared with the > JAX-RS, > >> the > >> >> > > method throws an 403 Forbidden. Is there any clean way to make > that > >> >> this > >> >> > > don't happen? Of course I can make JAXRS class as none EJB, but > >> this > >> >> > would > >> >> > > be my last option. > >> >> > > > >> >> > > >> >> > Well with @Transactional it would makes sense since you handle > >> security. > >> >> > Using jaas would be the way to have custom logic in ejbs. > >> >> > > >> >> > > Also is there a way to use @Inject in ContainerRequestFilter? > >> >> Currently I > >> >> > > cannot use it because the instance is not injected. > >> >> > > > >> >> > > >> >> > Not yet, dont recall what spec says about it btw > >> >> > > >> >> > > Thank you so much. > >> >> > > > >> >> > > Alex. > >> >> > > >> >> > >> > > >> > > >
