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=6c1802c9e2e825172f550d7793450a81899cfa46;hb=d08f37411b41e19a3e5c2ff1c1620acb27c94d5b
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-access-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. >> > >> >
