Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Azure Entra ID #6668

Open
avernet opened this issue Dec 9, 2024 · 1 comment
Open

Support Azure Entra ID #6668

avernet opened this issue Dec 9, 2024 · 1 comment

Comments

@avernet
Copy link
Collaborator

avernet commented Dec 9, 2024

Constraints:

  • We want to minimize the amount of identity-provider-specific code.
    • In the future, we plan to add support for other identity providers, such as AWS IAM, Keycloak, Okta, Auth0, and Google Cloud Identity.
    • This is similar to how we use JDBC to minimize database-specific code.
  • The identity provider configuration should be both simple and idiomatic:
    • Simple: so that it can be easily documented, maintained, and supported by customers implementing the configuration.
    • Idiomatic: because it will be challenging to require administrators to implement an unconventional setup.
  • The solution should adhere to the KISS principle:
    • Reducing the number of moving parts.
    • Making the solution easy to understand, test, and maintain for both customers and us.

Non-constraints:

  • We don’t necessarily need to use Tomcat or ensure the solution works on any servlet container.
  • We don’t need to rely on a servlet-based mechanism; we could also:
    • Implement everything at the Orbeon Forms level, leveraging a library that supports OIDC logic for us, like https://github.com/pac4j/pac4j.
    • Use a reverse proxy, such as:
      • Apache HTTPD with mod_auth_openidc (I like that their doc starts by "Authenticating against your Microsoft Entra ID / Azure AD is fairly straight-forward")
      • NGINX with nginx-openid-connect
      • HAProxy with oauth2-proxy
    • Use a cloud-based reverse proxy, such as Azure Front Door, AWS Application Load Balancer (ALB), Google Cloud HTTP(S) Load Balancer. In that scenario:
      • The cloud reverse proxy passes an Authorization: Bearer <token> to Orbeon Forms, where the token is a JWT (JSON Web Token).
      • Orbeon Forms uses a library to validate the token and retrieve info about the user based on that token. It could be:
        • An Azure agnostic library, like the aforementioned Pac4j
        • Maybe more simply, Microsoft Authentication Library (MSAL4J). The role roles could be retrieved:
          • From the JWT token claims (but getting them in the claim might require more setup?)
          • Using the Microsoft Graph API

Once implemented, this will most likely superced #2945.

@avernet avernet changed the title Support Azure Entra ID, AWS IAM, and Keycloak Support Azure Entra ID Dec 9, 2024
@obruchez
Copy link
Collaborator

obruchez commented Dec 9, 2024

Some notes about what has been tried so far.

With Tomcat, it should be possible to integrate with Microsoft Entra ID using Secure LADP ("LDAPS") and an JNDI Directory Realm in Tomcat:

  • on Entra ID's side, the configuration is quite simple, but it's mandatory to have an SSL certificate and, hence, a dedicated domain name, even for testing
  • the full deployment on Entra ID's side is long (about 45 minutes)
  • on the client's side, I encountered some difficulties with my self-signed test certificate
    • it should be possible to store the self-signed certificate in a JKS key store to eliminate the errors I encountered, but it didn't work (i.e. I couldn't get the JNDI Directory Realm to start successfully)
    • that's a lead probably worth following through to the end, but it's not clear if role mapping is easy to do using LDAP
    • try with a Let's Encrypt certificate?

Using tomcat-oidcauth as a Tomcat valve, it's possible to integrate with Entra ID:

  • a <Valve> element must be configured in the Tomcat context, with the OIDC provider information (URL, client ID, client secret) (example)
  • I implemented a simple servlet login page which retrieves the login URL from the request attributes (injected by the valve) and redirects to that URL (~10 LOC) ; the valve then retrieves the tokens from the OIDC provider and does what it has to do with them
  • because of how tomcat-oidcauth and Tomcat are designed, tomcat-oidcauth still checks with the configured Tomcat realm whether the user logged using the OIDC provider can be authentified (call to RealmBase.authenticate)
    • as suggested by tomcat-oidcauth's author (see also this), I implemented a very simple Java realm which always authenticate users logged via the OIDC provider (~10 LOC)
    • the problem is that the realm is also responsible for attributing roles to the user (i.e. this is not done by tomcat-oidcauth)
    • retrieving the user's roles can be done in the realm, using provider-specific code, in that case using Microsoft Graph API (~15-20 LOC to retrieve any information about the user)

Some problems with tomcat-oidcauth:

  • relatively old project with no commit since 2020
  • broken links on mvnrepository.com
  • support for Jakarta package (i.e. Tomcat 10+) only available in unsupported repository fork
  • we don't have access to the access/ID tokens returned by the OIDC providers from the realm, so we can't extract anything from the tokens (groups, roles, etc.)

Support for OIDC in WildFly is far easier:

  • WildFly standalone.xml configuration works out of the box (no change needed)
  • the OIDC configuration file (oidc.json) can be copied/mounted into the Docker image/container (URL, client ID, client secret) (9 lines in my case)
  • the OIDC WildFly subsystem automatically retrieves user roles from the access token
  • to use e.g. the user email as username (principal ID), you just need to add "principal-attribute": "email", to oidc.json
  • Entra ID makes it straightforward to include groups as roles in OIDC tokens (checkbox in the UI)
  • limitation: no support for logout (yet) (but some people are working on it - activity in Oct./Nov. 2024)
  • for reference: Orbeon Forms Docker image with WildFly

Some problems encountered when using Entra ID:

  • it's slightly tricky to include the roles in the access token instead of the ID token (instructions here)
    • once you know how to do it, it's quite easy to configure
    • you need to specify an extra scope in oidc.xml (e.g. "scope":"api://6adf2c28-1df4-4c85-ace2-75bd9d48dd52/Groups.Read")
    • WildFly's support for scopes is not considered stable, so you have to start WildFly with --stability=preview (this should change in the future, when the feature is considered stable enough?)
  • groups/roles are included in the tokens as IDs (which looks like e6374c07-f34f-473a-8894-0ebe826dc2b1)
  • custom roles are only configurable in Entra ID Premium P1/P2 ("To create custom roles, your organization needs Microsoft Entra ID Premium P1 or P2.")
    • a free trial is available for P1/P2
    • I couldn't get a trial license for my account for some weird reasons (Microsoft complaining that I don't have a payment associated with my account and then redirecting me to... my credit card information...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants