Opensearch Dashboards 2.14 openid role mapping assistance

Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):
Opensearch 2.14 and Opensearch Dashboards 2.14
Running in Openshift from official images

Describe the issue:
I am trying to use Ping Federate as an openid idp for access to OpenSearch Dashboards.

The users we want to have access are in an AD group.

once we have this configured we go to the opensearch dashboards and select the button for login using SSO.
This redirects us we get authenticated via PingID and are returned to Opensearch dashboards.
However we have no roles mapped other than own_index
the username shown in dashboards is the users email address

Configuration:
auth section of the opensearch config.yml

    authc:
      basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: "basic"
          challenge: false
        authentication_backend:
          type: "intern"
      openid_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: "openid"
          challenge: false
          config:
            subject_key: "email"
            roles_key: "groups"
            openid_connect_url: "https://my.company.com/.well-known/openid-configuration"
        authentication_backend:
          type: "noop"

This is the opensearch_dashboards.yml

opensearch_security.auth.type: ["basicauth","openid"]
opensearch_security.openid.connect_url: "https://my.company.com/.well-known/openid-configuration"
opensearch_security.openid.client_id: "eo-1lmx-genai-opensearch"
opensearch_security.openid.client_secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
opensearch_security.openid.base_redirect_url: "https://myapp.company.com"
opensearch_security.openid.scope: "openid email profile groups"
opensearch_security.openid.header: "Authorization"
opensearch_security.auth.multiple_auth_enabled: true

in roles_mapping.yml

for the all_access role i added

all_access:
  hosts: []
  users: []
  reserved: false
  hidden: false
  backend_roles:
  - "admin"
  - "us\\eo.1lmx.genai.opensearch.admins"
  - "us\\eo.1lmx.genai.aspire.admins"
  - "eo.1lmx.genai.aspire.admins"
  - "eo.1lmx.genai.opensearch.admins"
  - "myuser@company.com"
  and_backend_roles: []

Relevant Logs or Screenshots:

Hi @Jcourtade,

Do you have a token sample sent from your IdP to OpenSearch?

Best,
mj

I would love to know how to get one of those :slight_smile:

I do not This is the output from the well known endpoint

