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

OAuth connector #1630

Merged
merged 15 commits into from
Dec 2, 2021
Merged

Conversation

xtremerui
Copy link

@xtremerui xtremerui commented Jan 16, 2020

Hi, this implements an oauth connector, which could be used for generic authentication following OAuth2.0 framework.

@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch 2 times, most recently from f930a9f to c8d3ead Compare January 16, 2020 21:13
@xtremerui xtremerui requested a review from srenatus January 16, 2020 21:36
@mvdkleijn
Copy link
Contributor

Nice! This would be most welcome in my opinion.

@xtremerui Would you mind adding a commit or two to

a) list the generic oauth connector in the table of the main readme; and
b) add documentation entry for those of use who are too lazy (or unable) to read the code (in Documentation/connectors)

I believe that would be helpful to get the PR to be accepted.

@bonifaido @sagikazarmark This PR has stalled basically on a single person's review, I believe it'd be nice to get this in (with above mentions additions) so I'm hoping one of you could take a look since @srenatus doesn't appear to have time?

Disclaimer: I'm in no way involved with either the Concourse or Dex team. I'm just a simple user trying to help the process as it were.

@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch 2 times, most recently from 2f6d1e1 to fbc31d7 Compare July 31, 2020 18:51
@xtremerui
Copy link
Author

I have updated the documents for oauth connector. Please let me know if there is anything I can do. Thx!

Copy link
Contributor

@mvdkleijn mvdkleijn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So overall... with the caveat of me having read through the PR on my phone and not having "physically" tested it... 😄

LGTM assuming my comments are addressed.

Documentation/connectors/oauth.md Outdated Show resolved Hide resolved
Documentation/connectors/oauth.md Outdated Show resolved Hide resolved

identity.UserID, _ = userInfoResult[c.userIDKey].(string)
identity.Username, _ = userInfoResult[c.userNameKey].(string)
identity.PreferredUsername, _ = userInfoResult["name"].(string)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I am mistaken, you guys wanted to make sure the preferred_username field is available for users.

However, hardcoding it to be the same as the name field does not seem desirable to me. Apart from that it also doesn't give the backend a chance to pass preferred_username if it tries to and effectively renders preferred_username fairly useless.

My suggestion would be to:

  • default it to unset if its unset at the backend
  • pass through the value unchanged if the backend does provide the field
  • and allow a user to override the above two through a config entry which tells the connector to copy the value of another field to preferred_username

Please see the Atlassian Crowd connector for an example.

Again disclaimer: I'm not a member of Dex, just an occasional contributor trying to help both of you. 😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense. If there is connector that handles preferred_username already. I'd like to keep the behavior the same as much as possible.

