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