Using elytron-oidc-client with @RolesAllowed

805 views
Skip to first unread message

Will King

unread,
Jun 15, 2023, 8:30:36 PM6/15/23
to WildFly
Hi, I am attempting to implement the OIDC client in an application which utilizes the RolesAllowed annotation to secure EJBs, and this does not seem to recognize the roles configured on the Keycloak JWT. I am wondering if there is a way to configure Elytron and/or Keycloak so that the token's roles can be checked by this annotation, or if this is a feature which would need to be added to Wildfly. Here are some more details:

standalone.xml configuration snippet:
<subsystem xmlns="urn:wildfly:elytron-oidc-client:1.0">
  <secure-deployment name="DEPLOYMENT_NAME.war">
    <bearer-only>true</bearer-only>
    <client-id>account</client-id>
    <principal-attribute>preferred_username</principal-attribute>
    <provider-url>http://localhost:8080/realms/test-realm</provider-url>
     <ssl-required>external</ssl-required>
     <use-resource-role-mappings>true</use-resource-role-mappings>
  </secure-deployment>
</subsystem>


JWT snippet:
"realm_access": {
  "roles": [
    "READ",
    "default-roles-test-realm",
    "offline_access",
    "uma_authorization"
  ]
},
"resource_access": {
  "account": {
    "roles": [
      "manage-account",
      "manage-account-links",
      "view-profile"
    ]
  }
},
"Roles": [
  "READ",
  "default-roles-test-realm",
  "offline_access",
  "uma_authorization"
],
"preferred_username": "test",


The DEPLOYMENT_NAME in the config above contains a servlet which references an EJB that is in a separate war/ear, so we are using identity propagation, which seems to be working to an extent:
  • In the servlet itself, HttpServletRequest.isUserInRole works (i.e. it returns true when the JWT includes the correct role)
  • However, in the EJB, using @RolesAllowed blocks access for the same JWT and role ("Invocation on method ... is not allowed")
  • When the annotation is removed, from within the context of the EJB method, SessionContext.isCallerInRole does not work (i.e. it returns false even when HttpServletRequest.isUserInRole returns true in the servlet)
  • However, SessionContext.getCallerPrincipal does work in the EJB, so the context is at least partially aware of the propagated identity
In this case, securing the EJB using something other than @RolesAllowed would be very difficult, so I am hoping for a solution that would involve updating only the OIDC config and/or the token claims, which we have full control over. Any insight on this?

Farah Juma

unread,
Jun 15, 2023, 9:21:58 PM6/15/23
to WildFly
What version of WildFly are you using?

WildFly 28 added the ability to propagate an identity from the virtual security domain associated with your WAR to an EJB in a separate deployment. Additional configuration is needed to enable this, as described in the documentation here. If you're looking to use the same roles from the token when invoking the EJB, you'll want to follow the steps in this section to configure a virtual-security-domain and then add a corresponding @SecurityDomain annotation to your EJB.

Are you running into this issue with the new virtual-security-domain configuration?

Will King

unread,
Jun 15, 2023, 10:13:10 PM6/15/23
to WildFly
Thanks for the reply! This is with Wildfly 28 and identity propagation, like so (note MY_EAR.ear contains the DEPLOYMENT_NAME.war of the secure-deployment in the OIDC subsystem config):

<subsystem xmlns="urn:wildfly:elytron:17.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
    ...
    <security-domains>
        <security-domain name="domain1" default-realm="realm1" permission-mapper="default-permission-mapper" trusted-virtual-security-domains="MY_EAR.ear">
            <realm name="realm1" role-decoder="from-roles-attribute" />
        </security-domain>
        <virtual-security-domain name="MY_EAR.ear" outflow-security-domains="domain1" />
    </security-domains>
</subsystem>


I had not applied the @SecurityDomain attribute to the EJB. I can try that, but I'm wondering how that will work if the same EJB is used in 2 separate EAR deployments. Right now, I have updated one EAR to use OIDC while the other is using form-based auth, but even if both use OIDC, would they have to use 2 different virtual security domains, forcing the EJB @SecurityDomain annotation to choose between them?

Phrased a bit differently, is it possible for the same EJB to be annotated with @RolesAllowed and used in 2 deployments (potentially 2 auth methods), achieving the same effect as different security realms and/or auth methods for the same domain?

Will King

unread,
Jun 16, 2023, 9:51:13 AM6/16/23
to WildFly
Adding @SecurityDomain("MY_EAR.ear") doesn't seem to make a difference, actually. I tried to update the security domain for that EJB in jboss-ejb3.xml as well, same result.

Another data point which may be helpful is that in the servlet, SecurityIdentity.getRoles() works as expected, but is an empty set in the EJB (once the identity is propagated to the outflow security domain).
Reply all
Reply to author
Forward
0 new messages