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