Glassfish @RolesAllowed with custom SecurityContext

天大地大妈咪最大 提交于 2019-12-03 03:48:00
HankCa

Ok I've just completed that part (in fact all parts except for the EmailGateway).

Firstly I say thanks to Iain Porter for his work - its top quality. And I apologise for mistakenly referring to him as just 'Porter' before.

There is something going on with the Stackoverflow code formatting so be aware that some code proceeds the code boxes.

For your problem I did this:

  1. web.xml - I don't use except for Faces
  2. Instead of web.xml and to register the various providers I created a class AuthApplicationConfig.java

    @ApplicationPath("rest")
    public class AuthApplicationConfig extends Application {
    
        @Override
        public Set<Class<?>> getClasses() {
            Set<Class<?>> resources = new java.util.HashSet<>();
    
            // REST resources
            resources.add(HealthCheckResource.class);
            resources.add(PasswordResource.class);
            resources.add(UserResource.class);
            resources.add(VerificationResource.class);
    
            // Filters (Auth)
            resources.add(RolesAllowedDynamicFeature.class);
            resources.add(SecurityContextFilter.class);
    
            // Misc
            resources.add(GenericExceptionMapper.class);
            return resources;
        }
    }
    

See https://java.net/jira/browse/JERSEY-1634 for why you need to register the classes even though they are annotated with @Provider

  1. ResourceFilterFactory.java - I didn't use
  2. SecurityContextFilter.java is slightly different:

    @Provider
    @Priority(Priorities.AUTHENTICATION)    // So it comes in before org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature
    
    public class SecurityContextFilter implements ContainerRequestFilter {
        @Inject
        Logger logger;
    
        protected static final String HEADER_AUTHORIZATION = "Authorization";
    
        protected static final String HEADER_DATE = "x-java-rest-date";
    
        protected static final String HEADER_NONCE = "nonce";
    
        private AuthorizationService authorizationService;
    
        ApplicationConfig config;
    
        @Inject
        public SecurityContextFilter(UserRepository userRepository,
                UserService userService, ApplicationConfig config) {
            delegateAuthorizationService(userRepository, userService, config);
            this.config = config;
    
        }
    
        /**
         * If there is an Authorisation header in the request extract the session
         * token and retrieve the user
         * 
         * Delegate to the AuthorizationService to validate the request
         * 
         * If the request has a valid session token and the user is validated then a
         * user object will be added to the security context
         * 
         * Any Resource Controllers can assume the user has been validated and can
         * merely authorize based on the role
         * 
         * Resources with @PermitAll annotation do not require an Authorization
         * header but will still be filtered
         * 
         * @param request
         *            the ContainerRequest to filter
         * 
         */
        @Override
        public void filter(ContainerRequestContext requestContext)
                throws IOException {
            System.out.println("SecurityContextFilter / filter("+printContainerRequestContext(requestContext)+")");
            String authToken = requestContext.getHeaderString(HEADER_AUTHORIZATION);
            String requestDateString = requestContext.getHeaderString(HEADER_DATE);
            String nonce = requestContext.getHeaderString(HEADER_NONCE);
            AuthorizationRequestContext context = new AuthorizationRequestContext(
                    requestContext.getUriInfo().getPath(),
                    requestContext.getMethod(), requestDateString, nonce, authToken);
            ExternalUser externalUser = authorizationService.authorize(context);
            requestContext
                    .setSecurityContext(new SecurityContextImpl(externalUser));
            System.out.println(String.format(" END OF SecurityContextFilter / filter - AuthorizationRequestContext: %s, externalUser:%s", context,externalUser));
        }
    
        private String printContainerRequestContext(ContainerRequestContext requestContext) {
            return String.format("[ContainerRequestContext:%s]", requestContext);
        }
    
        /**
         * Specify the AuthorizationService that the application should use
         * 
         * @param userRepository
         * @param userService
         * @param config
         */
        private void delegateAuthorizationService(UserRepository userRepository,
                UserService userService, ApplicationConfig config) {
            System.out.println("SecurityContextFilter - requireSignedRequests?"+config.requireSignedRequests());
            if (config.requireSignedRequests()) {
                this.authorizationService = new RequestSigningAuthorizationService(
                        userRepository, userService, config);
            } else {
                this.authorizationService = new SessionTokenAuthorizationService(
                        userRepository);
            }
        }
    
        @Inject
        public void setConfig(ApplicationConfig config) {
            this.config = config;
        }
    }
    
  3. SecurityContextImpl is the same as Iain defined it:

    public class SecurityContextImpl implements SecurityContext {
    
        private final ExternalUser user;
    
        public SecurityContextImpl(ExternalUser user) {
            this.user = user;
        }
    
        @Override
        public Principal getUserPrincipal() {
            return user;
        }
    
        @Override
        public boolean isUserInRole(String role) {
            if(role.equalsIgnoreCase(Role.anonymous.name())) {
                 return true;
            }
            if(user == null) {
                throw new InvalidAuthorizationHeaderException();
            }
            System.out.println(String.format("SecurityContextImpl / isUserInRole - role:%s, user:%s", role, user));
            return user.getRole().equalsIgnoreCase(role);
        }
    
        @Override
        public boolean isSecure() {
            return false;
        }
    
        @Override
        public String getAuthenticationScheme() {
            return SecurityContext.BASIC_AUTH;
        }
    }
    
  4. UserResource is as Iain defined it and similar to your UserRestService:

    @Path("/user")
    // @Component
    @Produces({ MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_JSON })
    @RequestScoped
    public class UserResource {
        // A Social thing that is not needed
        // private ConnectionFactoryLocator connectionFactoryLocator;
        @Inject
        Logger logger;
    
        @Inject
        protected UserService userService;
    
        @Inject
        protected VerificationTokenService verificationTokenService;
    
        @Inject
        protected EmailServicesGateway emailServicesGateway;
    
        @Context
        protected UriInfo uriInfo;
    
        // @Inject
        // protected ApplicationConfig config;
    
        // @Autowired
        // public UserResource(ConnectionFactoryLocator connectionFactoryLocator) {
        // this.connectionFactoryLocator = connectionFactoryLocator;
        // }
    
        @PermitAll
        @POST
        public Response signupUser(CreateUserRequest request) {
            AuthenticatedUserToken token = userService.createUser(request, Role.authenticated);
            verificationTokenService.sendEmailRegistrationToken(token.getUserId());
            URI location = uriInfo.getAbsolutePathBuilder().path(token.getUserId()).build();
            return Response.created(location).entity(token).build();
        }
    
        @RolesAllowed("admin")
        @Path("{userId}")
        @DELETE
        public Response deleteUser(@Context SecurityContext sc, @PathParam("userId") String userId) {
            ExternalUser userMakingRequest = (ExternalUser) sc.getUserPrincipal();
            userService.deleteUser(userMakingRequest, userId);
            return Response.ok().build();
        }
        ...
    

what about your web.xml?

Have you already put this filters inside web.xml?

<init-param>
       <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
       <param-value>com.yourcompany.filter.SecurityFilter</param-value>
   </init-param>
    <init-param>
        <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
        <param-value>com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value>
    </init-param>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!