@@ -474,6 +475,7 @@ var ConnectorsConfig = map[string]func() ConnectorConfig{
"gitlab": func() ConnectorConfig { return new(gitlab.Config) },
"google": func() ConnectorConfig { return new(google.Config) },
"oidc": func() ConnectorConfig { return new(oidc.Config) },
"oauth": func() ConnectorConfig { return new(oauth.Config) },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some whitespace issues

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm can't tell where the whitespace is. I took an existing line and just changed the name. It shown no difference.

@mvdkleijn
Copy link
Contributor

Hmm... I'm wondering if I made a booboo here... I believe that preferred_username is part of the OIDC spec and not the OAUTH spec. (whoops) If so, my apologies in advance.

Can we verify this? @sagikazarmark & @xtremerui ? I did not find any reference to preferred_username in the OAUTH 2 specs, only in the OIDC specs.

@xtremerui
Copy link
Author

@mvdkleijn I think you are right. Though I can't see how it affects the current implementation in this PR.

Upstream might or might not include preferred_username claim.
If it does, users of oauth connection could leave the key not configured so it will pick up the claim.
If it does not, the preferred_username field in identity could be used for any claim, which is more flexible since oauth connector meant to be a backup plan for auth provider that support Oauth but not OIDC.

@mvdkleijn
Copy link
Contributor

Sounds sensible enough, but I'll leave this decision to one of the Dex mainteiners like @sagikazarmark 😄 I'm juat happy to see there's some movement in these PRs again since they're so close to being merged.

@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch 2 times, most recently from 64d658f to e094327 Compare September 28, 2020 19:39
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch 2 times, most recently from 93b72b4 to 785319a Compare October 3, 2020 00:57
Copy link
Member

@sagikazarmark sagikazarmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @xtremerui

I think it's a great feature.

Found a few nits, can you please take a look at those? Thanks!

Comment on lines 38 to 48
# Optional: Configurable keys for groups claim look up
# Default: groups
# groupsKey:

# Optional: Configurable keys for user ID claim look up
# Default: user_id
# userIDKey:

# Optional: Configurable keys for preferred username claim look up
# Default: preferred_username
# preferredUsernameKey:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a claim mapping for these (except userIDKey) similar to the one introduced in #1634?

(userIDKey is not actually an OIDC claim, so it should remain separate)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if userIDKey is not a standard claim (actullay i believe for oauth framework there is no standard claim, compared to OIDC), should we also include it in the claim mapping so user can configure it to match whatever they want from the auth provider?

I think the same case also apply to email and email_verified. Please correct me if there is a doc about standard claims of oauth.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in our case claims are interpreted from the Dex providing OIDC point of view. No, they are not oauth claims, but we map some information from oauth to the OIDC token.

The userIDKey is only used by Dex to determine which field to use as the user identifier for the specific connector. The rest of the keys are "mapped" into an OIDC token as standard claims.

That's how I see it at least, correct me if my thought process is wrong.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have put eveything but userIDKey under ClaimMappings and added an error if user ID is not found since it is critical. EmailKey and EmailVerifiedKey are added so it can handle a response like reddit:

Reddit

https://oauth.reddit.com/api/v1/me
{
    "comment_karma": 0, 
    "created": 1389649907.0, 
    "created_utc": 1389649907.0, 
    "has_mail": false,    
    "has_mod_mail": false, 
    "has_verified_email": null,   <--- emailVerifiedKey
    "id": "1",                               <--- userIDKey
    "is_gold": false, 
    "is_mod": true, 
    "link_karma": 1, 
    "name": "reddit_bot",           <--- preferredUsernameKey
    "over_18": true
}

Comment on lines 175 to 212
if c.userIDKey == "" {
c.userIDKey = "user_id"
}

if c.userNameKey == "" {
c.userNameKey = "user_name"
}

if c.groupsKey == "" {
c.groupsKey = "groups"
}

if c.preferredUsernameKey == "" {
c.preferredUsernameKey = "preferred_username"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these default should probably be assigned in the "constructor", no?

Copy link
Author

@xtremerui xtremerui Oct 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put them here to follow what OIDC does in the handlerCallback(). I have no preference here so if you insiit I can move them to the Open() method where it constructs Oauth connection.

dex/connector/oidc/oidc.go

Lines 282 to 310 in 2a28286

userNameKey := "name"
if c.userNameKey != "" {
userNameKey = c.userNameKey
}
name, found := claims[userNameKey].(string)
if !found {
return identity, fmt.Errorf("missing \"%s\" claim", userNameKey)
}
preferredUsername, found := claims["preferred_username"].(string)
if !found {
preferredUsername, _ = claims[c.preferredUsernameKey].(string)
}
hasEmailScope := false
for _, s := range c.oauth2Config.Scopes {
if s == "email" {
hasEmailScope = true
break
}
}
var email string
emailKey := "email"
email, found = claims[emailKey].(string)
if !found && c.emailKey != "" {
emailKey = c.emailKey
email, found = claims[emailKey].(string)
}

connector/oauth/oauth.go Outdated Show resolved Hide resolved
connector/oauth/oauth_test.go Outdated Show resolved Hide resolved
@sagikazarmark sagikazarmark added this to the v2.26.0 milestone Oct 4, 2020
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch 2 times, most recently from faa49fe to 6d77be2 Compare October 7, 2020 01:09
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch from 6d77be2 to cbd166d Compare October 16, 2020 16:43
@sagikazarmark sagikazarmark modified the milestones: v2.26.0, v2.27.0 Oct 18, 2020
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch from 7d1a86c to af62fc7 Compare October 20, 2020 20:16
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch 3 times, most recently from fdb86ea to 81e80d7 Compare November 5, 2020 04:20
@sagikazarmark sagikazarmark removed this from the v2.27.0 milestone Dec 14, 2020
@sagikazarmark sagikazarmark modified the milestones: v2.29.0, v2.30.0 Jun 28, 2021
@nabokihms nabokihms modified the milestones: v2.30.0, v2.31.0 Aug 2, 2021
@panxunying
Copy link

I have a similar scene, i want to know why this pr isn't merged now?

sagikazarmark and others added 13 commits November 17, 2021 15:06
Signed-off-by: Mark Sagi-Kazar <[email protected]>
Co-authored-by: Shash Reddy <[email protected]>
Signed-off-by: Joshua Winters <[email protected]>
Signed-off-by: Josh Winters <[email protected]>
Co-authored-by: Mark Huang <[email protected]>
Signed-off-by: Rui Yang <[email protected]>
Signed-off-by: Rui Yang <[email protected]>
move default key values configure to connector construct function

Signed-off-by: Rui Yang <[email protected]>
Signed-off-by: Rui Yang <[email protected]>
There are cases when groups are represented as a list
of maps, not strings e.g. "groups":[{"id":"1",
"name":"gr1"},{"id": "2", "name":"gr2"}]. Handle groups
represented as a list of maps.

#23

Signed-off-by: Vlad Safronov <[email protected]>
Signed-off-by: Vlad Safronov <[email protected]>
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch from 53d11be to 7c80e44 Compare November 17, 2021 20:07
us 'os' insteak of 'io/ioutil'

Signed-off-by: Rui Yang <[email protected]>
@xtremerui xtremerui force-pushed the pr/add-oauth-connector-sync branch from 8c61d5e to 8b86516 Compare November 17, 2021 22:59
Copy link
Member

@sagikazarmark sagikazarmark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xtremerui Thanks for the efforts you've put into this. I finally got the time around to give it a proper review. It looks good to me.

I had two small comments. Would you mind taking a look at them? We can finally get this merged after that.

connector/oauth/oauth.go Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
@xtremerui
Copy link
Author

Thx for reviewing. I have updated it accordingly. @sagikazarmark

@sagikazarmark
Copy link
Member

Thanks @xtremerui

@sagikazarmark sagikazarmark merged commit e7c287a into dexidp:master Dec 2, 2021
xtremerui pushed a commit to concourse/dex that referenced this pull request Feb 9, 2022
The official docker release for this release can be pulled from

```
ghcr.io/dexidp/dex:v2.31.0
```

## What's Changed
* Bump Dex image to v2.30.0 for Kubernetes deployment example by @rdimitrov in dexidp#2232
* Update Go to 1.17 by @sagikazarmark in dexidp#2247
* refactor: move from io/ioutil to io and os package by @Juneezee in dexidp#2278
* feat: Add MySQL ent-based storage driver by @nabokihms in dexidp#2272
* chore: fix ioutil lint error after merging MySQL ent storage by @nabokihms in dexidp#2282
* Add parametrization of grant type supported in discovery endpoint by @ariary in dexidp#2265
* Resolves dexidp#2111 Option to fetch transitive group membership by @snuggie12 in dexidp#2268
* Return valid JWT access token from password grant by @enj in dexidp#2234
* fix: do not update offlinesession lastUsed field if refresh token was not updated by @nabokihms in dexidp#2300
* fix web static file path slash error for win platform by @copperyp in dexidp#2305
* Update grpc by @sagikazarmark in dexidp#2321
* ci: fix container image permissions by @sagikazarmark in dexidp#2329
* feat: print dex version in the logs by @iam-veeramalla in dexidp#2337
* OAuth connector by @xtremerui in dexidp#1630
* fix: return invalid_grant error on claiming token of another client by @nabokihms in dexidp#2344
* chore: warning about deprecated LDAP groupSearch fields by @nabokihms in dexidp#2026
* Add Nix environment by @sagikazarmark in dexidp#2324
* Update dependencies in the examples package by @sagikazarmark in dexidp#2372
* add sigstore to ADOPTERS.md by @bobcallaway in dexidp#2374
* Add claimMapping enforcement by @Happy2C0de in dexidp#2233
* ci: run trivy scan on container image by @sagikazarmark in dexidp#2387
* chore: update gomplate by @sagikazarmark in dexidp#2388
* chore: update golangci-lint download script by @nabokihms in dexidp#2394
* [fix] Replace /teams API w/ /workspaces endpoints by @rahulchheda in dexidp#2390
* ci: add Docker cache to speed builds up by @sagikazarmark in dexidp#2400
* distroless: Dockerfile works with distroless base image by @ankeesler in dexidp#2378
* Update dependencies by @sagikazarmark in dexidp#2404
* Update API package by @sagikazarmark in dexidp#2405

## Dependency updates
* build(deps): bump entgo.io/ent from 0.8.0 to 0.9.0 by @dependabot in dexidp#2226
* build(deps): bump golang from 1.16.6-alpine3.13 to 1.16.7-alpine3.13 by @dependabot in dexidp#2225
* build(deps): bump google.golang.org/grpc from 1.39.0 to 1.39.1 by @dependabot in dexidp#2227
* build(deps): bump google.golang.org/api from 0.52.0 to 0.53.0 by @dependabot in dexidp#2235
* build(deps): bump google.golang.org/grpc from 1.39.1 to 1.40.0 by @dependabot in dexidp#2236
* build(deps): bump alpine from 3.14.0 to 3.14.1 by @dependabot in dexidp#2229
* build(deps): bump github.com/go-ldap/ldap/v3 from 3.3.0 to 3.4.0 by @dependabot in dexidp#2239
* build(deps): bump google.golang.org/api from 0.53.0 to 0.54.0 by @dependabot in dexidp#2241
* build(deps): bump github.com/AppsFlyer/go-sundheit from 0.4.0 to 0.5.0 by @dependabot in dexidp#2240
* build(deps): bump google.golang.org/protobuf from 1.26.0 to 1.27.1 in /api/v2 by @dependabot in dexidp#2243
* build(deps): bump google.golang.org/grpc from 1.36.1 to 1.40.0 in /api/v2 by @dependabot in dexidp#2242
* build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.0 to 3.4.1 by @dependabot in dexidp#2246
* build(deps): bump entgo.io/ent from 0.9.0 to 0.9.1 by @dependabot in dexidp#2249
* build(deps): bump alpine from 3.14.1 to 3.14.2 by @dependabot in dexidp#2258
* build(deps): bump google.golang.org/api from 0.54.0 to 0.55.0 by @dependabot in dexidp#2259
* build(deps): bump google.golang.org/api from 0.55.0 to 0.56.0 by @dependabot in dexidp#2262
* build(deps): bump github.com/lib/pq from 1.10.2 to 1.10.3 by @dependabot in dexidp#2263
* build(deps): bump github.com/russellhaering/goxmldsig from 1.1.0 to 1.1.1 by @dependabot in dexidp#2270
* build(deps): bump golang from 1.17.0-alpine3.14 to 1.17.1-alpine3.14 by @dependabot in dexidp#2269
* build(deps): bump google.golang.org/api from 0.56.0 to 0.57.0 by @dependabot in dexidp#2277
* build(deps): bump github.com/coreos/go-oidc/v3 from 3.0.0 to 3.1.0 by @dependabot in dexidp#2279
* build(deps): bump golang from 1.17.1-alpine3.14 to 1.17.2-alpine3.14 by @dependabot in dexidp#2292
* build(deps): bump go.etcd.io/etcd/client/pkg/v3 from 3.5.0 to 3.5.1 by @dependabot in dexidp#2298
* build(deps): bump go.etcd.io/etcd/client/v3 from 3.5.0 to 3.5.1 by @dependabot in dexidp#2299
* build(deps): bump google.golang.org/grpc from 1.40.0 to 1.41.0 by @dependabot in dexidp#2285
* build(deps): bump github.com/mattn/go-sqlite3 from 1.14.8 to 1.14.9 by @dependabot in dexidp#2302
* build(deps): bump google.golang.org/grpc from 1.40.0 to 1.41.0 in /api/v2 by @dependabot in dexidp#2286
* build(deps): bump google.golang.org/api from 0.57.0 to 0.58.0 by @dependabot in dexidp#2287
* build(deps): bump google.golang.org/api from 0.58.0 to 0.59.0 by @dependabot in dexidp#2303
* build(deps): bump google.golang.org/api from 0.59.0 to 0.60.0 by @dependabot in dexidp#2308
* build(deps): bump golang from 1.17.2-alpine3.14 to 1.17.3-alpine3.14 by @dependabot in dexidp#2317
* build(deps): bump github.com/lib/pq from 1.10.3 to 1.10.4 by @dependabot in dexidp#2320
* build(deps): bump alpine from 3.14.2 to 3.14.3 by @dependabot in dexidp#2325
* build(deps): bump alpine from 3.14.3 to 3.15.0 by @dependabot in dexidp#2336
* build(deps): bump google.golang.org/api from 0.60.0 to 0.61.0 by @dependabot in dexidp#2341
* build(deps): bump golang from 1.17.3-alpine3.14 to 1.17.4-alpine3.14 by @dependabot in dexidp#2345
* build(deps): bump google.golang.org/api from 0.61.0 to 0.62.0 by @dependabot in dexidp#2348
* build(deps): bump golang from 1.17.4-alpine3.14 to 1.17.5-alpine3.14 by @dependabot in dexidp#2349
* build(deps): bump github.com/spf13/cobra from 1.2.1 to 1.3.0 by @dependabot in dexidp#2354
* build(deps): bump google.golang.org/api from 0.62.0 to 0.63.0 by @dependabot in dexidp#2353
* build(deps): bump google.golang.org/grpc from 1.42.0 to 1.43.0 by @dependabot in dexidp#2355
* build(deps): bump google.golang.org/grpc from 1.42.0 to 1.43.0 in /api/v2 by @dependabot in dexidp#2356
* build(deps): bump github.com/mattn/go-sqlite3 from 1.14.9 to 1.14.10 by @dependabot in dexidp#2362
* build(deps): bump golang from 1.17.5-alpine3.14 to 1.17.6-alpine3.14 by @dependabot in dexidp#2363
* build(deps): bump google.golang.org/api from 0.63.0 to 0.64.0 by @dependabot in dexidp#2364
* build(deps): bump google.golang.org/api from 0.64.0 to 0.65.0 by @dependabot in dexidp#2368
* build(deps): bump github.com/prometheus/client_golang from 1.11.0 to 1.12.0 by @dependabot in dexidp#2380
* build(deps): bump google.golang.org/grpc from 1.43.0 to 1.44.0 by @dependabot in dexidp#2384
* build(deps): bump google.golang.org/grpc from 1.43.0 to 1.44.0 in /api/v2 by @dependabot in dexidp#2385
* build(deps): bump go.etcd.io/etcd/client/v3 from 3.5.1 to 3.5.2 by @dependabot in dexidp#2395
* build(deps): bump aquasecurity/trivy-action from 0.2.1 to 0.2.2 by @dependabot in dexidp#2398
* build(deps): bump google.golang.org/api from 0.65.0 to 0.67.0 by @dependabot in dexidp#2399
* build(deps): bump github.com/prometheus/client_golang from 1.12.0 to 1.12.1 by @dependabot in dexidp#2393

## New Contributors
* @rdimitrov made their first contribution in dexidp#2232
* @Juneezee made their first contribution in dexidp#2278
* @ariary made their first contribution in dexidp#2265
* @snuggie12 made their first contribution in dexidp#2268
* @enj made their first contribution in dexidp#2234
* @copperyp made their first contribution in dexidp#2305
* @iam-veeramalla made their first contribution in dexidp#2337
* @bobcallaway made their first contribution in dexidp#2374
* @Happy2C0de made their first contribution in dexidp#2233
* @rahulchheda made their first contribution in dexidp#2390
* @ankeesler made their first contribution in dexidp#2378

**Full Changelog**: dexidp/dex@v2.30.0...v2.31.0
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

Successfully merging this pull request may close these issues.

8 participants