Getting "SSO failed" after successfully logging into Keycloak

I compared my two Foreman instances (new 2.5.2 and upgraded from 1.24 → 2.5.2) and they both have the same Apache config (yet the new 2.5.2 works as expected).

I don’t have the Apache config you mentioned above (lookup_identity.conf.erb). After looking through the Puppet config, it doesn’t look like the lookup_identity.conf.erb file is used when only enabling Keycloak. You have to enable IPA to get the lookup_identity.conf Apache configuration: puppet-foreman/apache.pp at 91850a2b4522406a28dbc98e2c3f215130d08dab · theforeman/puppet-foreman · GitHub

I’m going to try to manually create that Apache config file in the conf.d directory and see if just setting the proper headers solves the OIDC on my original Foreman instance :crossed_fingers:

Turned out i made things worse, not sure how. I was able to revert my configuration and get my new 2.5.2 instance working with keycloak.

I tried using a different OIDC provider (Okta) and I was getting a Foreman SSO failed error saying Failed to create external User '': Username can't be blank. Why do you think that might be happening @evgeni? If it’s working fine with Keycloak, why would it be complaining about an empty username if I’m trying to use Okta?

I know this might be out of the scope of this thread (and support in general) but I was just curious if you might know the specifics of how keycloak presents/maps its data and I can compare that to Okta

I have honestly no idea.

Hello @eleneshector: I might be able to answer this for you, so there are certain fields that must be present in the JWT that we receive as a access token from the Openid provider i.e Keycloak in our case.

If you are able to get into the code and apply a debugger to get the JWT (access token) for me, I might be able to tell you how you can fix this to work with Okta. To further explain, in the Foreman project we try to follow all the guidelines provided by the RFC, so all endpoints are as per the RFC, if Okta doesn’t follow that then you will face errors.

I hope that answers your question, if not, let me know :slight_smile:

1 Like

Hello,

I have the same error with Auth0 provider.
@eleneshector were you able to fix it?

Thank you

Hey @Anthony_Chevalet ,

Sadly no. Not long after my last post, I had to move on to other issues/projects. We still have a story open for getting Foreman under SSO, but it’s not priority at the moment. Hopefully I can work on it in the near future and post an update. Please let me know if you get it working for Auth0 and I’ll cheer on your behalf :slight_smile:

Hey, actually I’ve just found a way to get my user created in foreman, by setting the REMOTE_USER* request headers in my browser! It looks like those are lost when coming from apache. still investigating… will let you know :slight_smile:

I’ll keep my fingers crossed! :crossed_fingers:

Hey,

I have a working setup with auth0 and the following configuration:

# /etc/httpd/conf.d/15-foreman-ssl-oidc.conf

OIDCProviderMetadataURL https://<redacted>.auth0.com/.well-known/openid-configuration
OIDCClientID <redacted>
OIDCClientSecret <redacted>
OIDCRedirectURI https://<redacted>/users/extlogin/redirect_uri
OIDCCryptoPassphrase <redacted>
OIDCScope "openid email profile"

OIDCResponseType "id_token"
OIDCRemoteUserClaim nickname@

<Location /users/extlogin>
    AuthType openid-connect
    Require valid-user
    LogLevel debug

    RequestHeader set REMOTE_USER %{OIDC_CLAIM_nickname}e
    RequestHeader set REMOTE_USER_EMAIL %{OIDC_CLAIM_email}e
    RequestHeader set REMOTE_USER_FIRSTNAME %{OIDC_CLAIM_given_name}e
    RequestHeader set REMOTE_USER_LASTNAME %{OIDC_CLAIM_family_name}e
    RequestHeader set REMOTE_USER_GROUPS %{OIDC_CLAIM_http---foreman_groups}e
</Location>

On Auth0 side, I have a standard application and one rule to manage custom groups (terraform version):

resource "auth0_client" "foreman" {
  name                                = "Foreman"
  description                         = "Foreman web UI/API"
  app_type                            = "spa"
  cross_origin_auth                   = false
  is_first_party                      = true
  custom_login_page_on                = false
  is_token_endpoint_ip_header_trusted = false
  token_endpoint_auth_method          = "client_secret_post"
  oidc_conformant                     = true
  callbacks = [
    "https://<redacted>/users/extlogin/redirect_uri",
  ]
  allowed_logout_urls = [
    "https://<redacted>/users/users/extlogout",
  ]
  grant_types = ["authorization_code", "implicit", "refresh_token"]
  jwt_configuration {
    lifetime_in_seconds = 36000
    secret_encoded      = false
    alg                 = "RS256"
    scopes              = {}
  }
}

