Glassfish @RolesAllowed with custom SecurityContext

Die Frage, die ich stellen werde, ist etwas knifflig und ich habe noch keine Antwort gefunden. Vielleicht, weil ich das Falsche suche. Aber ich hoffe du hilfst mir dabei.

Ich habe das benutztfolgendes Tutorial Implementieren eines benutzerdefinierten SecurityContext, der Token anstelle der grundlegenden Benutzer- / Kennwortauthentifizierung verwendet.

Grundsätzlich wird eine ResourceFilterFactory initialisiert und injiziert, die bei jeder an die Anwendung gesendeten HTTP-Anforderung selbst einen ResourceFilter injiziert.

Dieser ResourceFilter sucht in der Anfrage nach dem Header "Authentication", übernimmt dessen Inhalt und authentifiziert dann den Benutzer. Wenn der Benutzer authentifiziert ist, wird er über einen SecurityContext in die Anforderung eingefügt.

Ich habe den Code transformiert, damit er als EJB funktioniert.

Hier ist der Code:

web.xml

<init-param>  
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>  
<param-value>com.myapp.rest.filter.ResourceFilterFactory</param-value>
</init-param>

ResourceFilterFactory.java // Diese Klasse injiziert den EJB SecurityContextFilter

@Named
@Stateless
@LocalBean
public class ResourceFilterFactory extends RolesAllowedResourceFilterFactory{

    @EJB(name="securityContextFilter")
    private SecurityContextFilter securityContextFilter;

    @PostConstruct
    private void init(){
        System.out.println("ResourceFilterFactory initialized");
    }

     @Override
        public List<ResourceFilter> create(AbstractMethod am) {
         //System.out.println("Creating resource filters list");
            List<ResourceFilter> filters = super.create(am);
            if (filters == null) {
                filters = new ArrayList<ResourceFilter>();
            }

            List<ResourceFilter> securityFilters = new ArrayList<ResourceFilter>(filters);
            securityFilters.clear();
            securityFilters.add(0, securityContextFilter);

            return securityFilters;
     }
}

SecurityContextFilter.java // Dieser EJB wird bei jeder HTTP-Anforderung aufgerufen, die der Server empfängt. Es prüft, ob der Header "Authentication" (Authentifizierung) vorhanden ist, und ruft den Benutzer ab, der dem Token zugeordnet ist.

@Named("securityContextFilter")
@Stateless
@LocalBean
@Provider
public class SecurityContextFilter implements ResourceFilter, ContainerRequestFilter {

    protected static final String HEADER_AUTHORIZATION = "Authorization";

    @EJB
    private AuthorizationService authorizationService;

    @Override
    public ContainerRequest filter(ContainerRequest req) {
        System.out.println("Auth header: " + req.getHeaderValue(HEADER_AUTHORIZATION));
        String sessionToken =  req.getHeaderValue(HEADER_AUTHORIZATION);
        UserEntity entity = null;
        try {
            //entity = authorizationService.getParaUsingSessionToken(sessionToken);
            // removing the part that retrieves the user from the database
            ExternalUser user = new ExternalUser();
            user.setEmailAddress("[email protected]");
            user.setFirstName("lol");
            user.setLastName("LOL");
            user.setRole("arole");
            req.setSecurityContext(new org.company.server.rest.filter.SecurityContextImpl(user));
        } catch (AuthenticationException e) {
            System.out.println("authentication exception");
            ExternalUser user = new ExternalUser();
            req.setSecurityContext(new org.company.server.rest.filter.SecurityContextImpl(user));
        }

        return req;
    }

    @Override
    public ContainerRequestFilter getRequestFilter() {
        return this;
    }

    @Override
    public ContainerResponseFilter getResponseFilter() {
        return null;
    }

}

SecurityContextImpl.java // Diese Klasse wird in die Anforderung eingefügt und verfügt über die Methode isUserInRole (), die von der Annotation @RolesAllowed verwendet werden soll

public class SecurityContextImpl implements SecurityContext {


    private final ExternalUser user;

    public SecurityContextImpl(ExternalUser user) {
        //System.out.println("SecurityContext created : " + user.getFirstName());
        this.user = user;
    }

