wildfly-extras / wildfly-graphql-feature-pack

5 stars 6 forks source link

JEE Security Integration #46

Open redmitry opened 3 years ago

redmitry commented 3 years ago

Hello,

Having the GraphQL endpoint annotated with @GraphQLApi and @RequestScoped I cant inject SecurityContext in the CDI. I can inject Principal, but because this is a WELD proxy, I can not cast it to get an access to the roles. graphql-java provides the DataFetchingEnvironment, which in my understanding contains security context (?), but it doesn't work in Wildfly. I see that the problem is that the CDI is called from another thread (Callable) and loose the context. What is the correct way to provide programmatic security?

Kind regards,

Dmitry

jmartisk commented 3 years ago

Hey @redmitry , thanks for reporting this.I'll experiment with your use case and report back with my findings. I'm not aware of any security context support in DataFetchingEnvironment, and it would certainly need some integration to get it working, which we don't have.

jmartisk commented 3 years ago

I managed to retrieve the user's name and roles using Elytron API:

pom.xml:

 <dependency>
            <groupId>org.wildfly.security</groupId>
            <artifactId>wildfly-elytron</artifactId>
            <version>1.13.1.Final</version>
            <scope>provided</scope>
       </dependency>

code:

import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
(...)
SecurityIdentity identity = SecurityDomain.getCurrent().getCurrentSecurityIdentity();
System.out.println("Name: " + identity.getPrincipal().getName());
System.out.println("Roles:");
identity.getRoles().forEach(System.out::println);

I'm not sure about the state of support of Jakarta EE security in WF right now, maybe it could be supported (I think it works only in EJBs and servlets right now) but I'll have to dig more. Would this solution be sufficient for you for the time being?

redmitry commented 3 years ago

It doesn't work :-(. I get org.wildfly.security.auth.principal.AnonymousPrincipal

jmartisk commented 3 years ago

Does your deployment have security configured properly? I basically described my findings in this document https://github.com/wildfly-extras/wildfly-graphql-feature-pack/wiki/Server-side-security-guide if you don't need the declarative security I think you can leave out the web.xml file, but I think you still need jboss-web.xml

redmitry commented 3 years ago

I use usual JAX-RS endpoints along to the GraphQL an have no problems injecting SecurityContext.

I use Keycloak filter:

    <filter>
        <filter-name>Keycloak Filter</filter-name>
        <filter-class>org.keycloak.adapters.servlet.KeycloakOIDCFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Keycloak Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

P.S. Here is the endpoint: https://gitlab.bsc.es/inb/elixir/openebench/openebench-rest-api/-/blob/master/src/main/java/es/bsc/inb/elixir/openebench/graphql/OEBGraphQLService.java

jmartisk commented 3 years ago

Looking at the REST classes in your repo, I suppose you're referring to javax.ws.rs.core.SecurityContext rather than javax.security.enterprise.SecurityContext which I assumed earlier. It's no wonder that you can't inject a JAX-RS specific object in a GraphQL endpoint.

After some more experiments I found out I can actually inject javax.security.enterprise.SecurityContext in a GraphQL endpoint (I had to make my application explicitly depend on the org.glassfish.soteria module to make it work)

But if you're getting an anonymous principal, I think that switching from Elytron to javax.security.enterprise.SecurityContext might not help. I see your jboss-web.xml does not declare any security domain, so it could be something with using Keycloak instead of built-in WildFly security domains. I must admit I'm not familiar with Keycloak though.

redmitry commented 3 years ago

I have to admit that integrating KEYCLOAK "normal" way - via web.xml

    <login-config>
        <auth-method>KEYCLOAK</auth-method>
    </login-config>

the solution with SecurityDomain works. I am using the KC filter to be able to make a call without any security (injecting "BASIC" authorization when no specified). Thank you very much for pointing to the javax.ws.rs.core.SecurityContext in REST, I definitely should pass to the JEE8 SecurityContext to unify GraphQL with JAX-RS.

I hope, in some moment GraphQL integration solves the SecurityContext integration though.

Kind regards,

Dmitry