Как заставить Джерси @RolesAllowed работать с @Stateless? - PullRequest
0 голосов
/ 04 сентября 2018

Я не уверен, возможно ли это или нет, но я пытаюсь настроить тестовый проект EJB + JAX-RS (Джерси) и использовать аннотацию @RolesAllowed.

В настоящее время я получаю следующие журналы ошибок:

Warning:   WEB9102: Web Login Failed: com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Security Exception
Severe:   ejb.stateless_ejbcreate_exception
Warning:   A system exception occurred during an invocation on EJB TestSB, method: public java.util.List rest.sb.TestSB.findAll()
Warning:   javax.ejb.EJBException: javax.ejb.EJBException: javax.ejb.CreateException: Could not create stateless EJB

Соответствующие классы:

ApplicationConfig.java

@ApplicationPath("rest")
public class ApplicationConfig extends ResourceConfig {

    public ApplicationConfig() {
        packages("rest");
        register(RolesAllowedDynamicFeature.class);
    }
}

TestSBFacade.java

@Local
public interface TestSBFacade {

    public List<Test> findAll();
}

TestSB.java

@Stateless
@Path("secured/test")
public class TestSB implements TestSBFacade {

    @DAO @Inject
    private TestDAOFacade dao;

    @Context
    SecurityContext securityContext;

    @Secured
    @RolesAllowed({"READ"})
    @Path("all")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Override
    public List<Test> findAll() {
        //this works without the @RolesAllowed so it is a possible workaroud for now.

        System.out.println(securityContext.isUserInRole("READ")); //output: true
        return dao.findAll();
    }
}

AuthFilter.java

@Provider
@Secured //NameBinding
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        String token = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);

        try {
            verifyToken();
            createSecurityContext();
        } catch (Exception e) {
            Logger.getLogger(AuthenticationFilter.class.getName()).log(Level.SEVERE, null, "Invalid or Expired JWT");
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }

    }
}

Мой SecurityContext настроен и работает, @RolesAllowed, похоже, является проблемой, так как я не получаю ошибок, если удаляю его, и JSON правильно возвращается во внешний интерфейс. Сохранение @RolesAllowed приводит к ошибкам, упомянутым в начале.

Однако я бы хотел использовать удобную аннотацию вместо встраивания каждого метода в операторы IF isUserInRole. Любая помощь и идеи очень ценятся.

1 Ответ

0 голосов
/ 10 сентября 2018

Таким образом, очевидно, что из-за реализаций EJB и JAX-RS, использующих @RolesAllowed, они не очень хорошо работают вместе. Поэтому я решил вместо этого создать свою собственную аннотацию и зарегистрировать свою собственную DynamicFeature в ApplicationConfig.java.

Authorized.java

@Documented
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Authorized {
    public String[] value() default "";
}

AuthorizationDynamicFeature.java

public class AuthorizationDynamicFeature implements DynamicFeature {

    @Override
    public void configure(final ResourceInfo resourceInfo, final FeatureContext featureContext) {

        Authorized auth = new AnnotatedMethod(resourceInfo.getResourceMethod()).getAnnotation(Authorized.class);
        if (auth != null) {
            featureContext.register(new AuthorizationRequestFilter(auth.value()));
        }
    }

    @Priority(Priorities.AUTHORIZATION)
    private static class AuthorizationRequestFilter implements ContainerRequestFilter {

        private final String[] roles;

        AuthorizationRequestFilter() {
            this.roles = null;
        }

        AuthorizationRequestFilter(final String[] roles) {
            this.roles = roles;
        }

        @Override
        public void filter(final ContainerRequestContext requestContext) throws IOException {
            if (!this.roles[0].isEmpty()) {
                for (final String role : this.roles) {
                    if (requestContext.getSecurityContext().isUserInRole(role)) {
                        return;
                    }
                }
                throw new ForbiddenException(LocalizationMessages.USER_NOT_AUTHORIZED());
            }
        }
    }
}

Огромное спасибо @PaulSamsotha за то, что он привел меня к более подходящему решению.

...