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 for an arbitrary set of claims (including user defined claims) #1182

Open
cstrahan opened this issue Feb 2, 2018 · 14 comments
Open

Comments

@cstrahan
Copy link

cstrahan commented Feb 2, 2018

Dex currently has support for some particular set of claims, and that choice is reflected in various rigid data structures and e.g. the queries that make up the persistence backends (see storage/sql/crud.go for example). Each time a new claim is to be supported by Dex, the Dex maintainers must touch many files and many data structures. This is tedious work that could be obviated by a design change where an arbitrary set of claims can be plumbed through the system, and the storage backends would be changed such that they have no prior, hard coded knowledge about some set of predefined claims. There are a number of issues that are currently open proposing changes to the supported claims, and each would be easier to implement under this proposed design change:

In addition to easing the development burden for the Dex maintainers, this would have the added benefit of making it trivial to allow third party connector developers to specify additional claims of their own choosing.

This is something I could contribute, if this would be a welcome change.

@ChSch3000
Copy link

I would be happy if we can support at least the OpenID Standard claims 5.1 Standard Claims

@danielpcox
Copy link

For what it's worth (though, full-disclosure: I also work @DecipherNow) I also need this before we can use Dex to front identity providers that specify (potentially complex) user security attributes in custom claims. I would also be happy to help contribute the necessary improvements with @cstrahan, if we could be reasonably certain of general interest.

@zicklag
Copy link

zicklag commented Jun 25, 2020

if we could be reasonably certain of general interest.

Well there's 10 👍 on this issue now. 🤷‍♂️ 😃


I'm desiring to use Dex for a Hasura authentication backend, but the issue is that Hasura expects certain specific claims that Dex will not provide. I need to be able to take the claims that Dex can derive such as username and groups and transform them into the Hasura accepted claims.

For example I need to go from this:

{
  "iss": "http://123.456.789.100:5556/",
  "sub": "Caieoruqopier",
  "aud": "testapp",
  "exp": 1593188378,
  "iat": 1593101978,
  "nonce": "qpoireioquweiorpq",
  "at_hash": "t-asdfjalskdfjl",
  "email": "[email protected]",
  "email_verified": true,
  "groups": [
    "admin",
    "staff"
  ],
  "name": "Dude"
}

And I need to convert it to:

{
  "iss": "http://123.456.789.100:5556/",
  "sub": "Caieoruqopier",
  "aud": "testapp",
  "exp": 1593188378,
  "iat": 1593101978,
  "nonce": "qpoireioquweiorpq",
  "at_hash": "t-asdfjalskdfjl",
  "email": "[email protected]",
  "email_verified": true,
  "groups": [
    "admin",
    "staff"
  ],
  "name": "Dude",
  "https://hasura.io/jwt/claims": {
    "x-hasura-allowed-roles": ["admin", "staff"],
    "x-hasura-default-role": "admin",
    "x-hasura-user-id": "[email protected]"
  }
}

I would need some way to create fill out these custom claims, though. I'm thinking something like this in the config YAML:

- type: github
   # Provider options...
   # Custom claims could be used on any provider type
   customClaims:
     https://hasura.io/jwt/claims:
       # Use go template language for values and the existing claims as inputs
       # to the template.
       x-hasura-allowed-roles: {{ groups }}
       x-hasura-default-role: {{ index groups 1 }}
       x-hasura-user-id: {{ email }}

@zicklag
Copy link

zicklag commented Jun 25, 2020

