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.
>> >
>>
>

Reply via email to