    public Principal getUserPrincipal() {
        return user;
    }

    public boolean isUserInRole(String role) {
        System.out.println("Checking access rights : " + role + " / " + this.user.getRole());
        return user.getRole().equalsIgnoreCase(role);
    }

    public boolean isSecure() {
        return false;
    }

    public String getAuthenticationScheme() {
        return SecurityContext.BASIC_AUTH;
    }
}

ExternalUser.java // Die Entität, die erstellt und mit Datenbankbenutzerinformationen gefüllt wurde.

@XmlRootElement
public class ExternalUser implements Principal {

    private String id;
    private String firstName;
    private String lastName;
    private String emailAddress;
    private boolean isVerified;
    private String phoneNumber;
    private String professionalId;
    private String role;

    public ExternalUser() {}

    public ExternalUser(UserEntity user) {
        this.setEmailAddress(user.getEmailAddress());
        this.setFirstName(user.getFirstName());
        this.setLastName(user.getLastName());
        this.setRole(user.getRole().toString());
        this.setPhoneNumber(user.getPhoneNumber());
        this.setProfessionalId(user.getProfessionnalID());
    }
    // Getters and setters boilerplate code...
}

Endlich der Jersey WebService:

@Path("/account")
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Stateless
@LocalBean
public class UserRestService {

@Context
private SecurityContext security;

        @GET
        @Path("info")
        @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
        public Response getInfo() {
        ExternalUser user = (ExternalUser)security.getUserPrincipal();
        System.out.println("Email Address Of User : " + user.getEmailAddress());
            if (!security.isUserInRole("arole")){
                return Response.status(403).build();
            }
        return Response.ok(user).build();
        }
}

Der WebService funktioniert gutbekomme ich die ExternalUser-Instanz mit dem injizierten SecurityContext. Aber wenn ich das benutze@RolesAllowed({"arole"}) Anmerkung, Glassfish gibt mir diesen Fehler:

INFO: JACC Policy Provider:Failed Permission Check: context (" org.company.app.server/org_company_app_server_internal ") , permission (" ("javax.security.jacc.EJBMethodPermission" "UserRestService" "getInfo,Local,org.company.server.rest.models.authentication.RestSession") ") 
WARNING: EJB5184:A system exception occurred during an invocation on EJB UserRestService, method: public javax.ws.rs.core.Response org.company.server.rest.services.UserRestService.getInfo()
WARNING: javax.ejb.AccessLocalException: Client not authorized for this invocation
    at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1888)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
    at com.sun.proxy.$Proxy140.getInfoPara(Unknown Source)
    at org.company.server.rest.services.__EJB31_Generated__UserRestService__Intf____Bean__.getInfoPara(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
    at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
    at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
    at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
    at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
    at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
    at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
    at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
    at com.sun.jersey.spi.container.servlet.ServletContainer.doFilter(ServletContainer.java:895)
    at com.sun.jersey.spi.container.servlet.ServletContainer.doFilter(ServletContainer.java:843)
    at com.sun.jersey.spi.container.servlet.ServletContainer.doFilter(ServletContainer.java:804)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:722)

WARNING: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception
javax.ejb.AccessLocalException: Client not authorized for this invocation
    at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1888)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
    at com.sun.proxy.$Proxy140.getInfoPara(Unknown Source)
    at org.company.server.rest.services.__EJB31_Generated__UserRestService__Intf____Bean__.getInfoPara(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    ...

Ich denke, ich muss Glassfish so konfigurieren, dass es das von mir erstellte SecurityContextImpl verwendet. Ich weiß nicht, warum es nicht funktioniert, da es richtig injiziert ist und ich seine Methoden in meinem Code aufrufen kann.

Ich könnte einfach das benutzenisUserInRole() Methode manuell, aber ich würde nur das Problem vermeiden, anstatt es zu stellen. Es tut mir leid für den langen Beitrag, aber jetzt haben Sie, glaube ich, alle Informationen, die Sie benötigen, um mir dabei zu helfen. Vielen Dank im Voraus für Ihre Hilfe.

Emeric

Antworten auf die Frage(2)

Ihre Antwort auf die Frage