Generic_oauth role_attribute_path unable to map groups to role

  • What Grafana version and what operating system are you using?
    Grafana Operator 5.12.0 on Openshift 4.12, Grafana Version 10.4.3

  • What are you trying to achieve?
    I would like to have all members of a particular group be given Admin rights upon login.

  • How are you trying to achieve it?
    config:

    auth.generic_oauth:
      enabled: 'true'
      client_secret: <secret>
      allow_sign_up: 'true'
      token_url: <token url>
      api_url: <api url>
      name: OAuth
      client_id: <client id>
      role_attribute_path: 'contains(groups[*], ''us\\group.for.admins'') && ''Admin'')'
      auth_allow_insecure_email_lookup: 'true'
      role_attribute_strict: 'true'
      allowed_domains: <domain>.com
      auth_url: <auth url>
      auto_login: 'false'
      allow_assign_grafana_admin: 'true'
      scopes: openid us_person_status preferred_username name email groups
  • What happened?
Login failed
IdP did not return a role attribute, please contact your administrator
logger=oauth.generic_oauth t=2024-09-12T12:54:45.833579126Z level=debug msg="Received user info response from API" raw_json="{\"sub\":\"<sub value>\",\"email_verified\":true,\"name\":\"<ursers name>\",\"groups\":[\"us\\\\group.for.admins\",\"us\\\\some.other.group\",\"us\\\\another.group\"]}

Confirmed using JMESPath that contains(groups[*], ‘us\\group.for.admins’) returns true

I guess that \, maybe . in the group name is causing a problem. It looks like you are using something to manage (helm?) Grafana, so make sure that each tool which is touching the config creates proper config content. Check how config content is rendered on the pod level.

Thank you for the quick response.

From the pod the role_attribute_path is:
role_attribute_path = contains(groups[*], ‘us\group.for.admins’) && ‘Admin’)

I also tried putting double qoutes around us\group.for.admins as suggested by another post to circumvent dashes, but that didn’t work either.
role_attribute_path = contains(groups[*], ‘“us\group.for.admins”’) && ‘Admin’)

So
role_attribute_path: 'contains(groups[*], ''us\\group.for.admins'') && ''Admin'')'

is rendered as:
role_attribute_path = contains(groups[*], ‘us\group.for.admins’) && ‘Admin’)

You still didn’t confirm what you are using (helm?) - what it is secret?

Still guessing it’s helm, so that was escaping \\\ was just applied by helm. So just applied another escaping \\\\ (yaml for helm) → \\ (after helm render - Grafana config).

At this point it is not a Grafana error, but how do you manage/escape Grafana config on your end.

I’m using the OpenShift Operator for Grafana.

https://github.com/grafana/grafana-operator

I am not manually deploying it with helm though. Here is quick explanation of OpenShift Operators.

So check doc for that operator implementation, maybe
https://docs.openshift.com/container-platform/4.16/openshift_images/using-templates.html

Unless escaped with a backslash, Kubernetes’ JSONPath implementation interprets characters such as ., @, and others as metacharacters, regardless of their position in the expression. Therefore, for example, to refer to a ConfigMap datum named my.key, the required JSONPath expression would be {.data['my\.key']}. Depending on how the JSONPath expression is then written in YAML, an additional backslash might be required, for example "{.data['my\\.key']}".

I think it was mapping correctly to /etc/grafana/grafana.ini in the pod since the file had

role_attribute_path = contains(groups[*], ‘us\\group.for.admins’) && ‘Admin’)

When I updated the grafana CR to include backslashes before the periods, the new grafana.ini in the pod came out as

role_attribute_path = contains(groups[*], ‘us\\group\.for\.admins’) && ‘Admin’) and also failed to authenticate. Same error as before

“Login failed
IdP did not return a role attribute, please contact your administrator”

logger=oauth.generic_oauth t=2024-09-12T17:44:05.8022369Z level=debug msg="HTTP GET" url=<userinfo url> status="200 OK" response_body="{\"sub\":\"<sub>\",\"email_verified\":true,\"name\":\"<name>\",\"groups\":[\"us\\\\group.for.admins\",\"us\\\\some.other.group\",\"us\\\\another.group\"]}
logger=oauth.generic_oauth t=2024-09-12T17:44:05.802468719Z level=debug msg="Received user info response from API" raw_json="{\"sub\":\"<sub>\",\"email_verified\":true,\"name\":\"<name>\",\"groups\":[\"us\\\\group.for.admins\",\"us\\\\some.other.group\",\"us\\\\another.group\"]}
logger=oauth.generic_oauth t=2024-09-12T17:44:05.802522079Z level=debug msg="Processing external user info" source=token data="Name: <name>, Displayname: , Login: , Username: , Email: <email>, Upn: , Attributes: map[]"
logger=oauth.generic_oauth t=2024-09-12T17:44:05.802538313Z level=debug msg="Setting user info name from name field"
logger=oauth.generic_oauth t=2024-09-12T17:44:05.802541792Z level=debug msg="Set user info email from extracted email" email=<email>
logger=oauth.generic_oauth t=2024-09-12T17:44:05.802626782Z level=warn msg="Failed to extract role" err="[oauth.role_attribute_strict_violation] idP did not return a role attribute, but role_attribute_strict is set"

Use simpler setup and simpler group names and increase complexity, when you figure out simpler setup with proper escaping, e.g.

  • no \ and no . in the group name
  • no \ and . in the group name
  • \ and . in the group name