{
    "issuer": "https://my.company.com",
    "authorization_endpoint": "https://my.company.com/as/authorization.oauth2",
    "token_endpoint": "https://my.company.com/as/token.oauth2",
    "revocation_endpoint": "https://my.company.com/as/revoke_token.oauth2",
    "userinfo_endpoint": "https://my.company.com/idp/userinfo.openid",
    "introspection_endpoint": "https://my.company.com/as/introspect.oauth2",
    "jwks_uri": "https://my.company.com/pf/JWKS",
    "registration_endpoint": "https://my.company.com/as/clients.oauth2",
    "ping_revoked_sris_endpoint": "https://my.company.com/pf-ws/rest/sessionMgmt/revokedSris",
    "ping_session_management_sris_endpoint": "https://my.company.com/pf-ws/rest/sessionMgmt/sessions",
    "ping_session_management_users_endpoint": "https://my.company.com/pf-ws/rest/sessionMgmt/users",
    "ping_end_session_endpoint": "https://my.company.com/idp/startSLO.ping",
    "backchannel_logout_supported": true,
    "backchannel_logout_session_supported": true,
    "device_authorization_endpoint": "https://my.company.com/as/device_authz.oauth2",
    "scopes_supported": [
        "lm_job",
        "us_person_status",
        "preferred_username",
        "suffix",
        "credential_authenticator",
        "offline_access",
        "mfa_required",
        "email",
        "lmco_upn",
        "address",
        "email_verified",
        "openid",
        "lm_business_area",
        "profile",
        "lmc_subject_uuid",
        "given_name",
        "middle_name",
        "location_of_authentication",
        "lm_employee_type",
        "lm_credential_strength",
        "upn",
        "country_access_claim",
        "employee_id",
        "lm_business_unit",
        "name",
        "phone_number",
        "family_name"
    ],
    "claims_supported": [
        "address",
        "country_access_claim",
        "credential_authenticator",
        "email",
        "email_verified",
        "employee_id",
        "family_name",
        "given_name",
        "groups",
        "lm_business_area",
        "lm_business_unit",
        "lm_credential_strength",
        "lm_employee_type",
        "lm_job",
        "lmc_subject_uuid",
        "lmco_upn",
        "location_of_authentication",
        "middle_name",
        "name",
        "phone_number",
        "preferred_username",
        "profile",
        "scope",
        "sub",
        "suffix",
        "upn",
        "us_person_status"
    ],
    "response_types_supported": [
        "code",
        "token",
        "id_token",
        "code token",
        "code id_token",
        "token id_token",
        "code token id_token"
    ],
    "response_modes_supported": [
        "fragment",
        "fragment.jwt",
        "query",
        "query.jwt",
        "form_post",
        "form_post.jwt",
        "jwt"
    ],
    "grant_types_supported": [
        "implicit",
        "authorization_code",
        "refresh_token",
        "password",
        "client_credentials",
        "urn:pingidentity.com:oauth2:grant_type:validate_bearer",
        "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "urn:ietf:params:oauth:grant-type:saml2-bearer",
        "urn:ietf:params:oauth:grant-type:device_code",
        "urn:ietf:params:oauth:grant-type:token-exchange",
        "urn:openid:params:grant-type:ciba"
    ],
    "subject_types_supported": [
        "public",
        "pairwise"
    ],
    "id_token_signing_alg_values_supported": [
        "none",
        "HS256",
        "HS384",
        "HS512",
        "RS256",
        "RS384",
        "RS512",
        "PS256",
        "PS384",
        "PS512"
    ],
    "token_endpoint_auth_methods_supported": [
        "client_secret_basic",
        "client_secret_post",
        "client_secret_jwt",
        "private_key_jwt",
        "tls_client_auth"
    ],
    "token_endpoint_auth_signing_alg_values_supported": [
        "RS256",
        "RS384",
        "RS512",
        "ES256",
        "ES384",
        "ES512",
        "PS256",
        "PS384",
        "PS512",
        "HS256",
        "HS384",
        "HS512"
    ],
    "claim_types_supported": [
        "normal"
    ],
    "claims_parameter_supported": false,
    "request_parameter_supported": true,
    "request_uri_parameter_supported": false,
    "authorization_response_iss_parameter_supported": false,
    "request_object_signing_alg_values_supported": [
        "RS256",
        "RS384",
        "RS512",
        "ES256",
        "ES384",
        "ES512",
        "PS256",
        "PS384",
        "PS512"
    ],
    "request_object_encryption_alg_values_supported": [
        "dir",
        "A128KW",
        "A192KW",
        "A256KW",
        "A128GCMKW",
        "A192GCMKW",
        "A256GCMKW",
        "ECDH-ES",
        "ECDH-ES+A128KW",
        "ECDH-ES+A192KW",
        "ECDH-ES+A256KW",
        "RSA-OAEP",
        "RSA-OAEP-256"
    ],
    "request_object_encryption_enc_values_supported": [
        "A128CBC-HS256",
        "A192CBC-HS384",
        "A256CBC-HS512",
        "A128GCM",
        "A192GCM",
        "A256GCM"
    ],
    "id_token_encryption_alg_values_supported": [
        "dir",
        "A128KW",
        "A192KW",
        "A256KW",
        "A128GCMKW",
        "A192GCMKW",
        "A256GCMKW",
        "ECDH-ES",
        "ECDH-ES+A128KW",
        "ECDH-ES+A192KW",
        "ECDH-ES+A256KW",
        "RSA-OAEP",
        "RSA-OAEP-256"
    ],
    "id_token_encryption_enc_values_supported": [
        "A128CBC-HS256",
        "A192CBC-HS384",
        "A256CBC-HS512",
        "A128GCM",
        "A192GCM",
        "A256GCM"
    ],
    "introspection_signing_alg_values_supported": [
        "HS256",
        "HS384",
        "HS512",
        "RS256",
        "RS384",
        "RS512",
        "PS256",
        "PS384",
        "PS512"
    ],
    "introspection_encryption_alg_values_supported": [
        "dir",
        "A128KW",
        "A192KW",
        "A256KW",
        "A128GCMKW",
        "A192GCMKW",
        "A256GCMKW",
        "ECDH-ES",
        "ECDH-ES+A128KW",
        "ECDH-ES+A192KW",
        "ECDH-ES+A256KW",
        "RSA-OAEP",
        "RSA-OAEP-256"
    ],
    "introspection_encryption_enc_values_supported": [
        "A128CBC-HS256",
        "A192CBC-HS384",
        "A256CBC-HS512",
        "A128GCM",
        "A192GCM",
        "A256GCM"
    ],
    "authorization_signing_alg_values_supported": [
        "HS256",
        "HS384",
        "HS512",
        "RS256",
        "RS384",
        "RS512",
        "PS256",
        "PS384",
        "PS512"
    ],
    "authorization_encryption_alg_values_supported": [
        "dir",
        "A128KW",
        "A192KW",
        "A256KW",
        "A128GCMKW",
        "A192GCMKW",
        "A256GCMKW",
        "ECDH-ES",
        "ECDH-ES+A128KW",
        "ECDH-ES+A192KW",
        "ECDH-ES+A256KW",
        "RSA-OAEP",
        "RSA-OAEP-256"
    ],
    "authorization_encryption_enc_values_supported": [
        "A128CBC-HS256",
        "A192CBC-HS384",
        "A256CBC-HS512",
        "A128GCM",
        "A192GCM",
        "A256GCM"
    ],
    "pushed_authorization_request_endpoint": "https://my.company.com/as/par.oauth2",
    "require_pushed_authorization_requests": false,
    "authorization_details_types_supported": [],
    "backchannel_authentication_endpoint": "https://my.company.com/as/bc-auth.ciba",
    "backchannel_token_delivery_modes_supported": [
        "poll",
        "ping"
    ],
    "backchannel_authentication_request_signing_alg_values_supported": [
        "RS256",
        "RS384",
        "RS512",
        "ES256",
        "ES384",
        "ES512",
        "PS256",
        "PS384",
        "PS512"
    ],
    "backchannel_user_code_parameter_supported": false,
    "code_challenge_methods_supported": [
        "plain",
        "S256"
    ],
    "dpop_signing_alg_values_supported": [
        "RS256",
        "RS384",
        "RS512",
        "ES256",
        "ES384",
        "ES512",
        "PS256",
        "PS384",
        "PS512"
    ]
}```

I guess where I am at with this is hoping to have my config validated

Make sure I did not miss some configuration I need to do this. …

trying to figure out where this is being logged and how to turn on debugging for this

I don’t see much in the opensearch dashboard logs

is the actual work being done in the opensearch cluster?

@Jcourtade, would you mind running the below and sharing the output:

curl --insecure -u <user>:<password> -XGET https://<OS_node>:9200/_plugins/_security/authinfo?pretty

Thanks,
mj

the only user i can do that with is the admin user…

{
  "user" : "User [name=admin, backend_roles=[admin], requestedTenant=null]",
  "user_name" : "admin",
  "user_requested_tenant" : null,
  "remote_address" : "XXXXXXXXXXXXXXXXXXXX",
  "backend_roles" : [
    "admin"
  ],
  "custom_attribute_names" : [ ],
  "roles" : [
    "own_index",
    "all_access"
  ],
  "tenants" : {
    "global_tenant" : true,
    "admin_tenant" : true,
    "admin" : true
  },
  "principal" : null,
  "peer_certificates" : "0",
  "sso_logout_url" : null
}

this looks like the "basicauth" user, can you please do the same using an OpenId user?

Best,
mj

If I do this in dashboards as the logged in user i get this

{
  "user": "User [name=myuser@my.company.com, backend_roles=[], requestedTenant=__user__]",
  "user_name": "myuser@my.company.com",
  "user_requested_tenant": "__user__",
  "remote_address": "XXXXXXXXXXXXXXX",
  "backend_roles": [],
  "custom_attribute_names": [
    "attr.jwt.iss",
    "attr.jwt.email_verified",
    "attr.jwt.preferred_username",
    "attr.jwt.middle_name",
    "attr.jwt.given_name",
    "attr.jwt.aud",
    "attr.jwt.acr",
    "attr.jwt.family_name",
    "attr.jwt.scope",
    "attr.jwt.sub",
    "attr.jwt.name",
    "attr.jwt.exp",
    "attr.jwt.iat",
    "attr.jwt.jti",
    "attr.jwt.email"
  ],
  "roles": [
    "own_index"
  ],
  "tenants": {
    "myuser@my.company.com": true
  },
  "principal": null,
  "peer_certificates": "0",
  "sso_logout_url": null
}

@Jcourtade, can you test with “roles” instead of “groups”:

roles_key: "roles"

thanks,
mj

I can but there are no roles passed if you check the output of the well known endpoint

changed that in the opemsearch_dashboards.yml

restarted the dashboards pod

i log into the dashboard as my oidc user and still have no mapped internal roles

image

i have to change that in the config.yml and rerun the security script on the opnesearch server

ok I am doing that and retesting

same thing in dashboards with the oidc user

image

So I managed to get a role mapped by creating a copy of all_access and adding the username/email address to it

in roles_mapping.yml

all_access_copy:
  hosts: []
  users:
  - "myuser@myco.com"
  reserved: false
  hidden: false
  backend_roles: []
  and_backend_roles: []

now when the user logs in he sees

{
  "user": "User [name=myuser@myco.com, backend_roles=[], requestedTenant=__user__]",
  "user_name": "myuser@myco.com",
  "user_requested_tenant": "__user__",
  "remote_address": "10.129.1.40:53724",
  "backend_roles": [],
  "custom_attribute_names": [
    "attr.jwt.iss",
    "attr.jwt.email_verified",
    "attr.jwt.preferred_username",
    "attr.jwt.middle_name",
    "attr.jwt.given_name",
    "attr.jwt.aud",
    "attr.jwt.acr",
    "attr.jwt.family_name",
    "attr.jwt.scope",
    "attr.jwt.sub",
    "attr.jwt.name",
    "attr.jwt.exp",
    "attr.jwt.iat",
    "attr.jwt.jti",
    "attr.jwt.email"
  ],
  "roles": [
    "all_access_copy",
    "own_index"
  ],
  "tenants": {
    "myuser@myco.com": true,
    "global_tenant": true,
    "admin_tenant": true
  },
  "principal": null,
  "peer_certificates": "0",
  "sso_logout_url": null
}

image

So the question becomes …

how do i restrict users to just a subset of all of the oidc possible users?
Why are we not getting the groups information?

Yep, you can map the roles via username (in your case subject_key: "email" ) or backen_roles ( roles_key: "groups"). It would be very helpful to see what’s in the JWT to see what roles_key can be mapped to, as at the moment it looks like there is no key called groups (or it is empty, etc., …).

I am not that familiar with Ping Federate, tho, I will try to play with it in my lab and if I find the answer for you I`ll get back to you.

best,
mj

Thanks

so the other problem is that every single user in the IDP can log into dashboards

I need a way to restrict them to a list of either usernames or groups

if you know how i can get opensearch to log the LWT token nfo and where we can look for it I would be happy to grab that and redact it

I think you need to ensure that role mapping is correctly configured for these users

The users are in an AD group.

I have no way to use that group it seems or I cannot figure out how to configure for it.

If I have a way to see what the user interaction was with the IDP and what was being returend by the IDP maybe we could figure this out.

As it is I do not know where this is being logged or if it is. The logs on the dashboards just show me my username basically without much other information.

if the authentication and communication happening on the opensearch servers?