Update: Just found this PR ( hasura/graphql-engine#3575 ) in Hasura which makes this unnecessary for my particular use-case, I think, but I still think that custom claims would be a great feature.

@zicklag
Copy link

zicklag commented Jun 25, 2020

Now that I think about it, I could still use a way to get more information about the user from certain backends like LDAP. For example, I want to know the users username ( in LDAP it's the uid ) and their full name ( in LDAP it's the cn ), but I'm only allowed to grab one value for the name with the current LDAP connector.

I think different connectors would need different connector-specific ways of adding custom claims that are based on the connector data ( such as LDAP ), but all connectors could support static/templated custom claims like the YAML example above.

@candlerb
Copy link
Contributor

At the simplest level, custom claims could configured explicitly:

  • per user - using the (provider, sub) pair as the key
  • per group - using the (provider, group) pair as the key

and stored either in YAML or in a SQL/etcd backend (with API maintenance). That would cover my use cases, as long as custom claims includes being able to add custom groups.

It looks like there are two further suggestions:

  • algorithmic mapping of claims to claims, such as the x-hasura-user-id example above
  • algorithmic mapping of source database attributes to claims, such as arbitrary LDAP attributes

I think those would be done most flexibly by spawning a child process which takes JSON on stdin and returns updated or additional claims on stdout. Then it can be written in whatever language you like, and use whatever data sources you like.

@KairaMiu
Copy link

What is the status of this issue?
Is there currently a possibility to create custom claims or are you planning to implement this feature?

I would need this feature as minIO needs custom claim "policy" (possible values: "writeonly", "readonly", "readwrite").

@harshavardhana
Copy link

I would need this feature as minIO needs custom claim "policy" (possible values: "writeonly", "readonly", "readwrite").

FWIW - You can configure custom claims @KairaMiu

docs/sts/dex.md:export MINIO_IDENTITY_OPENID_CLAIM_NAME=groups

@candlerb
Copy link
Contributor

Not all IDPs let you choose the names of your groups though. For example, using Azure AD as your IDP, I believe all the groups are UUIDs. Maybe you can rename your STS policies with those UIUD names, but it's not ideal.

In general, I see a tension between IDPs and applications:

  • Some IDP providers only provide specific standard claims. They expect that the application will do all authorization (configured based on individual user identities, or group memberships)
  • Some IDP consumers (applications) expect the IDP to provide specific authorization claims to meet their needs

I see Dex in the middle as a way to resolve this, if it can add extra claims for specific users and/or specific groups - perhaps scoped to individual consuming applications, so that other apps don't see irrelevant or conflicting claims.

@sagikazarmark
Copy link
Member

I think Dex could probably help with this, #1635 could possibly provide an opportunity to alter claims, but I'm also concerned this is an infinitely deep rabbit hole we might not want to go down to. I wouldn't want to clutter Dex with application specific logic. As long as we can keep the core clean and provide extension points, I'm all in.

@candlerb
Copy link
Contributor

I think that makes sense, although I'd also like to see either

  1. Extension of the existing storage engine and API to support applying claims to users and groups
    (including additional group memberships); or
  2. Separate out the build-in user/password management (CreatePassword, UpdatePassword, DeletePassword, ListPasswords, VerifyPassword) into a plugin. In that case, maybe LDAP becomes a plugin too.

This is to avoid having static users/passwords in one place managed by one API, while the claims and group memberships are stored in a different place managed by a different API.

@candlerb
Copy link
Contributor

I have another concrete example of where custom claims could be used.

PostgREST, a REST front-end to Postgres, uses JWT claims to perform authorization. Specifically, it requires:

{
    "role": "<postgres-role>"
}

to switch to a particular postgres role for this user. (The code inside the database can also look at additional claims such as "email" if required, but "role" is mandatory to start this process)

Therefore, it would be extremely useful if I could attach this claim to specific users and/or groups.

This also makes something clear to me: adding such custom claims should be specific to the Dex client (audience). It's pointless adding a PostgREST "role" claim for tokens destined to a different audience; and in the worst case, two different apps may use the "role" claim for different purposes.

Hence I think custom claims should be attached to (provider, sub, audience) and (provider, group, audience) [^1][^2]

To be most useful, I believe these custom claims should be in Dex's own data store (i.e. etcd, sqlite or whatever). These could then be managed via the gRPC interface. Whilst the LDAP backend could also be extended for custom claims, I consider the LDAP backend to be a "connector" like the Github or Google connectors: a remote source of truth, which you may not want to meddle with (e.g. a corporate Active Directory where you are not allowed to alter the schema).


[^1] Or more generally: (provider, claim_name, claim_value, audience). You could then match arbitrary claims in the JWT provided by the upstream connector.

[^2] There needs to be some rule for what happens if there are conflicts, e.g. a user is member of two different groups which have different values for the same claim. Maybe there should be a priority value attached to the row, and highest priority wins.

It's possible also that someone might want to assemble a multi-valued list claim as a list. The most likely use case I can see for that is updating or replacing the "group" claim itself - e.g. if a user is a member of group "some-long-uid" from Azure Active Directory, then make them a member of group "admins" for a particular client application.

@candlerb
Copy link
Contributor

FYI, the proposed middleware implementation in PR #1841 extends the connector.Identity object with

	CustomClaims map[string]interface{}

@Fresa
Copy link

Fresa commented May 5, 2021

Azure AD can emit a roles claim in the id_token containing all application roles assigned to the user. Would be really nice to be able to funnel through those to be used for RBAC mapping as a complement to the groups claim.
https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps

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

No branches or pull requests

9 participants