resource "auth0_rule" "foreman" {
  name = "Terraformed - Foreman"
  script = file("./rules/foreman.js")
  enabled = true
  order = 123
}
// ./rules/foreman.js
/*global UnauthorizedError*/
// eslint-disable-next-line no-unused-vars
function foreman(user, context, callback) {
  if (context.clientName === 'Foreman') {
    const groupsAllowed = ['foreman_admin', 'foreman_users'];

    if (!Object.prototype.hasOwnProperty.call(user, 'groups_custom')) {
      user.groups_custom = [];
    }

    const userHasAccess = user.groups_custom.some((group) => groupsAllowed.includes(group));
    if (!userHasAccess) {
      console.log('Access denied.!');
      return callback(new UnauthorizedError('Access denied.'));
    }

    const foremanGroups = user.groups_custom.filter((name) => name.startsWith('foreman_')).join(':');
    context.idToken['http://foreman_groups'] = foremanGroups;
  }
  callback(null, user, context);
}

Note that I have no oidc settings on Foreman side, only authorize_login_delegation and the request headers added by apache:

# hammer setting list --search oidc
---------------|----------------|-------|---------------------------------------------------------------------------------
NAME           | FULL NAME      | VALUE | DESCRIPTION                                                                     
---------------|----------------|-------|---------------------------------------------------------------------------------
oidc_jwks_url  | OIDC JWKs URL  |       | OpenID Connect JSON Web Key Set(JWKS) URL. Typically https://keycloak.example...
oidc_audience  | OIDC Audience  | []    | Name of the OpenID Connect Audience that is being used for Authentication. In...
oidc_issuer    | OIDC Issuer    |       | The iss (issuer) claim identifies the principal that issued the JWT, which ex...
oidc_algorithm | OIDC Algorithm |       | The algorithm used to encode the JWT in the OpenID provider.                    
---------------|----------------|-------|---------------------------------------------------------------------------------

External users are correctly created and mapped to the correct foreman groups! :sunny:

1 Like

That’s awesome @Anthony_Chevalet ! Glad you were able to get it working for Auth0. I’m going to see if there are any similarities to my Okta configuration and hopefully get it working too.

1 Like

Has anyone been able to get this working with Okta? I can’t seem to get past the “Failed to create external User ‘’: Username can’t be blank” error.

Here is my configuration so far.

# /etc/httpd/conf.d/foreman-openidc_oidc_keycloak_ssl-realm.conf
OIDCClientID <redacted>
OIDCProviderMetadataURL https://<redacted>.okta.com/oauth2/default/.well-known/openid-configuration
OIDCCryptoPassphrase <redacted>
OIDCClientSecret <redacted>
OIDCRedirectURI https://<redacted>/users/extlogin/redirect_uri
OIDCRemoteUserClaim email

OIDCOAuthRemoteUserClaim email
OIDCScope "openid email profile"

<Location /users/extlogin>
    AuthType openid-connect
    Require valid-user
    LogLevel debug

    RequestHeader set REMOTE_USER %{OIDC_CLAIM_email}e
    RequestHeader set REMOTE_USER_EMAIL %{OIDC_CLAIM_email}e
    RequestHeader set REMOTE_USER_FIRSTNAME %{OIDC_CLAIM_given_name}e
    RequestHeader set REMOTE_USER_LASTNAME %{OIDC_CLAIM_family_name}e
</Location>

with the following configuration in Foreman

# hammer setting list --search oidc
---------------|----------------|---------------------------------------------------|---------------------------------------------------------------------------------
NAME           | FULL NAME      | VALUE                                             | DESCRIPTION
---------------|----------------|---------------------------------------------------|---------------------------------------------------------------------------------
oidc_jwks_url  | OIDC JWKs URL  | https://<redacted>.okta.com/oauth2/default/v1/keys | OpenID Connect JSON Web Key Set(JWKS) URL. Typically https://keycloak.example...
oidc_audience  | OIDC Audience  | ["api://default"]                                 | Name of the OpenID Connect Audience that is being used for Authentication. In...
oidc_issuer    | OIDC Issuer    | https://<redacted>.okta.com/oauth2/default         | The iss (issuer) claim identifies the principal that issued the JWT, which ex...
oidc_algorithm | OIDC Algorithm | RS256                                             | The algorithm used to encode the JWT in the OpenID provider.
---------------|----------------|---------------------------------------------------|---------------------------------------------------------------------------------
# hammer setting list --search delegation
-------------------------------------------------------|--------------------------------------------------------|----------------------------------------------------|---------------------------------------------------------------------------------
NAME                                                   | FULL NAME                                              | VALUE                                              | DESCRIPTION
-------------------------------------------------------|--------------------------------------------------------|----------------------------------------------------|---------------------------------------------------------------------------------
login_delegation_logout_url                            | Login delegation logout URL                            | https://<redacted>/users/extlogout | Redirect your users to this url on logout (authorize_login_delegation should ...
authorize_login_delegation_auth_source_user_autocreate | Authorize login delegation auth source user autocreate | External                                           | Name of the external auth source where unknown externally authentication user...
authorize_login_delegation                             | Authorize login delegation                             | true                                               | Authorize login delegation with REMOTE_USER HTTP header
authorize_login_delegation_api                         | Authorize login delegation API                         | true                                               | Authorize login delegation with REMOTE_USER HTTP header for API calls too
-------------------------------------------------------|--------------------------------------------------------|----------------------------------------------------|---------------------------------------------------------------------------------

I’d advise you to open a new thread instead. Also specify the versions you’re using there.

Thank you! New thread created.