Compare commits

...

1608 Commits

Author SHA1 Message Date
Maksim Nabokikh 2081f7d057
Merge pull request #2620 from mayurwaghmode/master
Signed-off-by: mayurwaghmode <waghmodemayur17@gmail.com>
2022-08-15 13:39:07 +04:00
mayurwaghmode b9d88c723f updated gomplate version and added ppc64le support
Signed-off-by: mayurwaghmode <waghmodemayur17@gmail.com>
2022-08-11 02:31:12 -07:00
dependabot[bot] e74acdff6c
build(deps): bump github.com/prometheus/client_golang (#2623)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.12.2 to 1.13.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.12.2...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-11 10:18:39 +03:00
Márk Sági-Kazár b479d26137
Merge pull request #2624 from dexidp/dependabot/docker/alpine-3.16.2
build(deps): bump alpine from 3.16.1 to 3.16.2
2022-08-10 11:45:06 +02:00
dependabot[bot] adb5454913
build(deps): bump alpine from 3.16.1 to 3.16.2
Bumps alpine from 3.16.1 to 3.16.2.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-10 04:04:29 +00:00
dependabot[bot] 4bcdcf8e1e
build(deps): bump aquasecurity/trivy-action from 0.6.0 to 0.6.1 (#2604)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.6.0 to 0.6.1.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.6.0...0.6.1)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-28 15:39:50 +03:00
dependabot[bot] 3df7c489ce
build(deps): bump google.golang.org/api from 0.86.0 to 0.89.0 (#2605)
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.86.0 to 0.89.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.86.0...v0.89.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-28 15:39:14 +03:00
dependabot[bot] ce11154529
build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.2 to 3.4.4 (#2606)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.2 to 3.4.4.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.2...v3.4.4)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-28 15:38:35 +03:00
Bob Callaway e1a407830d
add config to explicitly set scopes for microsoft connector (#2582)
Signed-off-by: Bob Callaway <bcallaway@google.com>
2022-07-27 19:03:29 +03:00
Bob Callaway 83e2df821e
add PKCE support to device code flow (#2575)
Signed-off-by: Bob Callaway <bobcallaway@users.noreply.github.com>
2022-07-27 19:02:18 +03:00
dependabot[bot] 454122ca22
build(deps): bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 (#2599)
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/sirupsen/logrus
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-26 13:52:10 +04:00
Björn Busse 4a0218e87c
grpc-client: Do not crash on empty response (#2584)
Signed-off-by: Björn Busse <bj.rn@baerlin.eu>
2022-07-25 23:30:22 +04:00
Joe Knight 27c25d00be
Add domainHint parameter to Microsoft Connector (#2586)
Signed-off-by: Joe Knight <josephtknight@users.noreply.github.com>
2022-07-25 23:12:55 +04:00
dependabot[bot] 367487d7c5
build(deps): bump golang from 1.18.3-alpine3.15 to 1.18.4-alpine3.15 (#2592)
Bumps golang from 1.18.3-alpine3.15 to 1.18.4-alpine3.15.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-25 23:11:24 +04:00
dependabot[bot] 3b7e56035a
build(deps): bump alpine from 3.16.0 to 3.16.1 (#2598)
Bumps alpine from 3.16.0 to 3.16.1.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-25 23:11:06 +04:00
dependabot[bot] f53fab6b06
build(deps): bump aquasecurity/trivy-action from 0.5.1 to 0.6.0 (#2602)
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.5.1 to 0.6.0.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.5.1...0.6.0)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-25 23:10:46 +04:00
dhaus67 100246328b
Use GitLab's refresh_token during Refresh. (#2352)
Signed-off-by: Daniel Haus <dhaus@redhat.com>
2022-07-20 13:16:12 +04:00
Maksim Nabokikh d564cc7200
Merge pull request #2591 from chancez/patch-1
Add expiry.refreshToken settings to config.yaml.dist
2022-07-18 23:23:16 +04:00
Chance Zibolski a3e2946cfc
Add expiry.refreshToken settings to config.yaml.dist
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
2022-07-13 15:45:21 -07:00
Maksim Nabokikh f49e7bc218
Merge pull request #2560 from dexidp/dependabot/go_modules/github.com/spf13/cobra-1.5.0
build(deps): bump github.com/spf13/cobra from 1.4.0 to 1.5.0
2022-07-04 23:03:15 +04:00
Maksim Nabokikh 9ebcd651ff
Merge pull request #2574 from dexidp/dependabot/go_modules/google.golang.org/api-0.86.0
build(deps): bump google.golang.org/api from 0.82.0 to 0.86.0
2022-07-04 22:27:42 +04:00
dependabot[bot] 1aaa7fa0b7
build(deps): bump github.com/spf13/cobra from 1.4.0 to 1.5.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-04 18:22:22 +00:00
Maksim Nabokikh c561318baa
Merge pull request #2565 from dexidp/dependabot/github_actions/mheap/github-action-required-labels-2
build(deps): bump mheap/github-action-required-labels from 1 to 2
2022-07-04 22:21:19 +04:00
Maksim Nabokikh 5066414735
Merge pull request #2576 from dexidp/dependabot/github_actions/aquasecurity/trivy-action-0.5.1
build(deps): bump aquasecurity/trivy-action from 0.4.0 to 0.5.1
2022-07-04 22:20:59 +04:00
Maksim Nabokikh 731d0d7d9d
Merge pull request #2577 from dexidp/dependabot/go_modules/github.com/stretchr/testify-1.8.0
build(deps): bump github.com/stretchr/testify from 1.7.2 to 1.8.0
2022-07-04 22:20:20 +04:00
Márk Sági-Kazár 1cc26fab2f
Merge pull request #2468 from flant/cwe-79-device-code
fix: prevent cross-site scripting for the device flow
2022-06-30 22:52:33 +03:00
dependabot[bot] f34529b13f
build(deps): bump github.com/stretchr/testify from 1.7.2 to 1.8.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.2 to 1.8.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.2...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 04:09:21 +00:00
dependabot[bot] ffec99287b
build(deps): bump aquasecurity/trivy-action from 0.4.0 to 0.5.1
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.4.0 to 0.5.1.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.4.0...0.5.1)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 04:09:00 +00:00
dependabot[bot] ea46fc39ca
build(deps): bump google.golang.org/api from 0.82.0 to 0.86.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.82.0 to 0.86.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.82.0...v0.86.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-29 04:07:24 +00:00
dependabot[bot] e253fa8efb
build(deps): bump mheap/github-action-required-labels from 1 to 2
Bumps [mheap/github-action-required-labels](https://github.com/mheap/github-action-required-labels) from 1 to 2.
- [Release notes](https://github.com/mheap/github-action-required-labels/releases)
- [Commits](https://github.com/mheap/github-action-required-labels/compare/v1...v2)

---
updated-dependencies:
- dependency-name: mheap/github-action-required-labels
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-22 04:09:16 +00:00
Márk Sági-Kazár c538f3d6a2
Merge pull request #2557 from dexidp/dependabot/github_actions/aquasecurity/trivy-action-0.4.0
build(deps): bump aquasecurity/trivy-action from 0.3.0 to 0.4.0
2022-06-16 18:41:20 +02:00
dependabot[bot] 33483aa179
build(deps): bump aquasecurity/trivy-action from 0.3.0 to 0.4.0
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.3.0 to 0.4.0.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.3.0...0.4.0)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-16 04:06:00 +00:00
Maksim Nabokikh b6c4112c88
Merge pull request #2555 from dexidp/dependabot/github_actions/helm/kind-action-1.3.0
build(deps): bump helm/kind-action from 1.2.0 to 1.3.0
2022-06-15 20:00:30 +04:00
dependabot[bot] 60228d8fd8
build(deps): bump helm/kind-action from 1.2.0 to 1.3.0
Bumps [helm/kind-action](https://github.com/helm/kind-action) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/helm/kind-action/releases)
- [Commits](https://github.com/helm/kind-action/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: helm/kind-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-15 04:05:46 +00:00
Maksim Nabokikh b07c8b1d8d
Merge pull request #2524 from aristanetworks/mkelly-limit-gc-size
Limit the amount of objects we attempt to GC on each cycle
2022-06-10 09:22:00 +04:00
Michael Kelly 9079c31637
Fix formatting
Signed-off-by: Michael Kelly <mkelly@arista.com>
2022-06-09 08:21:13 -07:00
Michael Kelly a51d12056f
Tweaks based on review comments
Signed-off-by: Michael Kelly <mkelly@arista.com>
2022-06-09 08:21:03 -07:00
Michael Kelly 6c99a9b99d
s/getUrl/getURL
golang prefers URL not Url

Signed-off-by: Michael Kelly <mkelly@arista.com>
2022-06-09 08:20:48 -07:00
Mark Sagi-Kazar 3836196af2
chore: update gitignore
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-06-07 13:39:54 +02:00
Márk Sági-Kazár b578e4d8e5
Merge pull request #2551 from dexidp/update-grpc
chore(deps): update grpc
2022-06-07 13:38:13 +02:00
Mark Sagi-Kazar 8360cbfbde
chore(deps): update grpc
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-06-07 12:53:03 +02:00
Márk Sági-Kazár 465be883a3
Merge pull request #2550 from dexidp/dependabot/go_modules/github.com/stretchr/testify-1.7.2
build(deps): bump github.com/stretchr/testify from 1.7.1 to 1.7.2
2022-06-07 12:50:39 +02:00
dependabot[bot] 870395971e
build(deps): bump github.com/stretchr/testify from 1.7.1 to 1.7.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.1 to 1.7.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.1...v1.7.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-07 04:06:47 +00:00
Márk Sági-Kazár ebb27418c4
Merge pull request #2548 from dexidp/dependabot/docker/golang-1.18.3-alpine3.15
build(deps): bump golang from 1.18.2-alpine3.15 to 1.18.3-alpine3.15
2022-06-03 10:25:27 +02:00
dependabot[bot] 15a516684b
Merge pull request #2543 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.47.0 2022-06-02 10:28:35 +00:00
dependabot[bot] dcb25d0c3d
build(deps): bump google.golang.org/grpc from 1.46.2 to 1.47.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.46.2 to 1.47.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.46.2...v1.47.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 09:54:02 +00:00
dependabot[bot] 59b69352e0
Merge pull request #2549 from dexidp/dependabot/go_modules/google.golang.org/api-0.82.0 2022-06-02 09:53:09 +00:00
dependabot[bot] 89d1c51e9b
build(deps): bump google.golang.org/api from 0.81.0 to 0.82.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.81.0 to 0.82.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.81.0...v0.82.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 04:06:00 +00:00
dependabot[bot] a0fd469e47
build(deps): bump golang from 1.18.2-alpine3.15 to 1.18.3-alpine3.15
Bumps golang from 1.18.2-alpine3.15 to 1.18.3-alpine3.15.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-02 04:05:41 +00:00
Maksim Nabokikh b6cc099305
Merge pull request #2290 from bobcallaway/issue2289
correctly handle path escaping for connector IDs
2022-05-31 16:03:12 +04:00
Bob Callaway 6eeba947f1 Merge remote-tracking branch 'upstream/master' into issue2289 2022-05-30 11:52:05 -04:00
Maksim Nabokikh a858ffbcf2
Merge pull request #2538 from loopholelabs/2537-fix-json-response
Device Code Flow does not return application/json in Content-Type header
2022-05-30 17:55:24 +04:00
Shivansh Vij 65592d0b5a
Updating test cases
Fixes https://github.com/dexidp/dex/issues/2537

Signed-off-by: Shivansh Vij <shivanshvij@outlook.com>
2022-05-26 15:54:54 -04:00
Shivansh Vij cbf158bcc0
Fixes https://github.com/dexidp/dex/issues/2537
Signed-off-by: Shivansh Vij <shivanshvij@outlook.com>
2022-05-26 15:49:49 -04:00
Maksim Nabokikh 6da5187b47
Merge pull request #2482 from flant/profiling-endpoint
feat: enable profiling endpoints
2022-05-25 20:55:05 +04:00
Maksim Nabokikh 957def7928
Merge pull request #2533 from flant/notify-groups-access
fix: add notification about groups access to the Grant Access page
2022-05-25 18:20:30 +04:00
Márk Sági-Kazár ec4ac04c41
Merge pull request #2463 from dexidp/release-config
Release note configuration
2022-05-25 16:04:47 +02:00
m.nabokikh bdfb10137a Add the comment about groups request notification
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-25 17:50:12 +04:00
dependabot[bot] e9d17888d8
Merge pull request #2535 from dexidp/dependabot/docker/golang-1.18.2-alpine3.15 2022-05-25 12:13:35 +00:00
Mark Sagi-Kazar b4ccd92d65
chore: release note configuration
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-05-25 13:46:28 +02:00
dependabot[bot] 505726e7d5
build(deps): bump golang from 1.18.0-alpine3.15 to 1.18.2-alpine3.15
Bumps golang from 1.18.0-alpine3.15 to 1.18.2-alpine3.15.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-25 11:40:20 +00:00
Márk Sági-Kazár 70e6cc2205
Merge pull request #2441 from dexidp/go118
feat: upgrade Go to 1.18
2022-05-25 13:39:37 +02:00
dependabot[bot] 3df9cf2cb9
Merge pull request #2452 from dexidp/dependabot/go_modules/api/v2/google.golang.org/protobuf-1.28.0 2022-05-25 09:46:13 +00:00
Mark Sagi-Kazar a02f2e8fac
chore: fix lint violations
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-05-25 11:17:34 +02:00
dependabot[bot] 55d963ac77
build(deps): bump google.golang.org/protobuf in /api/v2
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.27.1...v1.28.0)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-25 09:09:15 +00:00
dependabot[bot] c2f3bea207
Merge pull request #2517 from dexidp/dependabot/go_modules/api/v2/google.golang.org/grpc-1.46.2 2022-05-25 09:08:30 +00:00
Mark Sagi-Kazar 1736f95024
chore: upgrade linter
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-05-25 10:58:20 +02:00
Mark Sagi-Kazar ab02a2d714
feat: upgrade Go to 1.18
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-05-25 10:47:38 +02:00
dependabot[bot] a3dfe30a12
build(deps): bump google.golang.org/grpc in /api/v2
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.44.0 to 1.46.2.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.44.0...v1.46.2)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-25 08:39:38 +00:00
dependabot[bot] 1884705b87
Merge pull request #2534 from dexidp/dependabot/go_modules/google.golang.org/api-0.81.0 2022-05-25 08:39:09 +00:00
dependabot[bot] 8e6d123772
build(deps): bump google.golang.org/api from 0.74.0 to 0.81.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.74.0 to 0.81.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.74.0...v0.81.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-25 04:07:33 +00:00
dependabot[bot] 999d3855c1
Merge pull request #2527 from dexidp/dependabot/go_modules/github.com/felixge/httpsnoop-1.0.3 2022-05-24 12:17:52 +00:00
dependabot[bot] 81818b9afe
build(deps): bump github.com/felixge/httpsnoop from 1.0.2 to 1.0.3
Bumps [github.com/felixge/httpsnoop](https://github.com/felixge/httpsnoop) from 1.0.2 to 1.0.3.
- [Release notes](https://github.com/felixge/httpsnoop/releases)
- [Commits](https://github.com/felixge/httpsnoop/compare/v1.0.2...v1.0.3)

---
updated-dependencies:
- dependency-name: github.com/felixge/httpsnoop
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 11:15:22 +00:00
dependabot[bot] 2baf728d1f
Merge pull request #2529 from dexidp/dependabot/go_modules/github.com/prometheus/client_golang-1.12.2 2022-05-24 11:14:49 +00:00
dependabot[bot] 7071480c2a
Merge pull request #2526 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.46.2 2022-05-24 11:14:37 +00:00
dependabot[bot] 071969f172
Merge pull request #2528 from dexidp/dependabot/go_modules/github.com/coreos/go-oidc/v3-3.2.0 2022-05-24 11:13:43 +00:00
dependabot[bot] f881fb4b2e
build(deps): bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.12.1 to 1.12.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.12.1...v1.12.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 10:13:11 +00:00
dependabot[bot] bbb3bba01a
build(deps): bump github.com/coreos/go-oidc/v3 from 3.1.0 to 3.2.0
Bumps [github.com/coreos/go-oidc/v3](https://github.com/coreos/go-oidc) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/coreos/go-oidc/releases)
- [Commits](https://github.com/coreos/go-oidc/compare/v3.1.0...v3.2.0)

---
updated-dependencies:
- dependency-name: github.com/coreos/go-oidc/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 10:13:11 +00:00
dependabot[bot] 97c7f2491b
build(deps): bump google.golang.org/grpc from 1.45.0 to 1.46.2
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.45.0 to 1.46.2.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.45.0...v1.46.2)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 10:13:10 +00:00
dependabot[bot] 6c5286cbfe
Merge pull request #2491 from dexidp/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.4 2022-05-24 10:12:05 +00:00
dependabot[bot] a3880c7371
build(deps): bump go.etcd.io/etcd/client/v3 from 3.5.2 to 3.5.4
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.2 to 3.5.4.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Changelog](https://github.com/etcd-io/etcd/blob/main/Dockerfile-release.amd64)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.2...v3.5.4)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 09:29:30 +00:00
dependabot[bot] dc0dfa771f
Merge pull request #2531 from dexidp/dependabot/docker/alpine-3.16.0 2022-05-24 09:28:32 +00:00
Márk Sági-Kazár 6759369e16
Merge pull request #2532 from flant/go-mod-compact-1-17
chore: Go mod update 1.17
2022-05-24 11:27:38 +02:00
m.nabokikh a7ca81f03a chore: Go mod update 1.17
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-24 10:10:10 +04:00
dependabot[bot] 51f1ec441d
build(deps): bump alpine from 3.15.4 to 3.16.0
Bumps alpine from 3.15.4 to 3.16.0.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-24 04:07:07 +00:00
dependabot[bot] a4fb0a089f
Merge pull request #2525 from dexidp/dependabot/github_actions/aquasecurity/trivy-action-0.3.0 2022-05-23 18:33:56 +00:00
dependabot[bot] c98646f004
build(deps): bump aquasecurity/trivy-action from 0.2.5 to 0.3.0
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.2.5 to 0.3.0.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.2.5...0.3.0)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-23 04:07:04 +00:00
Maksim Nabokikh 9da59ce5dd
Merge pull request #2523 from flant/increase-lint-timeout
Bump lint timeout to reduce the number of failed executions
2022-05-21 00:04:42 +04:00
Michael Kelly 502a2d0d4a
Limit the amount of objects we attempt to GC on each cycle
If something causes the number k8s resources to increase beyond a
certain threshold, garbage collection can fail because the query to
retrieve those resources will time out, resulting in a perpetual cycle
of being unable to garbage collect resources.

In lieu of trying to get *every* object each cycle, we can limit the
number of resources retrieved per GC cycle to some reasonable number.

Signed-off-by: Michael Kelly <mkelly@arista.com>
2022-05-20 09:18:05 -07:00
dependabot[bot] f09af6102c
Merge pull request #2506 from dexidp/dependabot/github_actions/docker/setup-buildx-action-2 2022-05-20 14:50:39 +00:00
m.nabokikh 3d5a3befb4 fix: prevent cross-site scripting for the device flow
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-20 18:26:49 +04:00
m.nabokikh 97254db62a Bump lint timeout to reduce the number of failed executions
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-20 18:21:40 +04:00
dependabot[bot] 0270536a2e
Merge pull request #2508 from dexidp/dependabot/github_actions/docker/setup-qemu-action-2 2022-05-20 13:55:27 +00:00
dependabot[bot] 861ad968c5
build(deps): bump docker/setup-buildx-action from 1 to 2
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-20 13:52:12 +00:00
dependabot[bot] d26d4e15bc
Merge pull request #2507 from dexidp/dependabot/github_actions/docker/login-action-2 2022-05-20 13:51:31 +00:00
dependabot[bot] 96e0229205
Merge pull request #2509 from dexidp/dependabot/github_actions/docker/metadata-action-4 2022-05-20 13:50:43 +00:00
dependabot[bot] 866f3e0c76
Merge pull request #2510 from dexidp/dependabot/github_actions/docker/build-push-action-3 2022-05-20 13:50:09 +00:00
dependabot[bot] 47411e9a75
build(deps): bump docker/login-action from 1 to 2
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-20 13:15:47 +00:00
dependabot[bot] f26181558c
build(deps): bump docker/setup-qemu-action from 1 to 2
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-20 13:15:37 +00:00
dependabot[bot] 574650abe3
build(deps): bump docker/metadata-action from 3 to 4
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 3 to 4.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-20 13:14:49 +00:00
Maksim Nabokikh 3a83b6ce39
Merge pull request #2486 from flant/enhancement-template
feat: add enhancement template
2022-05-20 17:11:13 +04:00
dependabot[bot] a232af7f28
build(deps): bump docker/build-push-action from 2 to 3
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-20 12:58:44 +00:00
Maksim Nabokikh c74ad3bb66
Merge pull request #2522 from Blorpy/oidc_refresh_token
OIDC connector: Support cases where there is no id_token when using a refresh_token grant
2022-05-20 16:46:41 +04:00
m.nabokikh a98ab893c2 fix: Move enhancements to the docs folder
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-20 16:20:09 +04:00
Maksim Nabokikh 2571ae9096 Apply suggestions from code review
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>

Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-20 16:20:09 +04:00
m.nabokikh 38fe0f5319 feat: add enhancement template
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-20 16:20:09 +04:00
Márk Sági-Kazár 92161abfdc
Merge pull request #2516 from flant/no-cache-build
chore: do not use caching for docker build
2022-05-20 13:03:15 +02:00
Anthony Brandelli 5fe1647fc7 Fix issues to make the linter happy
Signed-off-by: Anthony Brandelli <abrandel@cisco.com>
2022-05-19 22:35:05 -06:00
Anthony Brandelli 7c335e9337 Add support for IDPs that do not send ID tokens in the reply when using a refresh grant. Add tests for the aforementioned functionality.
Signed-off-by: Anthony Brandelli <abrandel@cisco.com>
2022-05-19 22:13:10 -06:00
m.nabokikh 35f58dca73 chore: do not use caching for docker build
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-05-14 17:50:29 +04:00
Maksim Nabokikh 9cd29bdee0
Merge pull request #2511 from Blorpy/remove_hd_oidc
Remove google specific hd / hosted domain claim config from oidc connector
2022-05-13 07:48:14 +04:00
Maksim Nabokikh 997ec94a4a
Merge pull request #2483 from tsl0922/master
Add numeric user ID support for oauth connector
2022-05-11 14:58:58 +04:00
Anthony Brandelli f07a58a7f1 Remove google specific hd / hosted domain claim config
Signed-off-by: Anthony Brandelli <abrandel@cisco.com>
2022-05-06 13:54:19 -06:00
Shuanglei Tao 691f8be785 Fix unparam lint error in oauth_test
Signed-off-by: Shuanglei Tao <tsl0922@gmail.com>
2022-05-05 16:03:53 +08:00
Maksim Nabokikh 453504c450
Merge pull request #2430 from dhaus67/openshift-connector-system-root-cas
Create setting to allow to trust the system root CAs
2022-05-05 11:37:25 +04:00
dependabot[bot] fd15dd2248
Merge pull request #2494 from dexidp/dependabot/github_actions/github/codeql-action-2 2022-04-26 09:38:54 +00:00
dependabot[bot] ebe1c8b14a
build(deps): bump github/codeql-action from 1 to 2
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-26 04:09:06 +00:00
Márk Sági-Kazár 5c70f1227f
Merge pull request #2489 from dexidp/use-docker-meta
ci: use docker metadata for build input
2022-04-22 23:31:36 +02:00
Mark Sagi-Kazar 0b5a9581cd
ci: use docker metadata for build input
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-22 22:16:56 +02:00
Shuanglei Tao 7b75e1e0cc Add numeric user ID support for oauth connector
Signed-off-by: Shuanglei Tao <tsl0922@gmail.com>
2022-04-22 23:18:26 +08:00
Márk Sági-Kazár 6f07a27fad
Merge pull request #2488 from dexidp/docker-meta
Add docker metadata action
2022-04-22 15:32:52 +02:00
Mark Sagi-Kazar 42f8f91ebf
ci: add docker metadata action
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-22 15:00:13 +02:00
Márk Sági-Kazár 27fb1cf3bd
Merge pull request #2487 from dexidp/revert-docker-matrix
Build multi-platform images in a single build job
2022-04-22 14:59:06 +02:00
Mark Sagi-Kazar a9fb4ae7ef
revert: move container scan back to the container build step
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-22 14:21:28 +02:00
Mark Sagi-Kazar b8f2186593
revert: docker matrix build
Apparently matrix builds don't work with the docker action.

Only reference I found about the topic: https://github.com/docker/build-push-action/issues/130

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-22 14:15:04 +02:00
Márk Sági-Kazár ec9a57ee4b
Merge pull request #2480 from dexidp/qemu
Qemu tweaks
2022-04-21 12:02:30 +02:00
Maksim Nabokikh 7c60f79f10
Merge pull request #1789 from techknowlogick/gitea-groups
Feature: groups in Gitea
2022-04-20 10:30:04 +04:00
techknowlogick 1067641e53 Feature: groups in Gitea
Signed-off-by: techknowlogick <techknowlogick@gitea.io>
2022-04-19 16:58:05 -04:00
dependabot[bot] e9a43bf3cd
Merge pull request #2481 from dexidp/dependabot/github_actions/aquasecurity/trivy-action-0.2.5 2022-04-19 09:59:19 +00:00
dependabot[bot] 75d198bd85
build(deps): bump aquasecurity/trivy-action from 0.2.4 to 0.2.5
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.2.4 to 0.2.5.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.2.4...0.2.5)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-19 04:08:41 +00:00
Mark Sagi-Kazar c5c88a688b
ci: only enable the necessary platforms for emulation
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-15 17:45:14 +02:00
Maksim Nabokikh b26e639515
Merge pull request #2470 from flant/refresh-token-log-only-errors
fix: log only errors on refreshing
2022-04-15 17:20:02 +04:00
m.nabokikh ad89e01676 fix: log only errors on refreshing
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-04-15 10:54:43 +04:00
Márk Sági-Kazár c8ff7ed40a
Merge pull request #2478 from dexidp/distroless
Publish official distroless images
2022-04-15 08:48:42 +02:00
Mark Sagi-Kazar 3702525c86
ci: disable Docker job on push
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-14 16:08:39 +02:00
Mark Sagi-Kazar 8b2ce6252d
ci: build distroless images
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-14 16:07:00 +02:00
Mark Sagi-Kazar 6038af5044
build: help dependabot detect base image versions
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-14 15:18:28 +02:00
Mark Sagi-Kazar 95e81a925f
ci: update trivy scan job
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-14 15:08:26 +02:00
Márk Sági-Kazár 4a5f2dbb4d
Merge pull request #2474 from dexidp/artifact-build
New docker image build
2022-04-14 13:38:27 +02:00
Mark Sagi-Kazar aa35fa6580
ci: wait for container images with container scan
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-14 12:50:12 +02:00
Mark Sagi-Kazar 0f5481a00a
ci: new docker image build
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-14 01:44:13 +02:00
Márk Sági-Kazár 783a7621e0
Merge pull request #2471 from MattiasGees/bump-alpine
Bump Alpine to latest version
2022-04-14 01:05:55 +02:00
Mattias Gees 169b5a59cc Bump Alpine to latest version
Signed-off-by: Mattias Gees <mattias.gees@gmail.com>
2022-04-13 14:31:46 +01:00
Daniel Haus 4088d4f897
Remove external setting, enable injection of HTTP client to config.
Signed-off-by: Daniel Haus <dhaus@redhat.com>
2022-04-12 17:38:59 +02:00
Daniel Haus 2b262ff5d6
Create setting to allow to trust the system root CAs
Previously, when rootCA was set, the trusted system root CAs were ignored. Now, allow for both being able to be configured and used

Signed-off-by: Daniel Haus <dhaus@redhat.com>
2022-04-12 17:38:58 +02:00
m.nabokikh 6822ad950f feat: enable profiling endpoints
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-04-12 12:12:37 +04:00
Márk Sági-Kazár a2089dd8e7
Merge pull request #2467 from dexidp/dependabot/github_actions/actions/setup-go-3
build(deps): bump actions/setup-go from 2 to 3
2022-04-11 12:14:48 +02:00
Márk Sági-Kazár fdc43a0c36
Merge pull request #2466 from dexidp/dependabot/github_actions/aquasecurity/trivy-action-0.2.3
build(deps): bump aquasecurity/trivy-action from 0.2.2 to 0.2.3
2022-04-11 12:14:36 +02:00
dependabot[bot] d8289d3429
build(deps): bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-11 04:07:31 +00:00
dependabot[bot] 23de36d721
build(deps): bump aquasecurity/trivy-action from 0.2.2 to 0.2.3
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.2.2 to 0.2.3.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.2.2...0.2.3)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-11 04:07:31 +00:00
Márk Sági-Kazár a51ed2c4db
Merge pull request #2428 from dexidp/update-ent
Update ent
2022-04-07 17:26:43 +02:00
Mark Sagi-Kazar 9b1a8409f1
revert: atlas and precision change
Looks like Atlas (the new migration library under Ent) cannot
handle precision properly.

An issue has been reported to Ent: https://github.com/ent/ent/issues/2454

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-06 16:27:33 +02:00
Mark Sagi-Kazar b51e73bc2e
fix: define milisecond precision for postgres
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-06 16:27:33 +02:00
Mark Sagi-Kazar 0c3c577b52
feat: use the new atlas engine for migrations
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-06 16:27:32 +02:00
Mark Sagi-Kazar 20b03b3f6d
feat: update generated storage files
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-06 16:27:32 +02:00
Mark Sagi-Kazar 07a43f2d66
feat: update entgo library
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-04-06 16:27:31 +02:00
dependabot[bot] 493c0eb8b7
Merge pull request #2451 from dexidp/dependabot/go_modules/google.golang.org/protobuf-1.28.0 2022-04-06 11:11:23 +00:00
Márk Sági-Kazár 50dc2f5518
Merge pull request #2433 from flant/implicit_flow_discovery
fix: Implicit Grant discovery
2022-04-06 12:42:43 +02:00
dependabot[bot] ff68ca1aae
build(deps): bump google.golang.org/protobuf from 1.27.1 to 1.28.0
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.27.1...v1.28.0)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-06 10:33:34 +00:00
dependabot[bot] cf78e741ca
Merge pull request #2458 from dexidp/dependabot/go_modules/google.golang.org/api-0.74.0 2022-04-06 10:32:54 +00:00
dependabot[bot] e462d69353
Merge pull request #2461 from dexidp/dependabot/docker/alpine-3.15.4 2022-04-06 10:31:58 +00:00
dependabot[bot] b163944ee5
build(deps): bump alpine from 3.15.3 to 3.15.4
Bumps alpine from 3.15.3 to 3.15.4.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-05 04:06:34 +00:00
dependabot[bot] a136c0141e
build(deps): bump google.golang.org/api from 0.70.0 to 0.74.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.70.0 to 0.74.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.70.0...v0.74.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-31 04:07:36 +00:00
dependabot[bot] 2ebcd70d30
Merge pull request #2456 from dexidp/dependabot/docker/alpine-3.15.3 2022-03-29 08:13:35 +00:00
dependabot[bot] 6692759586
build(deps): bump alpine from 3.15.1 to 3.15.3
Bumps alpine from 3.15.1 to 3.15.3.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-29 04:08:06 +00:00
Márk Sági-Kazár 897ae8d2a3
Merge pull request #2446 from dexidp/update-base-image
Update alpine version
2022-03-22 14:09:20 +01:00
Mark Sagi-Kazar 863416f0a3
chore: update alpine version
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-03-22 13:10:17 +01:00
Márk Sági-Kazár 090593b7f9
Merge pull request #2444 from dexidp/dependabot/docker/alpine-3.15.1
build(deps): bump alpine from 3.15.0 to 3.15.1
2022-03-22 13:08:47 +01:00
dependabot[bot] df1cb1cdbf
build(deps): bump alpine from 3.15.0 to 3.15.1
Bumps alpine from 3.15.0 to 3.15.1.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-18 04:07:09 +00:00
dependabot[bot] 20e2e429b3
Merge pull request #2440 from dexidp/dependabot/go_modules/github.com/stretchr/testify-1.7.1 2022-03-16 12:27:51 +00:00
dependabot[bot] c98636457b
build(deps): bump github.com/stretchr/testify from 1.7.0 to 1.7.1
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.0 to 1.7.1.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.0...v1.7.1)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-16 04:08:06 +00:00
dependabot[bot] f1cc7133da
Merge pull request #2437 from dexidp/dependabot/go_modules/github.com/spf13/cobra-1.4.0 2022-03-12 10:48:01 +00:00
dependabot[bot] 111ce66bd0
build(deps): bump github.com/spf13/cobra from 1.3.0 to 1.4.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.3.0...v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-11 04:06:24 +00:00
m.nabokikh 57e9611ff6 fix: Implicit Grant discovery
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-03-08 16:16:25 +04:00
Maksim Nabokikh cb9f0b5d5e
Merge pull request #2418 from dirien/acr_values
feat: Add acr_values support for OIDC
2022-03-08 10:22:07 +04:00
dependabot[bot] a322f42a10
Merge pull request #2426 from dexidp/dependabot/docker/golang-1.17.8-alpine3.14 2022-03-07 11:10:18 +00:00
dependabot[bot] 22a7d3acd3
build(deps): bump golang from 1.17.7-alpine3.14 to 1.17.8-alpine3.14
Bumps golang from 1.17.7-alpine3.14 to 1.17.8-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 04:07:46 +00:00
Engin Diri 5d9d68106a
feat: Add acr_values support for OIDC
Signed-off-by: Engin Diri <engin.diri@mail.schwarz>
2022-03-05 09:25:27 +01:00
dependabot[bot] b83ba01c40
Merge pull request #2424 from dexidp/dependabot/go_modules/github.com/russellhaering/goxmldsig-1.2.0 2022-03-04 09:34:54 +00:00
Maksim Nabokikh 5f9abc5be8
Merge pull request #2371 from seuf/authproxy-groups-configuration
Allow configuration of returned groups via authproxy connector
2022-03-04 00:44:56 +04:00
dependabot[bot] 98ed9b70a4
build(deps): bump github.com/russellhaering/goxmldsig
Bumps [github.com/russellhaering/goxmldsig](https://github.com/russellhaering/goxmldsig) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/russellhaering/goxmldsig/releases)
- [Commits](https://github.com/russellhaering/goxmldsig/compare/v1.1.1...v1.2.0)

---
updated-dependencies:
- dependency-name: github.com/russellhaering/goxmldsig
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-03 04:06:30 +00:00
dependabot[bot] a190bba9e6
Merge pull request #2422 from dexidp/dependabot/github_actions/actions/checkout-3 2022-03-02 10:06:49 +00:00
Maksim Nabokikh 5b0cb0704a
Merge pull request #2342 from dhaus67/refresh-token-openshift-connector
Add support for RefreshConnector for openshift connector.
2022-03-02 11:46:21 +04:00
dependabot[bot] 616e20b334
build(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-02 04:08:38 +00:00
dependabot[bot] fd545e0493
Merge pull request #2419 from dexidp/dependabot/go_modules/google.golang.org/api-0.70.0 2022-02-23 13:13:17 +00:00
dependabot[bot] 575d935792
build(deps): bump google.golang.org/api from 0.69.0 to 0.70.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.69.0 to 0.70.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.69.0...v0.70.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-23 04:06:19 +00:00
dependabot[bot] e22c24dba2
Merge pull request #2416 from dexidp/dependabot/go_modules/github.com/go-ldap/ldap/v3-3.4.2 2022-02-16 06:24:16 +00:00
dependabot[bot] 333b1d1971
Merge pull request #2415 from dexidp/dependabot/go_modules/google.golang.org/api-0.69.0 2022-02-16 06:23:51 +00:00
dependabot[bot] d9535b8dc1
build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.1 to 3.4.2
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.1 to 3.4.2.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.1...v3.4.2)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-16 04:07:38 +00:00
dependabot[bot] 364f7954fd
build(deps): bump google.golang.org/api from 0.68.0 to 0.69.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.68.0 to 0.69.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.68.0...v0.69.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-16 04:07:22 +00:00
Márk Sági-Kazár dde621980d
Merge pull request #2411 from dexidp/dependabot/docker/golang-1.17.7-alpine3.14
build(deps): bump golang from 1.17.6-alpine3.14 to 1.17.7-alpine3.14
2022-02-11 10:32:56 +01:00
dependabot[bot] 2e2471b21f
build(deps): bump golang from 1.17.6-alpine3.14 to 1.17.7-alpine3.14
Bumps golang from 1.17.6-alpine3.14 to 1.17.7-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-11 04:06:53 +00:00
Mark Sagi-Kazar 102762062b
build: only build static release binaries
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-02-08 23:55:31 +01:00
Márk Sági-Kazár 5f58d8e7d2
Merge pull request #2405 from dexidp/update-dependencies
Update API package
2022-02-08 23:36:15 +01:00
Mark Sagi-Kazar b97732f353
chore(deps): update API package
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-02-08 23:19:29 +01:00
Márk Sági-Kazár f8685d2e83
Merge pull request #2404 from dexidp/update-dependencies
Update dependencies
2022-02-08 23:11:59 +01:00
Mark Sagi-Kazar 592a9f603f
chore(deps): update dependencies
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-02-08 22:41:52 +01:00
Mark Sagi-Kazar 727b0101f7
chore(deps): update dependencies
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-02-08 22:34:59 +01:00
Márk Sági-Kazár 75c27c8dba
Merge pull request #2378 from ankeesler/akeesler/distroless
distroless: Dockerfile works with distroless base image
2022-02-08 21:56:25 +01:00
Márk Sági-Kazár 470327e002
Merge pull request #2400 from dexidp/docker-cache
ci: add Docker cache to speed builds up
2022-02-07 10:31:13 +01:00
Mark Sagi-Kazar 8cee3927b4
ci: add Docker cache to speed builds up
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-02-04 13:45:08 +01:00
dependabot[bot] 238c07ac33
Merge pull request #2393 from dexidp/dependabot/go_modules/github.com/prometheus/client_golang-1.12.1 2022-02-04 11:22:08 +00:00
dependabot[bot] bf034906fd
Merge pull request #2399 from dexidp/dependabot/go_modules/google.golang.org/api-0.67.0 2022-02-04 11:21:38 +00:00
dependabot[bot] d03d229ddc
build(deps): bump google.golang.org/api from 0.65.0 to 0.67.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.65.0 to 0.67.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.65.0...v0.67.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-04 04:06:42 +00:00
dependabot[bot] f8fcae5f07
Merge pull request #2398 from dexidp/dependabot/github_actions/aquasecurity/trivy-action-0.2.2 2022-02-03 11:14:57 +00:00
dependabot[bot] 71d95d7aa2
build(deps): bump aquasecurity/trivy-action from 0.2.1 to 0.2.2
Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.2.1 to 0.2.2.
- [Release notes](https://github.com/aquasecurity/trivy-action/releases)
- [Commits](https://github.com/aquasecurity/trivy-action/compare/0.2.1...0.2.2)

---
updated-dependencies:
- dependency-name: aquasecurity/trivy-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-03 04:04:05 +00:00
dependabot[bot] 6275eba9ce
Merge pull request #2395 from dexidp/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.2 2022-02-02 15:19:15 +00:00
Maksim Nabokikh bf0025fbd3
Merge pull request #2390 from rahulchheda/fix/bitbucket-teams-issue-master
[fix] Replace /teams API w/ /workspaces endpoints
2022-02-02 12:09:11 +04:00
dependabot[bot] 2eedc5897c
build(deps): bump go.etcd.io/etcd/client/v3 from 3.5.1 to 3.5.2
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Changelog](https://github.com/etcd-io/etcd/blob/main/Dockerfile-release.amd64)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.1...v3.5.2)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-02 04:06:14 +00:00
Maksim Nabokikh 13f93cb785
Merge pull request #2394 from flant/update-goglangci-lint-link
chore: update golangci-lint download script
2022-02-01 08:18:30 +04:00
m.nabokikh 254165d665 chore: update golangci-lint download script
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2022-01-31 22:33:38 +04:00
seuf 4ee9658dfe [authproxy] Allow configuration of returned groups
Via HTTP Header if present and with manually configured staticGroups in authproxy connector

Signed-off-by: seuf <seuf76@gmail.com>
2022-01-31 10:36:54 +01:00
dependabot[bot] 0f89054634
build(deps): bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.12.0 to 1.12.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.12.0...v1.12.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-31 04:07:24 +00:00
Márk Sági-Kazár 8519219dae
Merge pull request #2388 from dexidp/update-gomplate
chore: update gomplate
2022-01-27 10:09:34 +01:00
Rahul M Chheda 2bc4ad6b56 [fix] Replace /teams API w/ /workspaces endpoints
Signed-off-by: Rahul M Chheda <rahul.chheda@accurics.com>
2022-01-27 14:08:48 +05:30
Mark Sagi-Kazar cd44a3e4f3
chore: update gomplate
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-01-26 22:44:02 +01:00
Márk Sági-Kazár 49e15945a2
Merge pull request #2387 from dexidp/trivy-scan
ci: run trivy scan on container image
2022-01-26 16:37:21 +01:00
Mark Sagi-Kazar 12a904afdd
ci: run trivy scan on container image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-01-26 16:09:43 +01:00
dependabot[bot] 373bddaf73
Merge pull request #2385 from dexidp/dependabot/go_modules/api/v2/google.golang.org/grpc-1.44.0 2022-01-26 13:59:07 +00:00
dependabot[bot] 593d03789d
build(deps): bump google.golang.org/grpc in /api/v2
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.43.0 to 1.44.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.43.0...v1.44.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-26 13:29:59 +00:00
dependabot[bot] deac802c73
Merge pull request #2384 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.44.0 2022-01-26 13:29:18 +00:00
dependabot[bot] b434058f19
build(deps): bump google.golang.org/grpc from 1.43.0 to 1.44.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.43.0 to 1.44.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.43.0...v1.44.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-26 04:05:04 +00:00
dependabot[bot] c205b49189
Merge pull request #2380 from dexidp/dependabot/go_modules/github.com/prometheus/client_golang-1.12.0 2022-01-20 09:06:07 +00:00
dependabot[bot] 22d27c60e4
build(deps): bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.11.0 to 1.12.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.11.0...v1.12.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-20 04:06:35 +00:00
Márk Sági-Kazár 73ce1eb110
Merge pull request #2233 from Happy2C0de/add-claimMapping-enforcement
Add claimMapping enforcement
2022-01-19 15:30:29 +01:00
Happy2C0de 419db81c67 Remove overrideWithMissingCustomEmailClaim
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Happy2C0de 55605751f5 Add overrideWithMissingCustomEmailClaim test
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Happy2C0de b28098dde8 Revert querying preferrredUsernameKey
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Happy2C0de 1608b473eb Remove false failed errors.
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Happy2C0de 2b6bb1997c Revert ClaimMapping struct
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Happy2C0de 14a0aecc81 Move claimMapping.enforce to overrideClaimMapping
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Happy2C0de 45143c98b3 Add claimMapping enforcement
Signed-off-by: Happy2C0de <46957159+Happy2C0de@users.noreply.github.com>
2022-01-19 13:38:09 +01:00
Andrew Keesler 0394bf8cea
distroless: Dockerfile works with distroless base image
I can build this via:
  docker build --build-arg BASEIMAGE=gcr.io/distroless/static:latest -t andrew:distroless .

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
2022-01-18 19:40:28 -05:00
Andrew Keesler a672ff9288
distroless: fetch CA certificates in builder stage
...so that we don't rely on a package manager to bring these down into the
runner stage.

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
2022-01-18 19:18:43 -05:00
Andrew Keesler 764ce711b6
distroless: rewrite docker-entrypoint.sh in go
See go doc ./cmd/docker-entrypoint for why.

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
2022-01-18 19:18:43 -05:00
Márk Sági-Kazár ba1bd65c10
Merge pull request #2374 from bobcallaway/patch-1
add sigstore to ADOPTERS.md
2022-01-16 16:19:01 +01:00
Bob Callaway 3e0f7c42b8 add sigstore to ADOPTERS.md
@sagikazarmark FYI

Signed-off-by: Bob Callaway <bob.callaway@gmail.com>
2022-01-16 08:43:33 -05:00
Márk Sági-Kazár f44af5c8e9
Merge pull request #2372 from dexidp/update-examples
Update dependencies in the examples package
2022-01-16 10:31:40 +01:00
Mark Sagi-Kazar eb26422bdc
chore(examples): update dependencies
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2022-01-15 11:10:51 +01:00
dependabot[bot] 716eef83bc
Merge pull request #2368 from dexidp/dependabot/go_modules/google.golang.org/api-0.65.0 2022-01-12 18:20:22 +00:00
dependabot[bot] e8d8967a5b
build(deps): bump google.golang.org/api from 0.64.0 to 0.65.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.64.0 to 0.65.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.64.0...v0.65.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-12 04:07:04 +00:00
dependabot[bot] adaa31c0a5
Merge pull request #2364 from dexidp/dependabot/go_modules/google.golang.org/api-0.64.0 2022-01-07 07:43:31 +00:00
dependabot[bot] 97abc800fb
Merge pull request #2363 from dexidp/dependabot/docker/golang-1.17.6-alpine3.14 2022-01-07 07:42:51 +00:00
dependabot[bot] cb916cdf43
build(deps): bump google.golang.org/api from 0.63.0 to 0.64.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.63.0 to 0.64.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.63.0...v0.64.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-07 04:16:52 +00:00
dependabot[bot] 84802f247f
build(deps): bump golang from 1.17.5-alpine3.14 to 1.17.6-alpine3.14
Bumps golang from 1.17.5-alpine3.14 to 1.17.6-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-07 04:06:48 +00:00
dependabot[bot] 3bc6a45ee1
Merge pull request #2362 from dexidp/dependabot/go_modules/github.com/mattn/go-sqlite3-1.14.10 2021-12-30 18:24:43 +00:00
Márk Sági-Kazár d112627564
ci: remove unnecessary permissions from docker workflow 2021-12-30 18:12:08 +01:00
dependabot[bot] 7f17aae35d
build(deps): bump github.com/mattn/go-sqlite3 from 1.14.9 to 1.14.10
Bumps [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) from 1.14.9 to 1.14.10.
- [Release notes](https://github.com/mattn/go-sqlite3/releases)
- [Commits](https://github.com/mattn/go-sqlite3/compare/v1.14.9...v1.14.10)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-sqlite3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-30 04:23:10 +00:00
Márk Sági-Kazár c8d55ce016
Merge pull request #2324 from dexidp/nix
Add Nix environment
2021-12-24 16:43:09 +01:00
dependabot[bot] 39ddadcd8e
Merge pull request #2356 from dexidp/dependabot/go_modules/api/v2/google.golang.org/grpc-1.43.0 2021-12-19 15:58:23 +00:00
dependabot[bot] 74dc922703
build(deps): bump google.golang.org/grpc in /api/v2
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.42.0 to 1.43.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.42.0...v1.43.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-19 16:10:14 +01:00
dependabot[bot] 25f5b47272
Merge pull request #2355 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.43.0 2021-12-19 15:09:38 +00:00
Mark Sagi-Kazar 79721196a8
fix(server): wrap credentials in the correct Dial option
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-12-19 15:41:15 +01:00
Stephen Augustus 243661155e
server: grpc.WithInsecure is now insecure.NewCredentials()
Signed-off-by: Stephen Augustus <foo@auggie.dev>
2021-12-17 19:39:03 -05:00
dependabot[bot] 3fa53bbc3d
build(deps): bump google.golang.org/grpc from 1.42.0 to 1.43.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.42.0 to 1.43.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.42.0...v1.43.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-18 00:14:40 +00:00
dependabot[bot] a407b5861b
Merge pull request #2353 from dexidp/dependabot/go_modules/google.golang.org/api-0.63.0 2021-12-18 00:05:47 +00:00
dependabot[bot] 93b32c3500
build(deps): bump google.golang.org/api from 0.62.0 to 0.63.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.62.0 to 0.63.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.62.0...v0.63.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-15 17:07:43 +00:00
dependabot[bot] 4a42e80a7a
Merge pull request #2354 from dexidp/dependabot/go_modules/github.com/spf13/cobra-1.3.0 2021-12-15 16:58:11 +00:00
dependabot[bot] a941593b8b
build(deps): bump github.com/spf13/cobra from 1.2.1 to 1.3.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-15 04:18:04 +00:00
Maksim Nabokikh 9d3471e39b
Merge pull request #2026 from flant/ldap-groups-user-matcher-warning
chore: warning about deprecated LDAP groupSearch fields
2021-12-11 13:26:30 +04:00
dependabot[bot] 79233f41ef
Merge pull request #2349 from dexidp/dependabot/docker/golang-1.17.5-alpine3.14 2021-12-11 01:15:16 +00:00
dependabot[bot] a413d9b383
build(deps): bump golang from 1.17.4-alpine3.14 to 1.17.5-alpine3.14
Bumps golang from 1.17.4-alpine3.14 to 1.17.5-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-10 04:07:09 +00:00
dependabot[bot] b14b0fd127
Merge pull request #2348 from dexidp/dependabot/go_modules/google.golang.org/api-0.62.0 2021-12-09 14:16:36 +00:00
dependabot[bot] ae1b50c26b
build(deps): bump google.golang.org/api from 0.61.0 to 0.62.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.61.0 to 0.62.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.61.0...v0.62.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-09 04:15:53 +00:00
Maksim Nabokikh ac02fb04cf
Merge pull request #2344 from flant/invalid_grant_claim_another_client
fix: return invalid_grant error on claiming token of another client
2021-12-08 17:30:52 +04:00
Maksim Nabokikh ca615f7ad7 Update server/refreshhandlers.go
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-12-08 09:13:24 +04:00
Márk Sági-Kazár 7ebc76b79e
Merge pull request #2345 from dexidp/dependabot/docker/golang-1.17.4-alpine3.14
build(deps): bump golang from 1.17.3-alpine3.14 to 1.17.4-alpine3.14
2021-12-08 03:39:30 +01:00
Daniel Haus 6256b863b0
Fix linting issues.
Signed-off-by: Daniel Haus <dhaus@redhat.com>
2021-12-06 13:28:25 +01:00
dependabot[bot] 131bf83699
build(deps): bump golang from 1.17.3-alpine3.14 to 1.17.4-alpine3.14
Bumps golang from 1.17.3-alpine3.14 to 1.17.4-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-06 04:05:51 +00:00
m.nabokikh 578cb05f7b fix: return invalid_grant error on claiming token of another client
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-12-05 23:45:52 +04:00
Daniel Haus 6d55fe1c80
Add support for refresh tokens for openshift connector.
Signed-off-by: Daniel Haus <dhaus@redhat.com>
2021-12-03 16:38:56 +01:00
dependabot[bot] 40e21f14ca
Merge pull request #2341 from dexidp/dependabot/go_modules/google.golang.org/api-0.61.0 2021-12-03 09:58:46 +00:00
dependabot[bot] 1f30080e6a
build(deps): bump google.golang.org/api from 0.60.0 to 0.61.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.60.0 to 0.61.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.60.0...v0.61.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-03 04:16:54 +00:00
Márk Sági-Kazár e7c287a00d
Merge pull request #1630 from concourse/pr/add-oauth-connector-sync
OAuth connector
2021-12-02 02:17:44 +01:00
Rui Yang 539e08ba50 small refactors and cleanup
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-12-01 12:45:25 -05:00
Márk Sági-Kazár e00e75b773
Merge pull request #2337 from iam-veeramalla/printversion
feat: print dex version in the logs
2021-11-25 16:01:16 +01:00
iam-veeramalla 528ef18c2f feat: print dex version in the logs
Signed-off-by: iam-veeramalla <abhishek.veeramalla@gmail.com>
2021-11-25 17:58:09 +05:30
dependabot[bot] f70015dfed
Merge pull request #2336 from dexidp/dependabot/docker/alpine-3.15.0 2021-11-25 08:50:42 +00:00
dependabot[bot] f717c71d66
build(deps): bump alpine from 3.14.3 to 3.15.0
Bumps alpine from 3.14.3 to 3.15.0.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-25 04:05:42 +00:00
Rui Yang 8b865169bd fix minor compilation error for group claim
us 'os' insteak of 'io/ioutil'

Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 17:58:34 -05:00
Vlad Safronov 7c80e44caf Add a test case
Signed-off-by: Vlad Safronov <vladislav.safronov@oracle.com>
2021-11-17 15:06:54 -05:00
Vlad Safronov 45932bd38a skymarshal: behaviour: Handle groups as maps
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.

concourse/dex#23

Signed-off-by: Vlad Safronov <vladislav.safronov@oracle.com>
2021-11-17 15:06:54 -05:00
Rui Yang f980d3e0a7 cleanup and optimization
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang 8ea121b45a move oauth connector doc to dex website repo
move default key values configure to connector construct function

Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang 49cb30af26 readme minor fix for oauth connector
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang 02860da8b6 use claim mappings when retrieving user identity
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang 60b8875780 use testify in oauth tests
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang 9952851cc4 add configurable preferred_username key
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang fdf19e8014 add docs for oauth connector
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-11-17 15:06:54 -05:00
Rui Yang 930b331a5b use PreferredUsername
Signed-off-by: Rui Yang <ryang@pivotal.io>
2021-11-17 15:06:53 -05:00
Josh Winters a087c05ebf Make oauth user name and user id configurable
Signed-off-by: Josh Winters <jwinters@pivotal.io>
Co-authored-by: Mark Huang <mhuang@pivotal.io>
2021-11-17 15:06:53 -05:00
Joshua Winters 9284ffb8c0 Add generic oauth connector
Co-authored-by: Shash Reddy <sreddy@pivotal.io>
Signed-off-by: Joshua Winters <jwinters@pivotal.io>
2021-11-17 15:06:53 -05:00
Mark Sagi-Kazar 1cb4b32fcb chore: upgrade alpine
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-17 15:06:45 -05:00
Márk Sági-Kazár 98e7d7a99d
Merge pull request #2329 from dexidp/fix-ci-permissions
ci: fix container image permissions
2021-11-15 19:07:46 +01:00
Mark Sagi-Kazar bc9322ff44
ci: fix container image permissions
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-15 17:23:38 +01:00
dependabot[bot] d3c4a170e3
Merge pull request #2325 from dexidp/dependabot/docker/alpine-3.14.3 2021-11-15 13:00:26 +00:00
dependabot[bot] 0aad109b6f
build(deps): bump alpine from 3.14.2 to 3.14.3
Bumps alpine from 3.14.2 to 3.14.3.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 04:05:23 +00:00
Mark Sagi-Kazar e875745ee0
chore: add kind to the tooling
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 14:46:33 +01:00
Mark Sagi-Kazar 49f9853a89
docs: add license section to the readme
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 14:11:38 +01:00
Mark Sagi-Kazar 1ecc17292b
docs: add a development section to the readme
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 14:11:38 +01:00
Mark Sagi-Kazar f45fe6d0c1
refactor: tool dependency download
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 14:11:38 +01:00
Mark Sagi-Kazar 054e397177
refactor: remove unused proto scripts
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 14:11:38 +01:00
Mark Sagi-Kazar ee76923443
chore: add direnv
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 13:25:04 +01:00
Mark Sagi-Kazar 1bfb1ab757
build: add nix flake
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-14 13:24:28 +01:00
Stephen Augustus (he/him) f92fc54b7a
Merge pull request #2321 from dexidp/update-grpc
Update grpc
2021-11-11 16:47:12 -05:00
Márk Sági-Kazár 21a8ac6d3c
Merge pull request #2305 from copperlib/master
fix web static file path slash error for win platform
2021-11-09 12:03:42 +01:00
Mark Sagi-Kazar 12a2c2b104
chore(deps): update grpc
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-09 11:55:21 +01:00
dependabot[bot] a86beb8952
Merge pull request #2320 from dexidp/dependabot/go_modules/github.com/lib/pq-1.10.4 2021-11-09 10:53:13 +00:00
dependabot[bot] d6cf1704ea
build(deps): bump github.com/lib/pq from 1.10.3 to 1.10.4
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.3 to 1.10.4.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.3...v1.10.4)

---
updated-dependencies:
- dependency-name: github.com/lib/pq
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-09 04:15:36 +00:00
dependabot[bot] 14fe699dcf
Merge pull request #2317 from dexidp/dependabot/docker/golang-1.17.3-alpine3.14 2021-11-05 19:38:19 +00:00
dependabot[bot] d2eec79e48
build(deps): bump golang from 1.17.2-alpine3.14 to 1.17.3-alpine3.14
Bumps golang from 1.17.2-alpine3.14 to 1.17.3-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-05 04:07:19 +00:00
Mark Sagi-Kazar 588910468a
chore: improve github files
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-11-01 14:12:13 +01:00
dependabot[bot] aebe808162
Merge pull request #2308 from dexidp/dependabot/go_modules/google.golang.org/api-0.60.0 2021-10-29 09:47:46 +00:00
dependabot[bot] 71d5c3415f
build(deps): bump google.golang.org/api from 0.59.0 to 0.60.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.59.0 to 0.60.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.59.0...v0.60.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-29 04:22:13 +00:00
copperyp 5854dd192d using path.Join replace filepath.Join
Signed-off-by: copperyp <copperyp@gmail.com>
2021-10-27 14:44:26 +08:00
copperyp a1c1076137 fix web static file path slash error for win platform
Signed-off-by: copperyp <copperyp@gmail.com>
2021-10-23 12:13:55 +08:00
Maksim Nabokikh 84b241721e
Merge pull request #2300 from flant/do-not-update-offline-session-last-time
fix: do not update offlinesession lastUsed field if refresh token was not updated
2021-10-21 20:23:45 +04:00
Márk Sági-Kazár 18311aa44d
Merge pull request #2234 from enj/enj/i/password_grant_access_token
Return valid JWT access token from password grant
2021-10-21 17:42:33 +02:00
dependabot[bot] 30bfb924c2
Merge pull request #2303 from dexidp/dependabot/go_modules/google.golang.org/api-0.59.0 2021-10-21 08:20:22 +00:00
dependabot[bot] 58cac422f5
build(deps): bump google.golang.org/api from 0.58.0 to 0.59.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.58.0 to 0.59.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.58.0...v0.59.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-21 04:34:23 +00:00
dependabot[bot] 5210e758d2
Merge pull request #2287 from dexidp/dependabot/go_modules/google.golang.org/api-0.58.0 2021-10-20 09:15:24 +00:00
dependabot[bot] 514c2f29c6
Merge pull request #2286 from dexidp/dependabot/go_modules/api/v2/google.golang.org/grpc-1.41.0 2021-10-20 09:14:56 +00:00
dependabot[bot] e2c40f8f71
Merge pull request #2302 from dexidp/dependabot/go_modules/github.com/mattn/go-sqlite3-1.14.9 2021-10-20 09:14:25 +00:00
dependabot[bot] 66aba9c32b
build(deps): bump github.com/mattn/go-sqlite3 from 1.14.8 to 1.14.9
Bumps [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) from 1.14.8 to 1.14.9.
- [Release notes](https://github.com/mattn/go-sqlite3/releases)
- [Commits](https://github.com/mattn/go-sqlite3/compare/v1.14.8...v1.14.9)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-sqlite3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-20 04:21:44 +00:00
dependabot[bot] b9046ce566
build(deps): bump google.golang.org/api from 0.57.0 to 0.58.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.57.0 to 0.58.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.57.0...v0.58.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-19 22:51:22 +00:00
dependabot[bot] ed5315bb2e
build(deps): bump google.golang.org/grpc in /api/v2
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.40.0 to 1.41.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.40.0...v1.41.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-19 22:44:07 +00:00
Stephen Augustus (he/him) f7d2bf38b2
Merge pull request #2285 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.41.0
build(deps): bump google.golang.org/grpc from 1.40.0 to 1.41.0
2021-10-19 15:28:58 -07:00
m.nabokikh 9fad0602ec fix: do not update offlinesession lastUsed field if refresh token was not change
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-10-19 01:16:34 +04:00
dependabot[bot] c319983ecc
Merge pull request #2299 from dexidp/dependabot/go_modules/go.etcd.io/etcd/client/v3-3.5.1 2021-10-18 12:06:05 +00:00
dependabot[bot] a48c8ea9a4
build(deps): bump go.etcd.io/etcd/client/v3 from 3.5.0 to 3.5.1
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Changelog](https://github.com/etcd-io/etcd/blob/main/CHANGELOG-3.5.md)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.5.1)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 10:38:58 +00:00
dependabot[bot] 94597d8dc8
Merge pull request #2298 from dexidp/dependabot/go_modules/go.etcd.io/etcd/client/pkg/v3-3.5.1 2021-10-18 09:05:31 +00:00
Joel Speed 4aa7e6846f
Merge pull request #2268 from snuggie12/mh-2111-nested-groups
Resolves #2111 Option to fetch transitive group membership
2021-10-18 09:46:54 +01:00
dependabot[bot] 0dd5d65cc7
build(deps): bump go.etcd.io/etcd/client/pkg/v3 from 3.5.0 to 3.5.1
Bumps [go.etcd.io/etcd/client/pkg/v3](https://github.com/etcd-io/etcd) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Changelog](https://github.com/etcd-io/etcd/blob/main/CHANGELOG-3.5.md)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.5.1)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/pkg/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 04:21:05 +00:00
Matt Hoey ee5b5b25bd Resolves #2111 Option to fetch transitive group membership
Signed-off-by: Matt Hoey <matt.hoey@missionlane.com>
2021-10-17 12:48:22 -07:00
dependabot[bot] a15cd8788f
Merge pull request #2292 from dexidp/dependabot/docker/golang-1.17.2-alpine3.14 2021-10-08 12:07:14 +00:00
dependabot[bot] 6bb627f3e3
build(deps): bump golang from 1.17.1-alpine3.14 to 1.17.2-alpine3.14
Bumps golang from 1.17.1-alpine3.14 to 1.17.2-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-08 04:07:23 +00:00
Bob Callaway 2e0041f95f ensure template does not double-escape URL
Signed-off-by: Bob Callaway <bob.callaway@gmail.com>
2021-10-06 10:16:55 -04:00
Márk Sági-Kazár 67ba7a1c70
Merge pull request #2265 from ariary/master
Add parametrization of grant type supported in discovery endpoint
2021-10-06 15:54:17 +02:00
ariary 7bc966217d sort grant type supported
Signed-off-by: ariary <ariary9.2@hotmail.fr>
2021-10-06 08:29:14 -04:00
Bob Callaway 8fd69c16f5 correctly handle path escaping for connector IDs
Signed-off-by: Bob Callaway <bob.callaway@gmail.com>
2021-10-01 16:04:34 -04:00
dependabot[bot] 8593933883
build(deps): bump google.golang.org/grpc from 1.40.0 to 1.41.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.40.0 to 1.41.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.40.0...v1.41.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-29 07:06:55 +00:00
Márk Sági-Kazár ff6e7c7688
Merge pull request #2282 from flant/fix-ioutils-mysql
chore: fix ioutil lint error after merging MySQL ent storage
2021-09-29 08:58:35 +02:00
m.nabokikh d4e82e3315 chore: fix ioutil lint error after merging MySQL ent storage
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-09-21 08:35:25 +04:00
Maksim Nabokikh f92a6f4457
Merge pull request #2272 from flant/mysql-ent
feat: Add MySQL ent-based storage driver
2021-09-21 08:24:36 +04:00
dependabot[bot] 3456c3315d
Merge pull request #2279 from dexidp/dependabot/go_modules/github.com/coreos/go-oidc/v3-3.1.0 2021-09-20 09:55:58 +00:00
dependabot[bot] a417f5d1b0
build(deps): bump github.com/coreos/go-oidc/v3 from 3.0.0 to 3.1.0
Bumps [github.com/coreos/go-oidc/v3](https://github.com/coreos/go-oidc) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/coreos/go-oidc/releases)
- [Commits](https://github.com/coreos/go-oidc/compare/v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: github.com/coreos/go-oidc/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-20 04:29:56 +00:00
Maksim Nabokikh 5169c4317d
Merge pull request #2278 from Juneezee/deprecate-ioutil
refactor: move from io/ioutil to io and os package
2021-09-17 16:36:35 +04:00
Eng Zer Jun 551022046c
chore: enable depguard for io/ioutil package
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-09-17 19:04:30 +08:00
Eng Zer Jun f0186ff265
refactor: move from io/ioutil to io and os package
The io/ioutil package has been deprecated as of Go 1.16, see
https://golang.org/doc/go1.16#ioutil. This commit replaces the existing
io/ioutil functions with their new definitions in io and os packages.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-09-17 14:12:39 +08:00
dependabot[bot] 40b426b276
Merge pull request #2277 from dexidp/dependabot/go_modules/google.golang.org/api-0.57.0 2021-09-17 04:44:44 +00:00
dependabot[bot] 8a7c2b47f1
build(deps): bump google.golang.org/api from 0.56.0 to 0.57.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.56.0 to 0.57.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.56.0...v0.57.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-17 04:17:58 +00:00
ariary c6f6dd69e9 lint comment
Signed-off-by: ariary <ariary9.2@hotmail.fr>
2021-09-15 03:58:27 -04:00
m.nabokikh 575742b137 Remove sqlite transaction tests for ent
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-09-14 18:55:03 +04:00
m.nabokikh 096e229562 Get rid of nolint
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-09-13 18:58:32 +04:00
m.nabokikh 4d4edaf540 Fix sqlite an mysql tests
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-09-13 18:48:46 +04:00
m.nabokikh fb38e1235d Add dialects
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-09-13 17:48:02 +04:00
m.nabokikh eae3219e4d feat: Add MySQL ent-based storage driver
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-09-13 14:25:17 +04:00
dependabot[bot] 79ce4fdbad
Merge pull request #2269 from dexidp/dependabot/docker/golang-1.17.1-alpine3.14 2021-09-10 05:39:30 +00:00
dependabot[bot] c9b4e8db3b
Merge pull request #2270 from dexidp/dependabot/go_modules/github.com/russellhaering/goxmldsig-1.1.1 2021-09-10 05:39:00 +00:00
dependabot[bot] 0d5b2ac060
build(deps): bump github.com/russellhaering/goxmldsig
Bumps [github.com/russellhaering/goxmldsig](https://github.com/russellhaering/goxmldsig) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/russellhaering/goxmldsig/releases)
- [Commits](https://github.com/russellhaering/goxmldsig/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: github.com/russellhaering/goxmldsig
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-10 04:19:07 +00:00
dependabot[bot] b4b74955bd
build(deps): bump golang from 1.17.0-alpine3.14 to 1.17.1-alpine3.14
Bumps golang from 1.17.0-alpine3.14 to 1.17.1-alpine3.14.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-10 04:07:21 +00:00
kali 1497e70225 Add parametrization of grant type supported in discovery endpoint
Signed-off-by: ariary <ariary9.2@hotmail.fr>
2021-09-03 05:50:59 -04:00
dependabot[bot] 1b8f544873
Merge pull request #2263 from dexidp/dependabot/go_modules/github.com/lib/pq-1.10.3 2021-09-03 08:20:29 +00:00
dependabot[bot] e412369851
build(deps): bump github.com/lib/pq from 1.10.2 to 1.10.3
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.2 to 1.10.3.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.2...v1.10.3)

---
updated-dependencies:
- dependency-name: github.com/lib/pq
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-03 04:17:54 +00:00
dependabot[bot] b74af809fc
Merge pull request #2262 from dexidp/dependabot/go_modules/google.golang.org/api-0.56.0 2021-09-01 12:25:33 +00:00
dependabot[bot] 656f5548d4
build(deps): bump google.golang.org/api from 0.55.0 to 0.56.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.55.0 to 0.56.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.55.0...v0.56.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-01 04:16:57 +00:00
dependabot[bot] 53c6eb6675
Merge pull request #2259 from dexidp/dependabot/go_modules/google.golang.org/api-0.55.0 2021-09-01 01:15:20 +00:00
dependabot[bot] b11a2a5604
Merge pull request #2258 from dexidp/dependabot/docker/alpine-3.14.2 2021-09-01 01:14:45 +00:00
dependabot[bot] 6dcf7a042d
build(deps): bump google.golang.org/api from 0.54.0 to 0.55.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.54.0 to 0.55.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.54.0...v0.55.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-31 04:14:32 +00:00
dependabot[bot] 33ba1d3b74
build(deps): bump alpine from 3.14.1 to 3.14.2
Bumps alpine from 3.14.1 to 3.14.2.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 04:07:37 +00:00
dependabot[bot] b3b9c26e5a
Merge pull request #2249 from dexidp/dependabot/go_modules/entgo.io/ent-0.9.1 2021-08-23 22:25:37 +00:00
dependabot[bot] 4488af24b6
build(deps): bump entgo.io/ent from 0.9.0 to 0.9.1
Bumps [entgo.io/ent](https://github.com/ent/ent) from 0.9.0 to 0.9.1.
- [Release notes](https://github.com/ent/ent/releases)
- [Commits](https://github.com/ent/ent/compare/v0.9.0...v0.9.1)

---
updated-dependencies:
- dependency-name: entgo.io/ent
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-23 21:42:55 +00:00
Márk Sági-Kazár ad13fdc523
Merge pull request #2247 from dexidp/go-update
Update Go to 1.17
2021-08-23 23:35:17 +02:00
Mark Sagi-Kazar a950a24811
chore: update Go version in go.mod
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-08-17 22:42:39 +02:00
Mark Sagi-Kazar 691ecbbd9e
chore: update Go in GitHub Actions
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-08-17 15:57:57 +02:00
Mark Sagi-Kazar e1c88b2598
chore: update Go in Docker
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-08-17 15:57:29 +02:00
Mark Sagi-Kazar 22db25ef94
chore: update golangci-lint
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-08-17 15:55:53 +02:00
dependabot[bot] e472fe668e
Merge pull request #2246 from dexidp/dependabot/go_modules/github.com/go-ldap/ldap/v3-3.4.1 2021-08-17 10:36:27 +00:00
dependabot[bot] d5727600ae
build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.0 to 3.4.1
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.0...v3.4.1)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-17 04:15:09 +00:00
dependabot[bot] 10a3ab9c4c
Merge pull request #2242 from dexidp/dependabot/go_modules/api/v2/google.golang.org/grpc-1.40.0 2021-08-16 10:49:00 +00:00
dependabot[bot] fdc46d2bd3
build(deps): bump google.golang.org/grpc in /api/v2
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.36.1 to 1.40.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.36.1...v1.40.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-16 10:26:54 +00:00
dependabot[bot] 4f3e410e33
Merge pull request #2243 from dexidp/dependabot/go_modules/api/v2/google.golang.org/protobuf-1.27.1 2021-08-16 10:25:09 +00:00
dependabot[bot] 091d9eae83
build(deps): bump google.golang.org/protobuf in /api/v2
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.26.0 to 1.27.1.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.26.0...v1.27.1)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-16 09:58:43 +00:00
Mark Sagi-Kazar 2a54eb4e4f
chore: add dependabot config for the api module
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-08-16 11:57:14 +02:00
dependabot[bot] 6c61425e36
Merge pull request #2240 from dexidp/dependabot/go_modules/github.com/AppsFlyer/go-sundheit-0.5.0 2021-08-16 09:51:51 +00:00
dependabot[bot] dc859e1ca9
Merge pull request #2241 from dexidp/dependabot/go_modules/google.golang.org/api-0.54.0 2021-08-16 09:51:34 +00:00
dependabot[bot] 27d4075f54
Merge pull request #2239 from dexidp/dependabot/go_modules/github.com/go-ldap/ldap/v3-3.4.0 2021-08-16 09:51:08 +00:00
dependabot[bot] 46a7f81f6d
build(deps): bump google.golang.org/api from 0.53.0 to 0.54.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.53.0 to 0.54.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.53.0...v0.54.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-16 04:20:59 +00:00
dependabot[bot] 7c0fd3f804
build(deps): bump github.com/AppsFlyer/go-sundheit from 0.4.0 to 0.5.0
Bumps [github.com/AppsFlyer/go-sundheit](https://github.com/AppsFlyer/go-sundheit) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/AppsFlyer/go-sundheit/releases)
- [Commits](https://github.com/AppsFlyer/go-sundheit/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: github.com/AppsFlyer/go-sundheit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-16 04:20:04 +00:00
dependabot[bot] c110f12441
build(deps): bump github.com/go-ldap/ldap/v3 from 3.3.0 to 3.4.0
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.3.0...v3.4.0)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-16 04:19:46 +00:00
Márk Sági-Kazár f9f48016f4
Merge pull request #2232 from rdimitrov/dimitrovr/bump-k8s-deployment
Bump Dex image to v2.30.0 for Kubernetes deployment example
2021-08-13 01:14:41 +02:00
dependabot[bot] 532bc88a65
Merge pull request #2229 from dexidp/dependabot/docker/alpine-3.14.1 2021-08-12 23:05:03 +00:00
dependabot[bot] f02415a83d
Merge pull request #2236 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.40.0 2021-08-12 20:20:41 +00:00
dependabot[bot] c4066b2153
build(deps): bump google.golang.org/grpc from 1.39.1 to 1.40.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.39.1 to 1.40.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.39.1...v1.40.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 19:50:52 +00:00
dependabot[bot] fa18b14437
Merge pull request #2235 from dexidp/dependabot/go_modules/google.golang.org/api-0.53.0 2021-08-12 19:45:06 +00:00
dependabot[bot] 11a9476bef
build(deps): bump google.golang.org/api from 0.52.0 to 0.53.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.52.0 to 0.53.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.52.0...v0.53.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 04:13:44 +00:00
Monis Khan 3009ae3b5d
Return valid JWT access token from password grant
This change updates the password grant handler to issue a valid JWT
access token instead of just returning a random value as the access
token.  This makes it possible to use the access token against the
user info endpoint.

Signed-off-by: Monis Khan <i@monis.app>
2021-08-11 14:57:58 -04:00
Radoslav Dimitrov 6865d84ae4 Bump Dex image to v2.30.0 for Kubernetes deployment example
Signed-off-by: Radoslav Dimitrov <dimitrovr@vmware.com>
2021-08-10 19:13:04 +03:00
dependabot[bot] 050339df86
build(deps): bump alpine from 3.14.0 to 3.14.1
Bumps alpine from 3.14.0 to 3.14.1.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-09 04:14:05 +00:00
dependabot[bot] 0e2459c230
Merge pull request #2227 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.39.1 2021-08-07 19:15:08 +00:00
dependabot[bot] 53c2dc30b5
build(deps): bump google.golang.org/grpc from 1.39.0 to 1.39.1
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.39.0 to 1.39.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.39.0...v1.39.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-07 18:55:38 +00:00
dependabot[bot] 3c1763a14f
Merge pull request #2225 from dexidp/dependabot/docker/golang-1.16.7-alpine3.13 2021-08-07 18:50:24 +00:00
dependabot[bot] fd67978363
Merge pull request #2226 from dexidp/dependabot/go_modules/entgo.io/ent-0.9.0 2021-08-07 18:50:12 +00:00
dependabot[bot] d6f14bd2d5
build(deps): bump entgo.io/ent from 0.8.0 to 0.9.0
Bumps [entgo.io/ent](https://github.com/ent/ent) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/ent/ent/releases)
- [Commits](https://github.com/ent/ent/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: entgo.io/ent
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-06 04:18:34 +00:00
dependabot[bot] 2109211d09
build(deps): bump golang from 1.16.6-alpine3.13 to 1.16.7-alpine3.13
Bumps golang from 1.16.6-alpine3.13 to 1.16.7-alpine3.13.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-06 04:07:05 +00:00
Maksim Nabokikh 3fac2ab6bc
Merge pull request #1862 from tkleczek/fix-rfc-errors
Improve auth flow error handling
2021-08-03 00:34:54 +04:00
Maksim Nabokikh 766fc7ad99
Merge pull request #2218 from jglick/htpasswd
Demonstrate use of `htpasswd` for bCrypt in `staticPasswords`
2021-08-02 10:17:39 +04:00
dependabot[bot] 1f7ddac4e2
Merge pull request #2211 from dexidp/dependabot/go_modules/github.com/mattn/go-sqlite3-1.14.8 2021-07-30 23:47:48 +00:00
dependabot[bot] 3f5f6172af
Merge pull request #2219 from dexidp/dependabot/go_modules/google.golang.org/api-0.52.0 2021-07-30 23:47:28 +00:00
Jesse Glick 65edeff231
Include explanation in comment: https://github.com/dexidp/dex/pull/2218#discussion_r679873279
Signed-off-by: Jesse Glick <jglick@cloudbees.com>
2021-07-30 12:52:43 -04:00
dependabot[bot] a6fbdc3ec8
build(deps): bump google.golang.org/api from 0.50.0 to 0.52.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.50.0 to 0.52.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.50.0...v0.52.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-30 04:17:09 +00:00
Jesse Glick f1d4fec45e
Demonstrate use of `htpasswd` for bCrypt in `staticPasswords`
Signed-off-by: Jesse Glick <jglick@cloudbees.com>
2021-07-27 11:40:02 -04:00
Maksim Nabokikh e650aef331
Merge pull request #2212 from salmanisd/feature/use-only-one-sqlite3-conn
storage/sql: use only one sqlite3 connection
2021-07-22 20:10:31 +04:00
Salman Ahmed e1f3bfe418 storage/sql: use only one sqlite3 connection
Signed-off-by: Salman Ahmed <salman.ahmed@weidmueller.com>
2021-07-22 14:07:37 +02:00
Tomasz Kleczek 4ffaa60d21 Improve auth flow error handling
Signed-off-by: Tomasz Kleczek <tomasz.kleczek@gmail.com>
2021-07-21 09:33:39 +02:00
Henning 138364ceeb
handlePasswordGrant: insert connectorData into OfflineSession (#2199)
* handlePasswordGrant: insert connectorData into OfflineSession

This change will insert the ConnectorData from the initial Login
into the OfflineSession, as already done in handlePasswordLogin.

Signed-off-by: Henning Surmeier <h.surmeier@mittwald.de>
2021-07-21 00:05:35 +04:00
dependabot[bot] ff10f84e42
build(deps): bump github.com/mattn/go-sqlite3 from 1.14.7 to 1.14.8
Bumps [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/mattn/go-sqlite3/releases)
- [Commits](https://github.com/mattn/go-sqlite3/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: github.com/mattn/go-sqlite3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-16 04:15:36 +00:00
dependabot[bot] d4bd37156d
Merge pull request #2210 from dexidp/dependabot/docker/golang-1.16.6-alpine3.13 2021-07-15 09:27:16 +00:00
dependabot[bot] 30c6ddd556
build(deps): bump golang from 1.16.5-alpine3.13 to 1.16.6-alpine3.13
Bumps golang from 1.16.5-alpine3.13 to 1.16.6-alpine3.13.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-15 04:06:59 +00:00
Márk Sági-Kazár a9942794e5
Merge pull request #2208 from dexidp/issue-template
Add GitHub issue forms
2021-07-14 02:57:34 +02:00
Mark Sagi-Kazar 1e61e9b1b4
chore: add GitHub issue forms
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-07-14 02:57:00 +02:00
Maksim Nabokikh 5b7ec77538
Merge pull request #2112 from flant/update-kubernetes-sa-tokens
feat: Update token periodically if Dex is running in Kubernetes cluster
2021-07-13 20:06:36 +04:00
Maksim Nabokikh 3d3f275efb Apply suggestions from code review
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-07-12 13:06:36 +04:00
m.nabokikh d413870f6e feat: Update token periodically if Dex is running in Kubernetes cluster
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-07-12 13:00:46 +04:00
Maksim Nabokikh 823484f024
Merge pull request #2092 from flant/kubernetes-fallback-to-namespace-file
fix: read namespace from file for Kubernetes storage client
2021-07-10 09:23:57 +04:00
Maksim Nabokikh 033a8d89f2
Merge pull request #2025 from flant/kubernetes-apiextensions-version
feat: create CRDs as apiextensions.k8s.io/v1
2021-07-08 10:52:55 +04:00
Maksim Nabokikh 2211c515a6
Merge pull request #2121 from flant/ent-postgres
feat: Add ent-based postgres storage
2021-07-08 10:49:13 +04:00
Márk Sági-Kazár 39f0e0e0b0
Merge pull request #2204 from dexidp/dependabot/go_modules/github.com/spf13/cobra-1.2.1
build(deps): bump github.com/spf13/cobra from 1.1.3 to 1.2.1
2021-07-05 17:00:41 +02:00
dependabot[bot] be492e97ce
build(deps): bump github.com/spf13/cobra from 1.1.3 to 1.2.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.3 to 1.2.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.3...v1.2.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-05 04:20:47 +00:00
dependabot[bot] 731e53913a
Merge pull request #2198 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.39.0 2021-07-01 07:56:11 +00:00
dependabot[bot] 9bb764b63c
build(deps): bump google.golang.org/grpc from 1.38.0 to 1.39.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.38.0 to 1.39.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.38.0...v1.39.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 07:31:35 +00:00
dependabot[bot] 176a6738fd
Merge pull request #2201 from dexidp/dependabot/go_modules/google.golang.org/api-0.50.0 2021-07-01 07:25:46 +00:00
dependabot[bot] 6cac94f720
Merge pull request #2200 from dexidp/dependabot/github_actions/helm/kind-action-1.2.0 2021-07-01 07:25:07 +00:00
dependabot[bot] eec8ed6182
build(deps): bump google.golang.org/api from 0.49.0 to 0.50.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.49.0 to 0.50.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.49.0...v0.50.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 04:15:59 +00:00
dependabot[bot] f72602c3bd
build(deps): bump helm/kind-action from 1.1.0 to 1.2.0
Bumps [helm/kind-action](https://github.com/helm/kind-action) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/helm/kind-action/releases)
- [Commits](https://github.com/helm/kind-action/compare/v1.1.0...v1.2.0)

---
updated-dependencies:
- dependency-name: helm/kind-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-01 04:06:47 +00:00
Márk Sági-Kazár 0780edbcbe
Merge pull request #2191 from dexidp/flaky-expiry-test
Quick fix flaky test
2021-06-29 11:01:08 +02:00
Márk Sági-Kazár 0d3d787511
Merge pull request #2193 from dexidp/dependabot/go_modules/google.golang.org/protobuf-1.27.1
build(deps): bump google.golang.org/protobuf from 1.27.0 to 1.27.1
2021-06-29 11:00:47 +02:00
dependabot[bot] 27cc11b4d6
build(deps): bump google.golang.org/protobuf from 1.27.0 to 1.27.1
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.0 to 1.27.1.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.27.0...v1.27.1)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-29 04:18:59 +00:00
Mark Sagi-Kazar ceb4324c18
test: quick fix flaky test
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-28 23:30:14 +02:00
Mark Sagi-Kazar e1ae7240f4
Revert "chore: add GitHub issue forms"
This reverts commit 452d466481.
2021-06-28 23:16:06 +02:00
Mark Sagi-Kazar 61881d751b
Revert "chore: fix GitHub issue forms"
This reverts commit 2e5e1488e6.
2021-06-28 23:15:57 +02:00
Mark Sagi-Kazar 2e5e1488e6
chore: fix GitHub issue forms
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-28 23:14:01 +02:00
Mark Sagi-Kazar 452d466481
chore: add GitHub issue forms
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-28 23:11:45 +02:00
Márk Sági-Kazár 59c7e20c3c
Merge pull request #2190 from dexidp/docker
Update docker build config
2021-06-28 22:45:42 +02:00
Mark Sagi-Kazar 81e884e903
ci: update docker build config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-28 22:07:14 +02:00
Márk Sági-Kazár cfc8d198ac
Merge pull request #2189 from dexidp/ldap-unauth-bind
Fix anonymous ldap bind
2021-06-28 19:17:57 +02:00
Mark Sagi-Kazar 215c3160f8
fix(connector/ldap): explicit anonymus ldap bind
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-28 17:49:47 +02:00
dependabot[bot] f7c09760f2
Merge pull request #2188 from dexidp/dependabot/go_modules/google.golang.org/protobuf-1.27.0 2021-06-28 09:21:09 +00:00
dependabot[bot] 79e1f25f21
build(deps): bump google.golang.org/protobuf from 1.26.0 to 1.27.0
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.26.0 to 1.27.0.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.26.0...v1.27.0)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-28 04:19:46 +00:00
Márk Sági-Kazár f6904c38ef
Merge pull request #1865 from WorldProgrammingLtd/fix-1849
fix: defer creation of auth request.
2021-06-25 19:05:41 +02:00
Márk Sági-Kazár 5e6a8362c6
Merge pull request #2178 from noesberger/patch-1
set readinessProbe to https
2021-06-24 11:48:58 +02:00
dependabot[bot] 3981ac8aa6
Merge pull request #2186 from dexidp/dependabot/go_modules/google.golang.org/api-0.49.0 2021-06-24 09:39:34 +00:00
dependabot[bot] 76cb5f521c
build(deps): bump google.golang.org/api from 0.48.0 to 0.49.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.48.0 to 0.49.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.48.0...v0.49.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-24 04:16:29 +00:00
noesberger e51704e41a
set readinessProbe to https
Fix the error
Readiness probe failed: Get "http://100.105.5.5:5556/healthz": dial tcp 100.105.5.5:5556: connect: connection refused
Client sent an HTTP request to an HTTPS server.
2021-06-17 15:55:15 +02:00
dependabot[bot] 9fe031776e
Merge pull request #2165 from dexidp/dependabot/go_modules/google.golang.org/api-0.48.0 2021-06-16 09:10:54 +00:00
dependabot[bot] cba7d69577
Merge pull request #2175 from dexidp/dependabot/docker/alpine-3.14.0 2021-06-16 09:05:37 +00:00
dependabot[bot] 5c315a3a4e
build(deps): bump google.golang.org/api from 0.47.0 to 0.48.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.47.0 to 0.48.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.47.0...v0.48.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-16 08:51:55 +00:00
Márk Sági-Kazár 0417789626
Merge pull request #2174 from dexidp/update-etcd
Update etcd
2021-06-16 10:46:18 +02:00
dependabot[bot] ddd19bf91d
build(deps): bump alpine from 3.13.5 to 3.14.0
Bumps alpine from 3.13.5 to 3.14.0.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-16 06:06:29 +00:00
Mark Sagi-Kazar a207238491
chore: fix lint issues
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-16 00:54:18 +02:00
Mark Sagi-Kazar 7043d944cf
chore: update etcd version in test environments
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-16 00:40:35 +02:00
Mark Sagi-Kazar 831c0efe9c
chore(deps): update etcd
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-16 00:37:48 +02:00
m.nabokikh 0754c30ac2 fix: get namespace from file for Kubernetes storage client
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-10 20:01:14 +04:00
m.nabokikh 7a2472555a feat: Create CRDs as apiextensions.k8s.io/v1
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-10 20:00:49 +04:00
Márk Sági-Kazár baec4f79ce
Merge pull request #2161 from dexidp/update-etcd
Update etcd
2021-06-07 11:24:16 +02:00
Mark Sagi-Kazar fd2c86d36e
chore(deps): update etcd
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-06-07 10:58:51 +02:00
dependabot[bot] 6c8c336e9a
Merge pull request #2160 from dexidp/dependabot/go_modules/gopkg.in/square/go-jose.v2-2.6.0 2021-06-07 08:45:41 +00:00
dependabot[bot] 753cff1764
Merge pull request #2154 from dexidp/dependabot/docker/golang-1.16.5-alpine3.13 2021-06-07 08:00:32 +00:00
dependabot[bot] aece0ce873
build(deps): bump gopkg.in/square/go-jose.v2 from 2.5.1 to 2.6.0
Bumps [gopkg.in/square/go-jose.v2](https://github.com/square/go-jose) from 2.5.1 to 2.6.0.
- [Release notes](https://github.com/square/go-jose/releases)
- [Commits](https://github.com/square/go-jose/compare/v2.5.1...v2.6.0)

---
updated-dependencies:
- dependency-name: gopkg.in/square/go-jose.v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-07 07:14:50 +00:00
dependabot[bot] 245a46e743
build(deps): bump golang from 1.16.4-alpine3.13 to 1.16.5-alpine3.13
Bumps golang from 1.16.4-alpine3.13 to 1.16.5-alpine3.13.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-04 06:42:17 +00:00
Márk Sági-Kazár f45a89f6b3
Merge pull request #2152 from flant/web-sprig-templates
Add sprigs v3 functions to web templates
2021-06-02 13:37:13 +02:00
m.nabokikh 21a01ee811 Add sprig v3 functions to web templates
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-02 11:11:45 +04:00
Maksim Nabokikh 93ded5c406
Merge pull request #2091 from flant/kubernetes-tests-kind
chore: test Kubernetes storage with KinD
2021-06-02 11:10:34 +04:00
m.nabokikh 97591861b2 Cleanup Makefile
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-02 10:33:54 +04:00
m.nabokikh 00950eedd6 Bump kind version and change kubeconfig tmp dir
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-01 21:57:19 +04:00
m.nabokikh bc5371e730 Add make file commands for kind
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-01 19:44:49 +04:00
m.nabokikh 5a48d8a82d chore: test Kubernetes storage with KinD
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-06-01 19:44:31 +04:00
Márk Sági-Kazár 6384af06e4
Update bug_report.md 2021-05-30 18:27:14 +02:00
Márk Sági-Kazár cdcf7a4694
Update PULL_REQUEST_TEMPLATE.md 2021-05-30 04:00:44 +02:00
Maksim Nabokikh 5d996661ea
Merge pull request #2144 from flant/bump-linter-version
Bump golag-ci lint version to 1.40.1
2021-05-27 21:50:23 +04:00
m.nabokikh 4b54433ec2 Bump golag-ci lint version to 1.40.1
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-27 19:27:06 +04:00
Márk Sági-Kazár 95941506f5
Merge pull request #2142 from dexidp/update-etcd
chore(deps): update etcd
2021-05-26 17:59:26 +02:00
Mark Sagi-Kazar 8dbd0c6536
chore(deps): update etcd
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-05-26 17:11:04 +02:00
Márk Sági-Kazár aef61cea8d
Merge pull request #2141 from dexidp/update-gosundheit
Update gosundheit
2021-05-26 17:05:40 +02:00
Mark Sagi-Kazar 0bef10ef80
chore(deps): update gosundheit
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-05-26 14:50:35 +02:00
Márk Sági-Kazár 5451188e29
Merge pull request #2124 from dexidp/update-etcd
Update etcd to 3.5.0-beta.3
2021-05-26 13:38:40 +02:00
Mark Sagi-Kazar ca02fc16bd
chore(deps): update etcd
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-05-26 13:16:05 +02:00
m.nabokikh dea1d3383c Deprecation warning log message
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-24 19:40:28 +04:00
m.nabokikh 13a83d9bba chore: warning about deprecated LDAP groupSearch fields
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-24 19:08:13 +04:00
Alastair Houghton cd0c24ec4d fix: add an extra endpoint to avoid refresh generating AuthRequests.
By adding an extra endpoint and a redirect, we can avoid a situation
where it's trivially easy to generate a large number of AuthRequests
by hitting F5/refresh in the browser.

Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2021-05-21 11:42:52 +01:00
Alastair Houghton 030a6459d6 fix: reinstate TestHandleAuthCode.
Reinstating this test as it shouldn't have been removed.

Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2021-05-21 11:24:30 +01:00
Alastair Houghton 88025b3d7c fix: remove some additional dependencies.
Accidentally added some of these back during merge.

Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2021-05-21 11:24:30 +01:00
Alastair Houghton 0284a4c3c9 fix: back link on password page needs to be explicit.
The back link on the password page was using Javascript to tell the
browser to navigate back, which won't work if the user has entered a
set of incorrect log-in details.  Fix this by using an explicit URL
instead.

Fixes #1851

Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2021-05-21 11:24:30 +01:00
Alastair Houghton cdbb5dd94d fix: defer creation of auth request.
Rather than creating the auth request when the user hits /auth, pass
the arguments through to /auth/{connector} and have the auth request
created there.  This prevents a database error when using the "Select
another login method" link, and also avoids a few other error cases.

Fixes #1849, #646.

Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2021-05-21 11:24:23 +01:00
dependabot[bot] 4a874cce89
Merge pull request #2130 from dexidp/dependabot/go_modules/google.golang.org/grpc-1.38.0 2021-05-20 12:35:09 +00:00
dependabot[bot] 461c5f687d
build(deps): bump google.golang.org/grpc from 1.37.0 to 1.38.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.37.0 to 1.38.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.37.0...v1.38.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-20 12:14:11 +00:00
dependabot[bot] 4e4dad023c
Merge pull request #2131 from dexidp/dependabot/go_modules/google.golang.org/api-0.47.0 2021-05-20 12:08:43 +00:00
dependabot[bot] 1220017f6c
build(deps): bump google.golang.org/api from 0.46.0 to 0.47.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.46.0 to 0.47.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.46.0...v0.47.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-20 06:20:51 +00:00
Maksim Nabokikh 20875c972e
Discard package "version" (#2107)
* Discard package "version"

Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>

* Inject api version

Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>

* Pass version arg to the dex API

Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-18 00:55:24 +02:00
dependabot[bot] 47d029a51b
Merge pull request #2110 from dexidp/dependabot/docker/golang-1.16.4-alpine3.13 2021-05-17 15:47:59 +00:00
Márk Sági-Kazár 18d1f70cee
Merge pull request #1861 from concourse/pr/bcrypt-for-client-secret-sync
Use constant time comparison for client secret verification
2021-05-17 17:27:42 +02:00
Rui Yang fe8085b886 remove client secret encryption option
constant time compare for client secret verification will be kept

Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-05-17 10:16:50 -04:00
dependabot[bot] 283dd89f4d
Merge pull request #2123 from dexidp/dependabot/go_modules/github.com/lib/pq-1.10.2 2021-05-17 07:41:26 +00:00
dependabot[bot] c65652ed8f
build(deps): bump github.com/lib/pq from 1.10.1 to 1.10.2
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.1 to 1.10.2.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.1...v1.10.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-17 07:11:13 +00:00
m.nabokikh 49adc4e5bb Fix ent-based postgres storage tests
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-15 09:06:44 +04:00
m.nabokikh 19884d92ac feat: Add ent-based postgres storage
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-14 23:19:59 +04:00
Rui Yang ecea593ddd fix a bug in hash comparison function
the client secret coming in should be hashed and the one in storage
is the one in plaintext

Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-05-14 13:32:27 -04:00
dependabot[bot] 47bdbdb1a2
build(deps): bump golang from 1.16.3-alpine3.13 to 1.16.4-alpine3.13
Bumps golang from 1.16.3-alpine3.13 to 1.16.4-alpine3.13.

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 06:46:19 +00:00
Maksim Nabokikh 81c4dc7994
Merge pull request #1906 from flant/ent-sqlite
feat: Add ent-based sqlite3 storage
2021-05-05 18:19:25 +04:00
Márk Sági-Kazár ba2cec3f72
Merge pull request #2103 from flant/add-new-maintainer
Add @nabokihms to the maintainers list
2021-05-04 21:22:49 +02:00
dependabot[bot] fcca5f4b4f
Merge pull request #2104 from dexidp/dependabot/go_modules/google.golang.org/api-0.46.0 2021-05-04 09:18:05 +00:00
dependabot[bot] b1292bd630
build(deps): bump google.golang.org/api from 0.45.0 to 0.46.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.45.0 to 0.46.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.45.0...v0.46.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-04 06:59:24 +00:00
m.nabokikh 8553309db3 Add obsolete tokens, resolve conflicts, bump ent
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-05-02 12:43:21 +04:00
Márk Sági-Kazár 94a2b3ed87
Merge pull request #2010 from flant/switch-device-token-endpoint-to-token
fix: use /token endpoint to get tokens with device flow
2021-05-01 13:24:55 +02:00
m.nabokikh 24fa4def5b chore: update ent
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-04-30 17:48:16 +04:00
m.nabokikh 2e61860d5a Add ent autogenerated code
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-04-30 17:47:54 +04:00
m.nabokikh 11859166d0 feat: Add ent-based sqlite3 storage
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-04-30 17:47:54 +04:00
Stephen Augustus 674631c9ab
Merge pull request #2090 from dexidp/security-policy
Initial security policy
2021-04-27 20:33:21 -04:00
Márk Sági-Kazár 47b0a2bdf9
Merge pull request #2100 from dexidp/mysql-port
Fix MySQL connection to use the provided port
2021-04-28 01:23:41 +02:00
Mark Sagi-Kazar e2b56d0a09
fix(storage/mysql): add missing port to the address
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-04-27 14:09:21 +02:00
m.nabokikh 4561214ab2 Add @nabokihms to maintainers list
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-04-27 13:11:15 +04:00
dependabot[bot] afa6f1e03e
Merge pull request #2099 from dexidp/dependabot/go_modules/github.com/felixge/httpsnoop-1.0.2 2021-04-26 09:09:08 +00:00
Mark Sagi-Kazar df9fc78d2d
ci: run mysql tests on non-standard port
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-04-26 11:01:24 +02:00
Mark Sagi-Kazar bf8c35ad2d
docs: update readme linking to the security policy
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-04-26 10:59:17 +02:00
Mark Sagi-Kazar 59fcab281e
docs: initial security policy
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-04-26 10:59:15 +02:00
dependabot[bot] 05b61a3d86
build(deps): bump github.com/felixge/httpsnoop from 1.0.1 to 1.0.2
Bumps [github.com/felixge/httpsnoop](https://github.com/felixge/httpsnoop) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/felixge/httpsnoop/releases)
- [Commits](https://github.com/felixge/httpsnoop/compare/v1.0.1...v1.0.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-26 08:50:00 +00:00
Márk Sági-Kazár 551229a986
Merge pull request #1846 from flant/refresh-token-expiration-policy
feat: Add refresh token expiration and rotation settings
2021-04-24 11:03:40 +02:00
Márk Sági-Kazár b1ac799073
Merge pull request #1912 from wellplayedgames/microsoft-prompt-type
Support setting the prompt type for the Microsoft connector
2021-04-24 10:58:43 +02:00
dependabot[bot] 31c18e557a
Merge pull request #2094 from dexidp/dependabot/go_modules/github.com/lib/pq-1.10.1 2021-04-22 08:26:07 +00:00
dependabot[bot] 5bc3cb2ad3
build(deps): bump github.com/lib/pq from 1.10.0 to 1.10.1
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.10.0...v1.10.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-22 06:54:28 +00:00
dependabot[bot] efd9839fd2
Merge pull request #2093 from dexidp/dependabot/go_modules/google.golang.org/api-0.45.0 2021-04-21 10:23:32 +00:00
dependabot[bot] fa3a4d7f6b
build(deps): bump google.golang.org/api from 0.43.0 to 0.45.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.43.0 to 0.45.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.43.0...v0.45.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-21 06:55:25 +00:00
Márk Sági-Kazár 0b9b588c96
Merge pull request #2089 from flant/remove-go-dev-badge-from-readme
chore: remove go dev badge from README
2021-04-17 21:20:47 +02:00
m.nabokikh 026d979073 chore: remove go dev badge from README
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-04-17 10:24:02 +04:00
dependabot[bot] e4065013a4
Merge pull request #2085 from dexidp/dependabot/docker/alpine-3.13.5 2021-04-15 08:18:38 +00:00
dependabot[bot] d4a2a362ab
Merge pull request #2086 from dexidp/dependabot/go_modules/github.com/mattn/go-sqlite3-1.14.7 2021-04-15 08:18:07 +00:00
dependabot[bot] de6d1bea56
build(deps): bump github.com/mattn/go-sqlite3 from 1.14.6 to 1.14.7
Bumps [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) from 1.14.6 to 1.14.7.
- [Release notes](https://github.com/mattn/go-sqlite3/releases)
- [Commits](https://github.com/mattn/go-sqlite3/compare/v1.14.6...v1.14.7)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 06:57:54 +00:00
dependabot[bot] 8fbbd4cec9
build(deps): bump alpine from 3.13.4 to 3.13.5
Bumps alpine from 3.13.4 to 3.13.5.

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-15 06:53:00 +00:00
Márk Sági-Kazár b79d9a84bc
Merge pull request #2072 from dexidp/dependency-updates
Update dependencies
2021-04-08 17:50:52 +02:00
Mark Sagi-Kazar 03db309337
chore(deps): update dependencies
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-04-07 14:45:53 +02:00
Márk Sági-Kazár c7549cce5b
Merge pull request #2071 from dexidp/dependabot/go_modules/github.com/go-ldap/ldap/v3-3.3.0
build(deps): bump github.com/go-ldap/ldap/v3 from 3.2.4 to 3.3.0
2021-04-06 10:15:37 +02:00
dependabot[bot] 656798c8bd
build(deps): bump github.com/go-ldap/ldap/v3 from 3.2.4 to 3.3.0
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.2.4 to 3.3.0.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.2.4...v3.3.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-06 07:01:29 +00:00
m.nabokikh beb8911cf7 chore: add note about units to expire config
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-04-02 16:12:43 +04:00
dependabot[bot] b73c406d21
Merge pull request #2069 from dexidp/dependabot/docker/golang-1.16.3-alpine3.13 2021-04-02 07:14:55 +00:00
dependabot[bot] 4b924f1d86
build(deps): bump golang from 1.16.2-alpine3.13 to 1.16.3-alpine3.13
Bumps golang from 1.16.2-alpine3.13 to 1.16.3-alpine3.13.

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-02 06:54:24 +00:00
dependabot[bot] 55352575b8
Merge pull request #2066 from dexidp/dependabot/docker/alpine-3.13.4 2021-04-01 11:20:38 +00:00
Márk Sági-Kazár d2eb1b04dc
Merge pull request #2067 from dexidp/dependabot/go_modules/github.com/go-sql-driver/mysql-1.6.0
build(deps): bump github.com/go-sql-driver/mysql from 1.5.0 to 1.6.0
2021-04-01 13:18:21 +02:00
dependabot[bot] 0f4ad150ce
build(deps): bump github.com/go-sql-driver/mysql from 1.5.0 to 1.6.0
Bumps [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/go-sql-driver/mysql/releases)
- [Changelog](https://github.com/go-sql-driver/mysql/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-sql-driver/mysql/compare/v1.5.0...v1.6.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-01 07:23:52 +00:00
dependabot[bot] b57c8fa75b
build(deps): bump alpine from 3.13.3 to 3.13.4
Bumps alpine from 3.13.3 to 3.13.4.

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-01 07:16:05 +00:00
dependabot[bot] 1076081f79
Merge pull request #2064 from dexidp/dependabot/docker/alpine-3.13.3 2021-03-26 10:41:31 +00:00
dependabot[bot] f5a29bcdbb
build(deps): bump alpine from 3.13.2 to 3.13.3
Bumps alpine from 3.13.2 to 3.13.3.

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-26 06:48:52 +00:00
Márk Sági-Kazár e18510b16e
Merge pull request #2058 from dexidp/proto
Upgrade protobuf and grpc
2021-03-24 20:18:08 +01:00
Mark Sagi-Kazar 95796b04a3
chore(deps): upgrade protobuf and grpc
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-24 19:17:26 +01:00
Márk Sági-Kazár 2bf728c6ec
Merge pull request #1926 from dexidp/update-etcd-3.5
Update etcd to 3.5
2021-03-23 14:44:26 +01:00
Mark Sagi-Kazar 356ccecc24
chore(deps): update etcd client to 3.5
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 22:12:35 +01:00
Márk Sági-Kazár 8e7ce6353f
Merge pull request #2057 from dexidp/codec
Upgrade protobuf in internal codec
2021-03-22 20:24:07 +01:00
Mark Sagi-Kazar d25051c867
chore(deps): upgrade protobuf in server/internal package
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 19:27:47 +01:00
Mark Sagi-Kazar 41712bcbfa
build: rename old proto download targets
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 18:28:15 +01:00
Márk Sági-Kazár e3f8b0f2f6
Merge pull request #2036 from flant/keystone-minor-fixes
chore: add keystone connector icon and bump tests dependencies
2021-03-22 17:51:19 +01:00
Márk Sági-Kazár 8cba308b0e
Merge pull request #2056 from dexidp/updates
Update xml roundtrip validator
2021-03-22 17:40:17 +01:00
Márk Sági-Kazár 3adb4e74df
Merge pull request #2055 from salmanisd/update-ldap-to-v3
connector/ldap: use go-ldap version v3
2021-03-22 17:39:50 +01:00
Márk Sági-Kazár 1ec5cf07f2
Merge pull request #2054 from dexidp/embed-web
Embed web assets
2021-03-22 17:38:09 +01:00
Mark Sagi-Kazar 3e12618f0c
chore(deps): update xml roundtrip validator
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 16:23:01 +01:00
Salman Ahmed bbd8b3b3cd connector/ldap: use go-ldap version v3
Signed-off-by: Salman Ahmed <salman.ahmed@weidmueller.com>
2021-03-22 16:17:47 +01:00
Mark Sagi-Kazar 3ecdd57282
chore: change frontend dir default to unset
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 15:44:05 +01:00
Mark Sagi-Kazar a050f3228a
feat: add DEX_FRONTEND_DIR env var for setting the frontend dir
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 15:44:05 +01:00
Mark Sagi-Kazar 3b80d480e5
feat!: move web assets to /srv in Dockerfile
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 15:44:05 +01:00
Mark Sagi-Kazar d1e8b085e2
feat: use embedded assets by default
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 15:44:03 +01:00
Mark Sagi-Kazar 78fcac7568
feat: embed web assets
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-22 11:05:50 +01:00
Márk Sági-Kazár 3f0ca9b361
Merge pull request #1416 from concourse/pr/http-filesystem
Use http.FileSystem for web assets
2021-03-22 10:56:39 +01:00
Rui Yang 2f28fc7451 default to ./web when Dir and WebFS are not set
update WebFS doc

Signed-off-by: Rui Yang <ruiya@vmware.com>
Co-authored-by: Aidan Oldershaw <aoldershaw@pivotal.io>
2021-03-20 20:05:59 +00:00
Rui Yang 4e569024fd use go 1.16 new package io/fs
Unify the interface for reading web statics. Now it could read an
OS directory or get the content on live

One could use

//go:embed static
var webFiles embed.FS

anywhere and config dex server to take the file system by setting

WebConfig{WebFS: webFiles}

Signed-off-by: Rui Yang <ruiya@vmware.com>
Co-authored-by: Aidan Oldershaw <aoldershaw@pivotal.io>
2021-03-20 20:05:59 +00:00
Rui Yang 7b50cbf0ac use pkger for embedding static contents
Co-authored-by: Vikram Yadav <vyadav@pivotal.io>
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-03-20 20:05:59 +00:00
Rui Yang 1eab25f89f use web host url for asset hosting
Signed-off-by: Rui Yang <ruiya@vmware.com>
Co-authored-by: Aidan Oldershaw <aoldershaw@pivotal.io>
2021-03-20 20:05:59 +00:00
Rui Yang 10e9054811 Use http.FileSystem for web assets
Signed-off-by: Rui Yang <ryang@pivotal.io>
Co-authored-by: Aidan Oldershaw <aoldershaw@pivotal.io>
2021-03-20 20:05:59 +00:00
Rui Yang d658c24e8f add dex config flag for enabling client secret encryption
* if enabled, it will make sure client secret is bcrypted correctly
* if not, it falls back to old behaviour that allowing empty client
secret and comparing plain text, though now it will do
ConstantTimeCompare to avoid a timing attack.

So in either way it should provide more secure of client secret
verification.

Co-authored-by: Alex Surraci <suraci.alex@gmail.com>
Signed-off-by: Rui Yang <ruiya@vmware.com>
2021-03-20 20:05:56 +00:00
Josh Winters ec6f3a2f19 use bcrypt when comparing client secrets
- this assumes that the client is already bcrytped
when passed to dex. Similar to user passwords.

Signed-off-by: Josh Winters <jwinters@pivotal.io>
Co-authored-by: Vikram Yadav <vyadav@pivotal.io>
2021-03-20 20:05:56 +00:00
Márk Sági-Kazár a1adf86e53
Merge pull request #2053 from dexidp/fix-gomplate-slim
fix: stop using slim version of gomplate
2021-03-20 13:59:51 +01:00
Mark Sagi-Kazar 27dfbc0344
fix: stop using slim version of gomplate
See hairyhenderson/gomplate#1085

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-03-20 13:23:46 +01:00
dependabot[bot] 83ad7bc4e3
Merge pull request #2037 from dexidp/dependabot/docker/golang-1.16.2-alpine3.13 2021-03-12 08:49:06 +00:00
dependabot[bot] 8fee3cd212
build(deps): bump golang from 1.16.1-alpine3.13 to 1.16.2-alpine3.13
Bumps golang from 1.16.1-alpine3.13 to 1.16.2-alpine3.13.

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-12 06:42:23 +00:00
m.nabokikh 6be747142a chore: add keystone connector icon and bump tests dependencies
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-03-11 23:03:37 +04:00
dependabot[bot] dab9f98a15
Merge pull request #2035 from dexidp/dependabot/docker/golang-1.16.1-alpine3.13 2021-03-11 07:13:08 +00:00
dependabot[bot] d93a238a42
build(deps): bump golang from 1.16.0-alpine3.13 to 1.16.1-alpine3.13
Bumps golang from 1.16.0-alpine3.13 to 1.16.1-alpine3.13.

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-11 06:50:39 +00:00
Márk Sági-Kazár 3ae53f7434
Make OpenShift an alpha connector
I'm not sure why this was ever marked as stable.
2021-03-10 16:12:05 +01:00
dependabot[bot] b9ff4dd9ae
Merge pull request #2032 from dexidp/dependabot/go_modules/github.com/sirupsen/logrus-1.8.1 2021-03-10 11:47:37 +00:00
dependabot[bot] 04b2f655e6
build(deps): bump github.com/sirupsen/logrus from 1.8.0 to 1.8.1
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.8.0...v1.8.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-10 07:07:37 +00:00
Maksim Nabokikh 568fc06520 Update server/refreshhandlers.go
Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-03-09 09:41:41 +04:00
dependabot[bot] 72d11017ce
Merge pull request #2030 from dexidp/dependabot/go_modules/github.com/lib/pq-1.10.0 2021-03-08 12:01:20 +00:00
dependabot[bot] 08647537e2
Bump github.com/lib/pq from 1.9.0 to 1.10.0
Bumps [github.com/lib/pq](https://github.com/lib/pq) from 1.9.0 to 1.10.0.
- [Release notes](https://github.com/lib/pq/releases)
- [Commits](https://github.com/lib/pq/compare/v1.9.0...v1.10.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-08 08:02:20 +00:00
Márk Sági-Kazár f7d1405cfd
Merge pull request #2019 from dexidp/refactor-run-groups
Refactor run groups
2021-02-25 14:36:01 +01:00
Mark Sagi-Kazar 24a1103f11
refactor: rename gr to group
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-25 12:33:19 +01:00
Mark Sagi-Kazar 9cffca70f2
refactor: relocate run group initialization
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-25 12:32:28 +01:00
m.nabokikh 3bd0e91a68 Make /device/token deprecation warning more concise
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-25 11:53:25 +04:00
m.nabokikh 9ed5cc00cf Add deprecation warning for /device/token endpoint
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-24 17:14:28 +04:00
m.nabokikh 1211a86d58 fix: use /token endpoint to get tokens with device flow
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-24 16:03:25 +04:00
Márk Sági-Kazár 3c5a631ce3
Merge pull request #2009 from flant/skip-ldap-tests
fix: do not run LDAP tests locally by default
2021-02-20 23:33:31 +01:00
Márk Sági-Kazár c73057f93d
Merge pull request #2006 from flant/update-kubernetes-section-in-readme
chore: update Kubernetes section in README
2021-02-20 23:33:20 +01:00
m.nabokikh 84a07a7805 Do not run LDAP tests if DEX_LDAP_HOST is not set
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-20 17:05:41 +04:00
m.nabokikh 796d4c1e6b Remove tectonic links from the README
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-20 16:59:37 +04:00
dependabot[bot] c166257cf4
Merge pull request #2007 from dexidp/dependabot/docker/alpine-3.13.2 2021-02-20 12:30:25 +00:00
dependabot[bot] ff60ac0c4f
Merge pull request #2008 from dexidp/dependabot/go_modules/github.com/sirupsen/logrus-1.8.0 2021-02-20 12:30:11 +00:00
m.nabokikh 1f2771b57e fix: do not run LDAP tests locally by default
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-20 12:55:52 +04:00
Steffen Pøhner Henriksen 0f68fadb9a
Allow public clients created with API to have no client_secret (#1871)
Signed-off-by: Steffen Pøhner Henriksen <str3sses@gmail.com>
2021-02-19 10:18:54 +01:00
dependabot[bot] b4238886b3
chore(deps): bump github.com/sirupsen/logrus from 1.7.1 to 1.8.0
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.7.1 to 1.8.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.7.1...v1.8.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-18 06:51:32 +00:00
dependabot[bot] 9162eace7a
chore(deps): bump alpine from 3.13.1 to 3.13.2
Bumps alpine from 3.13.1 to 3.13.2.

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-18 06:48:45 +00:00
m.nabokikh df86a1faca chore: update Kubernetes section in README
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-18 08:14:43 +04:00
dependabot[bot] 86ea49173c
Merge pull request #2002 from dexidp/dependabot/go_modules/github.com/sirupsen/logrus-1.7.1 2021-02-17 09:38:46 +00:00
Márk Sági-Kazár 08a10b063f
Merge pull request #2003 from dexidp/go1.16
Upgrade Go to 1.16
2021-02-17 10:37:56 +01:00
Mark Sagi-Kazar 809ccaf4da
build: upgrade Go to 1.16
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-17 10:18:26 +01:00
dependabot[bot] 02cf3db178
chore(deps): bump github.com/sirupsen/logrus from 1.7.0 to 1.7.1
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.7.0 to 1.7.1.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.7.0...v1.7.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-17 06:51:31 +00:00
Joel Speed 95d8a0cccb
Merge pull request #1997 from dexidp/rewrite-ldap-tests
Rewrite LDAP tests to use a single server instance
2021-02-15 18:16:14 +00:00
Mark Sagi-Kazar 6f70272bc3
test(connector/ldap): remove ldap test gate
Now that the ldap tests don't create containers on the fly
they can run the same way as other integration tests.

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-15 16:46:43 +01:00
Mark Sagi-Kazar f11db50369
test(connector/ldap): rewrite tests to use a single server instance
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-15 16:37:03 +01:00
dependabot[bot] 447841f513
Merge pull request #1986 from dexidp/dependabot/go_modules/github.com/spf13/cobra-1.1.3 2021-02-15 10:10:51 +00:00
Márk Sági-Kazár 39cb542cc3
Merge pull request #1996 from justaugustus/update-email
MAINTAINERS: Update email address for Stephen Augustus
2021-02-15 11:10:05 +01:00
dependabot[bot] ee10373993
chore(deps): bump github.com/spf13/cobra from 1.1.1 to 1.1.3
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.1.1 to 1.1.3.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v1.1.1...v1.1.3)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-15 09:06:38 +00:00
Stephen Augustus 71351b1f47 MAINTAINERS: Update email address for Stephen Augustus
Signed-off-by: Stephen Augustus <foo@auggie.dev>
2021-02-15 03:51:45 -05:00
Márk Sági-Kazár ce8b05b0be
Merge pull request #1991 from flant/close-storage
fix: close storage on shutdown
2021-02-13 07:53:58 +01:00
m.nabokikh 87ebbaf834 fix: close storage on shutdown
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-12 22:31:13 +04:00
Márk Sági-Kazár a8c7ed9f67
Merge pull request #1989 from candlerb/candlerb/1732
Improve "Grant Access" template when client requests only openid scope
2021-02-12 00:54:09 +01:00
Brian Candler aa615c04c9 Improve "Grant Access" template when client requests only openid scope
Fixes #1732

Signed-off-by: Brian Candler <b.candler@pobox.com>
2021-02-11 17:35:40 +00:00
Márk Sági-Kazár 35cd09d481
Merge pull request #1980 from dexidp/refactor-health-checks
Refactor health checks
2021-02-11 13:16:07 +01:00
Mark Sagi-Kazar 7da0a89936
refactor: remove unused health checker
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-11 01:29:27 +01:00
Mark Sagi-Kazar 316da70545
refactor: use new health checker
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-11 01:29:25 +01:00
Mark Sagi-Kazar d77147f7cf
refactor: fix router variable name
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-11 00:13:47 +01:00
Mark Sagi-Kazar 024f69b2c7
feat: add health check to telemetry server
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-02-11 00:13:07 +01:00
m.nabokikh 9340fee011 Fixes after rebasing to the actual main branch
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 23:46:17 +04:00
m.nabokikh 89295a5b4a More refresh token handler refactoring, more tests
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 23:43:19 +04:00
m.nabokikh 4e73f39f57 Do not refresh id token claims if refresh token is allowed to reuse
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 23:43:19 +04:00
m.nabokikh 0c75ed12e2 Add refresh token expiration tests and some refactoring
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 23:43:19 +04:00
m.nabokikh 06c8ab5aa7 Fixes of naming and code style
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 23:37:57 +04:00
m.nabokikh 91de99d57e feat: Add refresh token expiration and rotation settings
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 23:37:57 +04:00
Márk Sági-Kazár 10597cf09f
Merge pull request #1893 from flant/add-dockerize
feat: Add gomplate to the docker image
2021-02-10 20:06:45 +01:00
m.nabokikh 715fee7a01 Switch to slim version of a gomplate and add a comment to docker config
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-10 19:44:05 +04:00
Márk Sági-Kazár 5a667bbee0
Merge pull request #1773 from faro-oss/faro-upstream/add-c_hash-to-id_token
Add c_hash to id_token, issued on /auth endpoint, when in hybrid flow
2021-02-10 16:12:54 +01:00
Márk Sági-Kazár 9b1ecac0d9
Merge pull request #1952 from flant/auth-code-iinvalid-grant
fix: return invalid_grant error for invalid or expired auth codes
2021-02-10 15:50:18 +01:00
Márk Sági-Kazár a7a92b0513
Merge pull request #1899 from lcc3108/master
update example/k8s/dex.yaml
2021-02-10 13:44:13 +01:00
Márk Sági-Kazár 1c9fb499b4
Merge pull request #1947 from faro-oss/feature/ldaps-example
Extend OpenLDAP example for LDAPS
2021-02-10 13:39:29 +01:00
Márk Sági-Kazár 1c551fd86b
Merge pull request #1946 from flant/prealloc-unparam-sqlclosecheck
Enable unparam, prealloc, sqlclosecheck linters
2021-02-10 13:24:47 +01:00
Márk Sági-Kazár 728ae7b348
Merge pull request #1961 from flant/make-example-app-form-prettier
chore: make example-app form prettier
2021-02-10 00:16:56 +01:00
Márk Sági-Kazár e50d9a908b
Merge pull request #1963 from flant/graceful-shutdown
feat: graceful shutdown
2021-02-05 10:34:27 +01:00
Maksim Nabokikh 6664b5702d Apply suggestions from code review
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-05 13:16:41 +04:00
dependabot[bot] 8ff53d9d52
Merge pull request #1972 from dexidp/dependabot/docker/golang-1.15.8-alpine3.13 2021-02-05 08:16:45 +00:00
dependabot[bot] 4dcce60d5c
chore(deps): bump golang from 1.15.7-alpine3.13 to 1.15.8-alpine3.13
Bumps golang from 1.15.7-alpine3.13 to 1.15.8-alpine3.13.

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-05 07:00:52 +00:00
Maksim Nabokikh dd4a62e645 Apply suggestions from code review
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-02-04 21:17:30 +04:00
m.nabokikh 7f744598f5 Add detailed description to docker-entrypoint.sh
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-30 14:54:17 +04:00
m.nabokikh 3241fd4ae2 Move downloading gomplate to separate stage
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:40 +04:00
m.nabokikh a6cb627763 Add docker build args
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:05 +04:00
Maksim Nabokikh 226c91df06 Apply suggestions from code review
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:05 +04:00
m.nabokikh d43053e11c Download gomplate during building phase
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:05 +04:00
m.nabokikh e13aac4963 Switch to gomplate
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:05 +04:00
m.nabokikh 891fa1785f Remove entrypoint.sh, add config template example
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:05 +04:00
m.nabokikh 7784a4727c feat: Add dockerize to the Dex docker image
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-29 13:48:05 +04:00
dependabot[bot] 64e47cc22a
Merge pull request #1966 from dexidp/dependabot/docker/alpine-3.13.1 2021-01-29 09:13:38 +00:00
dependabot[bot] b598eca785
chore(deps): bump alpine from 3.13.0 to 3.13.1
Bumps alpine from 3.13.0 to 3.13.1.

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-29 07:04:44 +00:00
Márk Sági-Kazár 31f26735ff
Merge pull request #1957 from dexidp/config
Add new configuration examples
2021-01-28 19:27:45 +01:00
Mark Sagi-Kazar 27a43669a7
chore: add new development configuration
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-28 18:54:38 +01:00
Mark Sagi-Kazar e9b83e0a45
chore: add a new basic config example
The dev config example is used for documentation purposes,
but it's also full of development specific configuration.

This change adds a new config example that should serve
as a default, empty config as well as documentation.

The dev example should only contain the relevant configuration.

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-28 18:54:32 +01:00
Maksim Nabokikh 65a8bf2af3 feat: graceful shutdown fixes
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-26 16:45:10 +04:00
m.nabokikh f82c217e12 feat: graceful shutdown
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-26 12:16:30 +04:00
m.nabokikh d6b5105d9b fix: check code presence
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-25 18:50:36 +04:00
m.nabokikh a7667dff38 fix: remove empty RefreshTokens
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-25 14:53:19 +04:00
Stephen Augustus c41f970b16
Merge pull request #1958 from dexidp/chore-docker-volume
Generic docker improvements
2021-01-25 04:07:43 -05:00
Mark Sagi-Kazar bb651cc664
chore(docker): copy web assets to the filesystem root
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:56:53 +01:00
Mark Sagi-Kazar c939e51cb4
chore(docker): drop no-op workdir
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:49:08 +01:00
Mark Sagi-Kazar d2d0d4a1ea
chore(docker): reorder instructions in build image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:48:35 +01:00
Mark Sagi-Kazar a33669e3ec
chore(docker): move user to the end
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:48:32 +01:00
Mark Sagi-Kazar 7b2972a04b
chore(docker): copy web assets from the build image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:47:40 +01:00
Mark Sagi-Kazar 89f737329b
chore(docker): rename the builder image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:47:40 +01:00
Mark Sagi-Kazar feb90bd1b1
chore(docker): update builder image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-24 00:47:36 +01:00
Márk Sági-Kazár f7156c26eb
Merge pull request #1956 from flant/request-not-supported
fix: unsupported request parameter error
2021-01-23 19:43:22 +01:00
Mark Sagi-Kazar b19fe5b49d
chore(docker): move copying the dex binary up in Dockerfile
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-23 19:07:25 +01:00
Mark Sagi-Kazar fade69b5ae
chore(docker): relocate module files in the final image
/usr/local/src sounds like a better place than /opt

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-23 19:07:15 +01:00
Mark Sagi-Kazar e49f6661f3
chore(docker): add a data directory for dex to var
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-23 19:07:08 +01:00
Márk Sági-Kazár 186a719ecb
Merge pull request #1948 from flant/add-cache-headers
Add Cache-control headers to token responses
2021-01-23 14:13:51 +01:00
Márk Sági-Kazár 7cf43fdc7e
Merge pull request #1951 from flant/update-descovery-endpoint-info
fix: update auth methods and claims from discovery endpoint
2021-01-23 14:10:19 +01:00
m.nabokikh 30a5dade0f fix: unsupported request parameter error
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-22 18:01:24 +04:00
m.nabokikh 123185c456 fix: return invalid_grant error for invalid or expired auth codes
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-21 01:31:38 +04:00
m.nabokikh 283a87855a fix: update auth methods and claims in discovery endpoint
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-20 15:15:30 +04:00
dependabot[bot] 369e16e97e
Merge pull request #1950 from dexidp/dependabot/docker/golang-1.15.7-alpine3.12 2021-01-20 08:01:21 +00:00
dependabot[bot] 0ed680071c
chore(deps): bump golang from 1.15.6-alpine3.12 to 1.15.7-alpine3.12
Bumps golang from 1.15.6-alpine3.12 to 1.15.7-alpine3.12.

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-20 06:53:12 +00:00
Márk Sági-Kazár a55de6c991
Merge pull request #1949 from flant/use-constants-for-errors
Use constants to form oauth2 error responses
2021-01-19 11:58:20 +01:00
m.nabokikh bb503dbd81 Use constants in errors
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-18 14:54:43 +04:00
m.nabokikh a7978890c7 Add Cache-control headers to token responses
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-18 11:13:28 +04:00
Martin Heide c12c340e3c Extend OpenLDAP example for LDAPS
Signed-off-by: Martin Heide <martin.heide@faro.com>
2021-01-15 17:05:39 +00:00
m.nabokikh b2e9f67edc Enable unparam, prealloc, sqlclosecheck linters
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-15 19:29:13 +04:00
dependabot[bot] 3650fe2287
Merge pull request #1945 from dexidp/dependabot/docker/alpine-3.13.0 2021-01-15 09:23:00 +00:00
dependabot[bot] dbd42ae777
chore(deps): bump alpine from 3.12.3 to 3.13.0
Bumps alpine from 3.12.3 to 3.13.0.

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-15 07:20:22 +00:00
Mark Sagi-Kazar f9b3d8fcb4
docs(readme): fix links
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-15 02:08:23 +01:00
Mark Sagi-Kazar a73670488c
docs(readme): fix maintainer link
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-15 02:06:17 +01:00
Mark Sagi-Kazar 5bd55f6ee7
chore(deps): update dependabot config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-15 00:22:52 +01:00
dependabot[bot] 6400052265
Merge pull request #1930 from dexidp/dependabot/docker/alpine-3.12.3 2021-01-14 22:49:15 +00:00
dependabot[bot] a255bda911
Merge pull request #1935 from dexidp/dependabot/go_modules/github.com/stretchr/testify-1.7.0 2021-01-14 22:48:35 +00:00
Márk Sági-Kazár 566ba720a2
Merge pull request #1936 from dexidp/update-actions
ci: update workflow config
2021-01-14 23:45:50 +01:00
Mark Sagi-Kazar 2cc8b2fe3c
ci: update workflow config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 23:31:53 +01:00
dependabot[bot] cb2c85b2a5
chore(deps): bump github.com/stretchr/testify from 1.6.1 to 1.7.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.6.1 to 1.7.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.6.1...v1.7.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-14 22:30:40 +00:00
Márk Sági-Kazár 5bfe1a5d22
Merge pull request #1925 from dexidp/update-dependencies
Update project dependencies
2021-01-14 23:27:40 +01:00
dependabot[bot] 1866a7acc8
chore(deps): bump alpine from 3.12.2 to 3.12.3
Bumps alpine from 3.12.2 to 3.12.3.

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-14 22:20:48 +00:00
Márk Sági-Kazár bf23d392b6
Merge pull request #1928 from dexidp/dependabot
Add dependabot
2021-01-14 23:20:18 +01:00
Mark Sagi-Kazar d51937b62d
chore(docker): update alpine image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 22:33:16 +01:00
Mark Sagi-Kazar dc40d5b0df
chore(deps): add dependabot config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 22:32:58 +01:00
Márk Sági-Kazár c952ba743d
Merge pull request #1927 from dexidp/update-links
Update links pointing to slack channel
2021-01-14 21:17:22 +01:00
Mark Sagi-Kazar 040950341d
chore(docs): update links pointing to slack channel
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 20:52:48 +01:00
Mark Sagi-Kazar 3c686b24ce
chore(deps): update dependencies
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 19:20:11 +01:00
Márk Sági-Kazár afba7577bb
Merge pull request #1918 from flant/log-device-flow-gc
fix: log device flow entities GC result if no auth entities collected
2021-01-14 18:02:20 +01:00
Márk Sági-Kazár ccbf6c6e0f
Merge pull request #1921 from dexidp/feat-add-flags
Add flags for bind address config options
2021-01-14 17:54:38 +01:00
Márk Sági-Kazár 8515dfb35d
Merge pull request #1923 from dexidp/cleanup
Cleanup
2021-01-14 17:54:21 +01:00
Mark Sagi-Kazar e2ed31656e
chore: add editorconfig for makefiles
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 17:30:25 +01:00
Mark Sagi-Kazar 0a88483409
chore: rename the docs directory
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 17:30:04 +01:00
Mark Sagi-Kazar 48d78ec0ab
chore: improve docker-compose setup
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 17:30:02 +01:00
Mark Sagi-Kazar 0e1bc202c6
chore: reformat docker-compose.yaml
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 16:28:00 +01:00
Mark Sagi-Kazar cff4a11b41
chore: cleanup ignore files
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 16:27:17 +01:00
Mark Sagi-Kazar 97606bd623
refactor: stop using GOPATH for building Dex image
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 16:24:55 +01:00
Mark Sagi-Kazar 757a1eded5
chore: change email address for Nandor
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 16:23:46 +01:00
Mark Sagi-Kazar e954e3f9d8
chore: move DCO to .github for now
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 16:10:00 +01:00
Mark Sagi-Kazar 49c9c607c9
chore: remove notice file
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 16:09:23 +01:00
Mark Sagi-Kazar 6742008fc2
refactor: version command
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 15:55:07 +01:00
Mark Sagi-Kazar c55d84b5d2
feat: add flags for bind address config options
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 15:50:19 +01:00
Mark Sagi-Kazar cdefd1f788
refactor: serve command
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-14 15:30:03 +01:00
Stephen Augustus a189c25a6e
Merge pull request #1916 from dexidp/update-oidc-lib
Update OIDC lib
2021-01-13 14:35:58 -05:00
Mark Sagi-Kazar 7775a7e27a
Update oidc library in example app
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-13 19:56:23 +01:00
Mark Sagi-Kazar b8ac640c4f
Update oidc library
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-13 19:56:09 +01:00
Márk Sági-Kazár 1fbfaa9951
Merge pull request #1908 from bnu0/bnu-fix-etcd-pkce
Fix the etcd PKCE AuthCode deserialization
2021-01-13 19:43:02 +01:00
Márk Sági-Kazár 827889ee05
Merge pull request #1915 from flant/code-of-conduct
Update CODE_OF_CONDUCT.md
2021-01-13 11:51:13 +01:00
m.nabokikh eb10135774 Move CODE_OF_CONDUCT.md to .gitlab folder
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-13 14:33:50 +04:00
Maksim Nabokikh 35da73de38
chore: add frontend section to dev config (#1913)
* chore: add frontend section to dev config

Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-12 19:20:38 +01:00
m.nabokikh 8fdb207848 Update CODE_OF_CONDUCT.md
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-12 22:17:32 +04:00
Erica Taylor ba47aaba86 microsoft: Support setting the prompt type
Signed-off-by: Erica Taylor <ricky@wellplayed.games>
2021-01-11 11:48:58 +00:00
m.nabokikh 30c3d78365 fix: log device flow entities GC result if no auth entities collected
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-11 12:33:10 +04:00
m.nabokikh f2f19fa0d7 chore: make example-app form prettier
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2021-01-07 23:10:16 +04:00
Márk Sági-Kazár 4f326390aa
Merge pull request #1839 from seuf/authproxy-header-configuration
Allow configuration of returned auth proxy header
2021-01-07 10:40:57 +01:00
Márk Sági-Kazár ee50c09313
Merge pull request #1888 from VF-mbrauer/UPN-Lowercase
Added the possibility to activate lowercase for UPN-Strings
2021-01-06 20:36:43 +01:00
Maik Brauer 0d53fa2f42 Merge branch 'UPN-Lowercase' of https://github.com/VF-mbrauer/dex into UPN-Lowercase
Signed-off-by: Maik Brauer <maik.brauer@vodafone.com>
2021-01-05 21:48:02 +01:00
Maik Brauer c55f17ea64 Adapted recommendation from Maintainer for PR #1888
Signed-off-by: Maik Brauer <maik.brauer@vodafone.com>
2021-01-05 21:36:41 +01:00
Maik Brauer 4d246bc9dc Adapted recommendation from Maintainer for PR #1888
Signed-off-by: Maik Brauer <maik.brauer@vodafone.com>
2021-01-05 17:12:45 +01:00
Mark Sagi-Kazar fc7f1ef6cc
Run go mod tidy
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-05 15:29:15 +01:00
Benjamin Ullian b45a501c99 add PKCE roundtrip to conformance test
Signed-off-by: Benjamin Ullian <bnu@tumblr.com>
2021-01-04 22:50:05 -05:00
Benjamin Ullian 62abddca7d fix etcd pkce authcode json deserialization
Signed-off-by: Benjamin Ullian <bnu@tumblr.com>
2021-01-04 22:15:44 -05:00
Maik Brauer eb9ef3b0ec Added the possibility to acticate lowercase for UPN-Strings
Signed-off-by: Maik Brauer <maik.brauer@vodafone.com>
2021-01-04 15:07:14 +01:00
Mark Sagi-Kazar a825a22f7a
Point question link to qa category
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2021-01-03 00:35:35 +01:00
Márk Sági-Kazár e3383564b9
Merge pull request #1898 from parrotmac/ip/doc-typo
docs: Correct tlsClientCA example reference
2021-01-01 16:28:46 +01:00
Márk Sági-Kazár 01f7bf73a0
Merge pull request #1891 from jsoref/spelling
Spelling
2021-01-01 16:27:49 +01:00
Márk Sági-Kazár 4f0744ce80
Merge pull request #1902 from faro-oss/feature/no-expand-env
Allow to disable os.ExpandEnv for storage + connector configs by env variable DEX_EXPAND_ENV = false
2021-01-01 16:21:56 +01:00
Martin Heide 4cb5577e11 Allow to disable os.ExpandEnv for storage + connector configs by env variable DEX_EXPAND_ENV = false
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-12-30 20:11:18 +00:00
Márk Sági-Kazár 31353d2ccf
Merge pull request #1901 from WorldProgrammingLtd/upgrade-deps
fix: update dependencies to avoid some CVEs.
2020-12-29 14:56:40 +01:00
Alastair Houghton 17c00e5a58 fix: update dependencies to avoid some CVEs.
Updated hcsshim and Gorilla dependencies to avoid some CVEs.

Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2020-12-29 12:20:24 +00:00
IM CHAECHEOL f2fcb2c989 update example/k8s/dex.yaml
Signed-off-by: IM CHAECHEOL <dlacocjf32@gmail.com>
2020-12-28 21:57:27 +09:00
Isaac Parker 0af41fb4ca docs: Correct tlsClientCA example reference
Signed-off-by: Isaac Parker <parrotmac@gmail.com>
2020-12-28 01:58:02 -07:00
Márk Sági-Kazár bae6bbb171
Merge pull request #1858 from flant/light-dark-theme
feat: Change default themes to light/dark
2020-12-22 12:33:31 +01:00
m.nabokikh 1e88cca59a Make dark theme even darker, add fallback for legacy themes
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-12-22 11:07:28 +04:00
Márk Sági-Kazár 2b9ef8058b
Merge pull request #1887 from ericchiang/saml
README: add warning to the SAML connector
2020-12-20 04:59:38 +01:00
Josh Soref 84e9cb6947 spelling: verified
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 86526cd030 spelling: uri
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref fecd979bab spelling: update
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 5d659a108c spelling: templates
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref b155f66785 spelling: storage
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 43b95a2d28 spelling: signer
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 22de6da60b spelling: signatures
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 97d3e8fa7f spelling: signature
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 801fd64a11 spelling: serviceaccount
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 3f8fdbf314 spelling: rotator
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 791ad900cb spelling: reuse
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 8476e5acc0 spelling: requested
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref c79b40ad56 spelling: register
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:29 -05:00
Josh Soref 6790aea260 spelling: referenceable
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref d3d447fcf1 spelling: readable
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref 119e4d66c6 spelling: indices
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref 91e153780d spelling: including
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref 040abe5dc1 spelling: impersonate
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref 1bfe2f6db2 spelling: habit
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref a996c4ba54 spelling: guaranteeing
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref a8851ceb1b spelling: generated
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref 3352e4e74f spelling: from
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:26 -05:00
Josh Soref 8905fb4a65 spelling: existing
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:53:21 -05:00
Josh Soref 0288864da7 spelling: collision
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-12-19 22:12:13 -05:00
Thierry Sallé e164bb381e Apply suggestions from code review
Co-authored-by: Márk Sági-Kazár <sagikazarmark@users.noreply.github.com>
Signed-off-by: seuf <seuf76@gmail.com>
2020-12-17 16:50:00 +01:00
seuf a1c7198738 Rename config header to userHeader
Signed-off-by: seuf <seuf76@gmail.com>
2020-12-17 16:50:00 +01:00
seuf f19bccfc92 Allow configuration of groups for authproxy
Signed-off-by: seuf <seuf76@gmail.com>
2020-12-17 16:50:00 +01:00
seuf a12a919d3e Allow configuration of returned auth proxy header
Signed-off-by: seuf <seuf76@gmail.com>
2020-12-17 16:50:00 +01:00
Eric Chiang 01befc00ff README: add warning to the SAML connector
Signed-off-by: Eric Chiang <ericchiang@google.com>
2020-12-16 09:07:38 -08:00
Márk Sági-Kazár 31839549cd
Merge pull request #1886 from flant/adopters-add-flant
Add Flant to ADOPTERS.md
2020-12-15 12:56:06 +01:00
m.nabokikh da4fb97912 Add flant to ADOPTERS.md
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-12-15 10:47:24 +04:00
Márk Sági-Kazár 10c6eb3186
Merge pull request #1882 from dexidp/cleanup
Cleanup
2020-12-14 16:06:19 +01:00
Mark Sagi-Kazar 41c5916b97
chore: add discussion link to issue template config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-12-14 15:46:02 +01:00
Mark Sagi-Kazar 2c8fb8a3f2
chore: change my email address to my personal one
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-12-14 15:15:48 +01:00
Mark Sagi-Kazar 893413ac4f
chore: keep issue and pr templates in sync
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-12-14 15:14:00 +01:00
Stephen Augustus 0f9e2888ab
Merge pull request #1881 from justaugustus/cleanup
Update image versions, add release notes block, update guidance on reporting security issues
2020-12-14 03:40:49 -05:00
Stephen Augustus 8ed9ef8ad8 .github: Add release notes block to pull request template
Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-12-14 03:23:15 -05:00
Stephen Augustus c742b2a40a Update image versions
- golang:1.15.6-alpine3.12
- postgres:10.15
- gcr.io/etcd-development/etcd:v3.4.9

Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-12-14 03:23:15 -05:00
Stephen Augustus 2b0f47306b README.md: Use maintainers list for reporting security issues
Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-12-14 03:23:15 -05:00
Stephen Augustus 324b1c886b
Merge pull request from GHSA-m9hp-7r99-94h5
connector/saml: Validate XML roundtrip data before processing request
2020-12-14 03:21:11 -05:00
Stephen Augustus 6e5176822b
Merge pull request #1880 from dexidp/sr/remove-srenatus-from-maintainers
MAINTAINERS: drop @srenatus
2020-12-08 07:42:51 -05:00
Stephen Augustus 57640cc7a9 connector/saml: Validate XML roundtrip data before processing request
Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-12-08 07:26:48 -05:00
Stephan Renatus 706c3bba68 MAINTAINERS: drop @srenatus
This reflects that I currently don't have time to contribute to this fine
project. It's been fun, thanks a lot to all the current and past maintainers!

Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
2020-12-08 10:35:41 +01:00
Stephen Augustus a136ab6969 go.mod: Update goxmldsig to v1.1.0
Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-12-07 19:00:25 -05:00
Márk Sági-Kazár 845fb1e0f0
Merge pull request #1878 from pbalogh-sa/docs/fix-links
docs: fix broken links
2020-12-04 13:14:58 +01:00
Peter Balogh 64d7156d5f
docs: fix broken links
Signed-off-by: Peter Balogh <p.balogh.sa@gmail.com>
2020-12-04 08:57:30 +01:00
Márk Sági-Kazár 5a87bc5d59
Merge pull request #1874 from dexidp/add-codeql
Add CodeQL
2020-12-02 14:42:56 +01:00
Chris Aniszczyk ac43200665
Add CodeQL
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
2020-12-01 12:17:28 -08:00
Stephen Augustus 33e13c2aad
Fully automate dev setup with Gitpod (#1868)
* Fully automate dev setup with Gitpod

This commit implements a fully-automated development setup using Gitpod.io, an
online IDE for GitHub and GitLab that enables Dev-Environments-As-Code.
This makes it easy for anyone to get a ready-to-code workspace for any branch,
issue or pull request almost instantly with a single click.

Signed-off-by: justaugustus <foo@agst.us>
2020-11-20 01:00:16 +01:00
Márk Sági-Kazár d97d6de88c
Merge pull request #1863 from faro-oss/feature/go-mod-dockerimage
Copy module dependencies to Docker image for CVE scanning / dependency analysis
2020-11-19 17:57:55 +01:00
Martin Heide f7efe49e5e Copy module dependencies to Docker image for CVE scanning / dependency analysis
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-11-18 12:55:20 +00:00
Márk Sági-Kazár 6ca0cbc857
Merge pull request #1866 from pachyderm/actgardner/split-sqlite
Don't try to build sqlite storage when cgo isn't enabled
2020-11-18 10:41:23 +01:00
A Gardner 19d7edd530 Don't try to build sqlite when cgo isn't enabled
Signed-off-by: A Gardner <3100188+actgardner@users.noreply.github.com>
2020-11-17 17:48:40 -05:00
m.nabokikh bcaddd4354 feat: Change default themes to light/dark
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-11-08 02:12:06 +04:00
Márk Sági-Kazár 71bbbee075
Merge pull request #1856 from dexidp/improve-docker-build
Improve docker build
2020-11-05 15:53:54 +01:00
Mark Sagi-Kazar 9b629b6568
Fix docker workflow name
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 15:35:31 +01:00
Mark Sagi-Kazar 0520465207
Separate docker job again
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 15:34:18 +01:00
Mark Sagi-Kazar b580ffad70
Remove cache for now
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 15:30:17 +01:00
Mark Sagi-Kazar 4c86a5e7fe
Ignore files from docker context
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 14:46:32 +01:00
Mark Sagi-Kazar 85239d515d
Download dependencies in advance
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 14:26:39 +01:00
Mark Sagi-Kazar 10ac93d42b
Add docker layer caching
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 14:24:35 +01:00
Mark Sagi-Kazar 5cc8b562ec
Run build on ubuntu-latest
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 14:21:18 +01:00
Mark Sagi-Kazar b9bc0b8b11
Remove unused workflow
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 14:12:16 +01:00
Mark Sagi-Kazar b971415f0c
Improve Docker build
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 14:11:59 +01:00
Mark Sagi-Kazar 6500fdbdd1
Improve issue templates
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 11:44:16 +01:00
Mark Sagi-Kazar d62f312402
Improve issue templates
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 11:37:58 +01:00
Mark Sagi-Kazar fb282c3506
add documentation to contact links
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 11:36:38 +01:00
Mark Sagi-Kazar 1e14a33553
fix: missing frontmatter in issue templates
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 11:34:29 +01:00
Mark Sagi-Kazar ef7e9e5c99
Fix issue template config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-05 11:32:37 +01:00
Márk Sági-Kazár 170794725d
Merge pull request #1822 from faro-oss/feature/redirect-uris-for-public-clients
Allow public clients (e.g. SPAs using implicit flow or PKCE) to have redirect URLs other than localhost
2020-11-05 11:02:25 +01:00
Márk Sági-Kazár 6fcd9b4887
Merge pull request #1852 from flant/description_templates
chore: Add description templates
2020-11-05 10:43:27 +01:00
Márk Sági-Kazár 40409eafe8
Merge pull request #1847 from flant/retry-kubernetes-update-requests
feat: Retry Kubernetes update requests
2020-11-05 10:41:58 +01:00
Márk Sági-Kazár bca77245df
Merge pull request #1853 from dexidp/linter-config
Linter config
2020-11-05 10:33:19 +01:00
Mark Sagi-Kazar 349832b380
Run fixer
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-03 20:52:14 +01:00
Mark Sagi-Kazar 84ea790885
Enable gci and gofumpt
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-03 20:52:14 +01:00
Mark Sagi-Kazar cafea292ca
Update linter
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-03 20:52:13 +01:00
Mark Sagi-Kazar 3841f05ba4
Update linter config
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-03 20:51:29 +01:00
Mark Sagi-Kazar ed7b71a190
chore: add editorconfig
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-11-03 20:37:38 +01:00
Martin Heide 162073b33e No longer allow desktop/mobile redirect URIs implicitly if RedirectURIs is set
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-11-02 14:05:47 +00:00
Martin Heide c15e2887bc Add oob, device and localhost redirect URI tests
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-11-02 13:41:56 +00:00
Martin Heide 1ea481bb73 Fix gofmt in oauth2_test.go
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-11-02 12:52:52 +00:00
Martin Heide b894d9c888 Allow public clients (e.g. using implicit flow or PKCE) to have redirect URIs configured
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-11-02 12:52:10 +00:00
m.nabokikh 7198f17d0e chore: Add description templates
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-11-02 10:52:08 +04:00
m.nabokikh be378dd9a7 feat: Retry Kubernetes update requests
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-28 12:46:58 +04:00
Márk Sági-Kazár 6cdbb59406
Merge pull request #1845 from flant/minor-linter-fixes
fix: Minor style fixes after merging PKCE implementation
2020-10-26 21:37:30 +01:00
m.nabokikh a5ad5eaf08 fix: Minor style fixes after merging PKCE implementation
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-26 23:20:33 +04:00
Bernd Eckstein b5519695a6
PKCE implementation (#1784)
* Basic implementation of PKCE

Signed-off-by: Tadeusz Magura-Witkowski <tadeuszmw@gmail.com>

* @mfmarche on 24 Feb: when code_verifier is set, don't check client_secret

In PKCE flow, no client_secret is used, so the check for a valid client_secret
would always fail.

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* @deric on 16 Jun: return invalid_grant when wrong code_verifier

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Enforce PKCE flow on /token when PKCE flow was started on /auth
Also dissallow PKCE on /token, when PKCE flow was not started on /auth

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* fixed error messages when mixed PKCE/no PKCE flow.

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* server_test.go: Added PKCE error cases on /token endpoint

* Added test for invalid_grant, when wrong code_verifier is sent
* Added test for mixed PKCE / no PKCE auth flows.

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* cleanup: extracted method checkErrorResponse and type TestDefinition

* fixed connector being overwritten

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* /token endpoint: skip client_secret verification only for grand type authorization_code with PKCE extension

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Allow "Authorization" header in CORS handlers

* Adds "Authorization" to the default CORS headers{"Accept", "Accept-Language", "Content-Language", "Origin"}

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Add "code_challenge_methods_supported" to discovery endpoint

discovery endpoint /dex/.well-known/openid-configuration
now has the following entry:

"code_challenge_methods_supported": [
  "S256",
  "plain"
]

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Updated tests (mixed-up comments), added a PKCE test

* @asoorm added test that checks if downgrade to "plain" on /token endpoint

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* remove redefinition of providedCodeVerifier, fixed spelling (#6)

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>
Signed-off-by: Bernd Eckstein <HEllRZA@users.noreply.github.com>

* Rename struct CodeChallenge to PKCE

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* PKCE: Check clientSecret when available

In authorization_code flow with PKCE, allow empty client_secret on /auth and /token endpoints. But check the client_secret when it is given.

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Enable PKCE with public: true

dex configuration public on staticClients now enables the following behavior in PKCE:
- Public: false, PKCE will always check client_secret. This means PKCE in it's natural form is disabled.
- Public: true, PKCE is enabled. It will only check client_secret if the client has sent one. But it allows the code flow if the client didn't sent one.

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Redirect error on unsupported code_challenge_method

- Check for unsupported code_challenge_method after redirect uri is validated, and use newErr() to return the error.
- Add PKCE tests to oauth2_test.go

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Reverted go.mod and go.sum to the state of master

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Don't omit client secret check for PKCE

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Allow public clients (e.g. with PKCE) to have redirect URIs configured

Signed-off-by: Martin Heide <martin.heide@faro.com>

* Remove "Authorization" as Accepted Headers on CORS, small fixes

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Revert "Allow public clients (e.g. with PKCE) to have redirect URIs configured"

This reverts commit b6e297b78537dc44cd3e1374f0b4d34bf89404ac.

Signed-off-by: Martin Heide <martin.heide@faro.com>

* PKCE on client_secret client error message

* When connecting to the token endpoint with PKCE without client_secret, but the client is configured with a client_secret, generate a special error message.

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* Output info message when PKCE without client_secret used on confidential client

* removes the special error message

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

* General missing/invalid client_secret message on token endpoint

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>

Co-authored-by: Tadeusz Magura-Witkowski <tadeuszmw@gmail.com>
Co-authored-by: Martin Heide <martin.heide@faro.com>
Co-authored-by: M. Heide <66078329+heidemn-faro@users.noreply.github.com>
2020-10-26 11:33:40 +01:00
Márk Sági-Kazár 2a282860fa
Merge pull request #1836 from lcostea/master
feat: reduce image size without apk cache
2020-10-18 18:21:39 +02:00
Márk Sági-Kazár c82d21b155
Merge pull request #1837 from flant/bump-golangci-lint-and-fix-some-linters
fix: Bump golangci-lint version and fix some linter's problems
2020-10-18 16:05:57 +02:00
m.nabokikh 1d83e4749d Add gocritic
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-18 01:54:27 +04:00
m.nabokikh 4d63e9cd68 fix: Bump golangci-lint version and fix some linter's problems
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-18 01:02:29 +04:00
Liviu Costea 83673fb320 feat: reduce image size without apk cache
Signed-off-by: Liviu Costea <email.lcostea@gmail.com>
2020-10-16 19:52:21 +03:00
Nándor István Krácser 28b2350cd2
Merge pull request #1835 from flant/kubernetes-client-keys-conflicts-fix
fix: Handle Kubernetes API conflicts properly for signing keys
2020-10-13 15:16:19 +02:00
Márk Sági-Kazár 9c026107e6
Merge pull request #1830 from WorldProgrammingLtd/fix-1813
fix: log errors from login during password grant
2020-10-13 09:21:44 +02:00
m.nabokikh 4801b2c975 fix: Handle kubernetes API conflicts properly for signing keys
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-12 09:15:00 +03:00
Tom Quarendon 4da93e75fc fix: log errors from login during password grant
Issues: #1813
Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2020-10-07 13:36:42 +01:00
Nate W 3f41b26fb9
[WIP] Removing .md files as a part of the Dex IdP Documentation migration. (#1810)
* Removing .md files as a part of the Dex IdP Documentation migration.

https://github.com/dexidp/dex/issues/1761
https://github.com/dexidp/website/issues/2
Signed-off-by: Nate Waddington <nwaddington@cncf.io>

* Updating README.md links after .md files removal.

Signed-off-by: Nate Waddington <nwaddington@cncf.io>

* Updating URL as per PR feedback. dexidp.org -> dexidp.io

Signed-off-by: Nate Waddington <nwaddington@cncf.io>

* removing errant ")"

Signed-off-by: Nate Waddington <nwaddington@cncf.io>
2020-10-06 18:02:40 +02:00
Márk Sági-Kazár d1f599dd32
Merge pull request #1819 from al45tair/cors-auth
fix: allow Authorization header when doing CORS
2020-10-06 14:35:21 +02:00
Márk Sági-Kazár a28f5bb218
Merge pull request #1821 from al45tair/fix-1820
fix: copy the "web" directory.
2020-10-05 17:24:51 +02:00
Alastair Houghton 3288450b3e fix: copy the "web" directory.
The Dockerfile was changed to do

    COPY web .

which is unfortunate because that means copy the *contents* of the directory
"web", rather than copying the directory itself which is what the author
intended.

Issues: #1820
Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2020-10-05 15:52:30 +01:00
Alastair Houghton 9187aa669d fix: allow Authorization header when doing CORS
The Authorization header needs to be allowed when doing CORS because
otherwise /userinfo can't work.  It isn't one of the headers
explicitly allowed by default by Gorilla, so we have to call
handlers.AllowedHeaders() to specify it.

Issues: #1532
Signed-off-by: Alastair Houghton <alastair@alastairs-place.net>
2020-10-05 15:01:54 +01:00
Márk Sági-Kazár 828a1c6ec2
Merge pull request #1688 from flant/bitbucket-groups
feat: Add team groups support to bitbucket connector
2020-10-04 20:08:49 +02:00
m.nabokikh ec66cedfcc feat: Add team groups support to bitbucket connector
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-04 20:50:59 +03:00
Márk Sági-Kazár 3e5ff2f853
Merge pull request #1815 from dexidp/fix-docker-login
ci: do not login to docker registry in PRs
2020-10-04 15:18:44 +02:00
Mark Sagi-Kazar 4a1fd77166
ci: do not login to docker registry in PRs
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-10-04 15:01:45 +02:00
Márk Sági-Kazár 3b385ecf4a
Merge pull request #1812 from flant/bitbucket-replace-teams-endpoint
fix: Replace deprecated teams endpoint in bitbucket connector
2020-10-04 14:27:14 +02:00
m.nabokikh 4b94469547 fix: Replace teams endpoint for bitbucket connector
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-10-03 20:30:23 +03:00
Márk Sági-Kazár d4c3a3505d
Merge pull request #1802 from concourse/pr/static-public-key-sync
Add constructor for static key strategy
2020-10-01 22:19:15 +02:00
Rui Yang bd2234cd12 Add constructor for static key strategy
Co-authored-by: Josh Winters <jwinter@pivotal.io>
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-10-01 15:32:23 -04:00
Márk Sági-Kazár 9781e56ba5
Merge pull request #1690 from flant/fix-relative-url
Fix templates which asset path points to external URL
2020-09-29 19:47:38 +02:00
Márk Sági-Kazár 641615ff58
Merge pull request #1806 from dexidp/go115
chore: update Go to 1.15
2020-09-28 00:45:39 +02:00
Mark Sagi-Kazar f3fc0c5395
chore: update Go to 1.15
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-09-28 00:22:47 +02:00
Márk Sági-Kazár 5807011b6a
Merge pull request #1805 from dexidp/fix-dockerhub-typo
fix: typo in environment variables introduced in #1781
2020-09-28 00:22:17 +02:00
Mark Sagi-Kazar 8a1a1b8b5d
fix: typo in environment variables introduced in #1781
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-09-27 23:56:02 +02:00
MIℂHΛΞL FѲRИΛRѲ 549b67bccd
Adding architecture support for arm/arm64/amd64 docker images (#1781)
add multi-arch image support for armv7/arm64/amd64 architectures
2020-09-27 23:47:39 +02:00
Johan Tordsson c64ff34d11
Add Elastisys to Adopters (#1803)
Added description Elastisys use of Dex in Compliant Kubernetes.
2020-09-18 16:40:59 +02:00
Márk Sági-Kazár 458059cc89
Merge pull request #1708 from tkleczek/fix-overwriting-connector-in-authreq
abort connector login if connector was already set #1707
2020-09-16 17:49:04 +02:00
Márk Sági-Kazár a64e7c2986
Merge pull request #1769 from batara666/master
ldap.go: drop else on returned if block
2020-09-16 17:47:52 +02:00
Márk Sági-Kazár e837475ca6
Merge pull request #1795 from lzeng27/master
update documentation
2020-09-09 17:47:18 +02:00
Linda Zeng 6745af7747 updated docs
Signed-off-by: Linda Zeng <linda.zeng@blackrock.com>
2020-09-09 11:01:14 -04:00
Márk Sági-Kazár d4a67e43fa
Merge pull request #1794 from dexidp/fix-example-app
Fix building the example app
2020-09-09 14:00:27 +02:00
Mark Sagi-Kazar 63098fe9fe
Fix building the example app
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-09-09 13:50:19 +02:00
Márk Sági-Kazár ca0a9e821e
Merge pull request #1634 from concourse/pr/oidc-username-key-sync
Support username, email and groups claim in OIDC connector
2020-09-08 19:19:44 +02:00
Rui Yang 058202d007 revert changes for user id and user name
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-09-08 13:12:59 -04:00
Rui Yang 0494993326 update oidc documentation and email claim err msg
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-09-08 10:03:57 -04:00
Márk Sági-Kazár 07dddc7b0e
Merge pull request #1791 from onkarbhat/adopters_kasten
Add Kasten as an adopter of Dex.
2020-09-08 09:18:05 +02:00
Onkar Bhat c489a074c1 Add Kasten as an adopter of Dex. 2020-09-07 16:39:21 -07:00
Tomasz Kleczek b1311baa3c abort connector login if connector was already set #1707
Signed-off-by: Tomasz Kleczek <tomasz.kleczek@gmail.com>
2020-08-29 17:19:14 +02:00
Joel Speed 336c73c0a2
Merge pull request #1706 from justin-slowik/device_flow
Implementing the OAuth2 Device Authorization Grant
2020-08-28 11:35:46 +01:00
Joel Speed a24f73c19f
Merge pull request #1780 from tom-haines/master
Minor documentation tweaks re storage.md
2020-08-14 11:04:53 +01:00
Thomas Haines d39b77bda3 Minor documentation tweaks re storage.md
Signed-off-by: Thomas Haines <thomas.haines@gmail.com>
2020-08-14 16:51:00 +08:00
Rui Yang 41207ba265 Combine #1691 and #1776 to unify OIDC provider claim mapping
add tests for groups key mapping

Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Scott Lemmon a783667c57 Add groupsClaimMapping to the OIDC connector
The groupsClaimMapping setting allows one to specify which claim to pull
group information from the OIDC provider.  Previously it assumed group
information was always in the "groups" claim, but that isn't the case
for many OIDC providers (such as AWS Cognito using the "cognito:groups"
claim instead)

Signed-off-by: Scott Lemmon <slemmon@aurora.tech>
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Cyrille Nofficial 61312e726e Add parameter configuration to override email claim key
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Rui Yang 52c39fb130 check if upstream contains preferrend username claim first
Signed-off-by: Rui Yang <ryang@pivotal.io>
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Rui Yang 4812079647 add tests when preferred username key is not set
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Rui Yang d9afb7e59c default to preferred_username claim
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Josh Winters 9a4e0fcd00 Make OIDC username key configurable
Signed-off-by: Josh Winters <jwinters@pivotal.io>
Co-authored-by: Mark Huang <mhuang@pivotal.io>
Signed-off-by: Rui Yang <ruiya@vmware.com>
2020-08-11 16:26:55 -04:00
Bernd Eckstein f6cd778b60 Add c_hash to id_token, issued on /auth endpoint, when in hybrid flow
* fixed name collision (renamed hash->hashFunc)

Signed-off-by: Bernd Eckstein <Bernd.Eckstein@faro.com>
2020-07-31 12:06:19 +02:00
batara666 6499f5bfd3
ldap.go: drop else on returned if block 2020-07-27 22:27:55 +07:00
Márk Sági-Kazár 19cd9cc65c
Merge pull request #1768 from Bryji/bsolan/add-aspect-adopter
Add Aspect as adopter
2020-07-23 19:46:16 +02:00
Solan, Bryan 89c6ebafa2 Add Aspect as adopter 2020-07-23 12:36:15 -05:00
Márk Sági-Kazár ff1ed7afaa
Merge pull request #1767 from dexidp/update-api
Update API package
2020-07-23 10:44:13 +02:00
Mark Sagi-Kazar 2fa5e33ae0
Update API package
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-07-23 10:25:52 +02:00
justin-slowik 9a7926c19b Cleaned up Device Flow test log levels
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>

Remove extraneous "=" from conformance.go

Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>

Additional test for TestHandleDeviceCode

Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-21 16:01:08 -04:00
Márk Sági-Kazár a8cedc8bc3
Merge pull request #1764 from dexidp/examples
Move the example app to the examples folder
2020-07-16 09:54:43 +02:00
Mark Sagi-Kazar 6dadc26ca2
Move the example app to th examples folder
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2020-07-16 09:48:35 +02:00
Márk Sági-Kazár cb46a28c3c
Merge pull request #1762 from heidemn-faro/doc/ldap-example
[doc/example] Make LDAP example functional again by running OpenLDAP with docker-compose
2020-07-15 15:51:17 +02:00
Martin Heide 521954a3b9 Improve formatting
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-07-15 09:49:41 +00:00
Martin Heide 705cf8bb6a Rework to use docker-compose
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-07-15 09:49:23 +00:00
justin-slowik 334ecf0482 Fixes based on PR comments.
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-14 10:13:37 -04:00
Martin Heide b4d22bf1b2 Improve script logging
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-07-13 15:55:23 +00:00
Martin Heide ce337661b9 Add missing slapd.sh script from LDAP docs, and convert it to using Docker
Signed-off-by: Martin Heide <martin.heide@faro.com>
2020-07-13 15:55:23 +00:00
justin-slowik 1ea2892b79 fix merge error in config.go
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:31:44 -04:00
justin-slowik 1404477326 Updates based on dexidp pr
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:06 -04:00
justin-slowik f91f294385 gofmt
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:06 -04:00
justin-slowik 9882ea453f better support for /device/callback redirect uris with public clients.
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:06 -04:00
justin-slowik f6d8427f32 Added device flow static client to config-dev.yaml
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:05 -04:00
Justin Slowik 9c699b1028 Server integration test for Device Flow (#3)
Extracted test cases from OAuth2Code flow tests to reuse in device flow

deviceHandler unit tests to test specific device endpoints

Include client secret as an optional parameter for standards compliance

Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:05 -04:00
Justin Slowik 9bbdc721d5 Device flow token code exchange (#2)
* Added /device/token handler with associated business logic and storage tests.

Perform user code exchange, flag the device code as complete.

Moved device handler code into its own file for cleanliness.  Cleanup

* Removed PKCE code

* Rate limiting for /device/token endpoint based on ietf standards

* Configurable Device expiry

Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:05 -04:00
Justin Slowik 0d1a0e4129 Device token api endpoint (#1)
* Added /device/token handler with associated business logic and storage tests.

* Use crypto rand for user code

Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:05 -04:00
Justin Slowik 6d343e059b Generates/Stores the device request and returns the device and user codes.
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:05 -04:00
Mark Sagi-Kazar 11fc8568cb Remove vendor folder
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:25:05 -04:00
Mark Sagi-Kazar bad2a06960 Revendor dependencies
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:24:38 -04:00
krishnadurai 6698f1f80a Corrects imports after merge
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:24:25 -04:00
krishnadurai 776aa9dd53 Option to add staticPasswords from environment variables
Signed-off-by: justin-slowik <justin.slowik@thermofisher.com>
2020-07-08 16:24:25 -04:00
Nándor István Krácser 62efe7bf07
Merge pull request #1441 from jimmythedog/1440-fix-msoft-refresh-token
dexidp#1440 Add offline_access scope, if required
2020-07-08 16:13:26 +02:00
m.nabokikh 70505b258d Fix templates with asset paths that point to external URL
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-07-06 12:02:39 +04:00
Márk Sági-Kazár 1d892c6cac
Merge pull request #1750 from dexidp/api-v2-v2
API v2 v2
2020-07-03 23:03:32 +02:00
Márk Sági-Kazár 0be5232edd
Merge pull request #1748 from dexidp/go114
Build with Go 1.14
2020-07-01 14:41:49 +02:00
Márk Sági-Kazár 04c137e594
Merge pull request #1749 from dexidp/pkg-dev-badge
Replace godoc badge with pkg.go.dev badge
2020-07-01 14:41:15 +02:00
Mark Sagi-Kazar 1b2ab6fa35
Update api documentation 2020-07-01 14:33:22 +02:00
Mark Sagi-Kazar e84682d7b9
Add v2 api module 2020-07-01 14:20:57 +02:00
Mark Sagi-Kazar 7bbda55225
Replace godoc badge with pkg.go.dev badge 2020-07-01 14:08:17 +02:00
Mark Sagi-Kazar dc3dcdd5c5
Build with Go 1.14 2020-07-01 14:02:01 +02:00
Márk Sági-Kazár 5160c659c8
Merge pull request #1747 from dexidp/docker-build
Add docker build and push to docker hub
2020-07-01 13:55:53 +02:00
Mark Sagi-Kazar 0b067af8e7
Add docker build and push to docker hub 2020-07-01 13:03:41 +02:00
Márk Sági-Kazár eef8c0a60d
Merge pull request #1745 from dexidp/remove-vendor
Remove vendor
2020-06-30 21:50:39 +02:00
Mark Sagi-Kazar 8b089dc441
Remove remaining references to vendor 2020-06-30 18:55:50 +02:00
Mark Sagi-Kazar 83d5f77495
Remove revendor from Makefile 2020-06-30 18:52:00 +02:00
Mark Sagi-Kazar d1b4443740
Add vendor to gitignore 2020-06-30 18:51:50 +02:00
Mark Sagi-Kazar f29b54d11c
Remove vendor folder 2020-06-30 18:51:19 +02:00
Márk Sági-Kazár df34848caa
Merge pull request #1741 from dexidp/separate-api-package
Add separate module for the api package
2020-06-30 18:49:43 +02:00
Mark Sagi-Kazar 4792f0c59f
Revendor dependencies 2020-06-30 17:36:41 +02:00
Nándor István Krácser 371df97cbf
Merge pull request #1743 from dexidp/docker-compose
add docker-compose.yaml for local testing
2020-06-30 14:12:49 +02:00
Márk Sági-Kazár 415a4ea4f7
Merge pull request #1742 from dexidp/remove-copypasta
Remove copypasta dependency
2020-06-30 13:51:03 +02:00
Nandor Kracser 5b7a664e9d
add docker-compose for local testing 2020-06-30 13:46:05 +02:00
Mark Sagi-Kazar af9dfd4a29
Remove copypasta dependency 2020-06-30 13:12:36 +02:00
Mark Sagi-Kazar dad8d6d687
Add separate module for the api package 2020-06-30 13:11:06 +02:00
Stephen Augustus e1a45ba33e
Merge pull request #1738 from justaugustus/augustus
MAINTAINERS: Add Stephen Augustus (@justaugustus)
2020-06-25 15:25:11 -04:00
Stephen Augustus e151af1b44 MAINTAINERS: Add Stephen Augustus (justaugustus)
Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-06-25 13:59:17 -04:00
Stephen Augustus de871b3f8a MAINTAINERS: Alpha-sort maintainers
Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2020-06-25 13:16:41 -04:00
Joel Speed 9d7e472c63
Merge pull request #1720 from candlerb/fix-google
Allow the "google" connector to work without a service account
2020-06-19 17:10:23 +01:00
Márk Sági-Kazár 2ca992e9b3
Merge pull request #1721 from candlerb/fix-token-comment
Fix comment for implicit flow
2020-05-31 21:54:31 +02:00
techknowlogick 0a9f56527e
Add Gitea connector (#1715)
* Add Gitea connector

* Add details to readme

* resolve lint issue
2020-05-26 13:54:40 +02:00
Brian Candler 442d3de11d Allow the "google" connector to work without a service account
Fixes #1718
2020-05-22 09:24:26 +00:00
Brian Candler d2c9305e0f Fix comment for implicit flow 2020-05-21 12:00:53 +01:00
Márk Sági-Kazár 709d4169d6
Merge pull request #1694 from flant/fix-openshift-root-ca
Fix OpenShift connector rootCA option
2020-05-12 13:55:45 +02:00
Márk Sági-Kazár ba723caa0a
Merge pull request #1704 from srenatus/sr/saml/filter-allowed-groups
connector/saml: add 'FilterGroups' setting
2020-05-12 13:40:29 +02:00
Márk Sági-Kazár c0dfeb7068
Merge pull request #1692 from flant/oidc-icon
Add icon for OIDC provider
2020-05-12 13:39:53 +02:00
m.nabokikh 47b0d33142 Add icon for OIDC provider
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-05-12 15:33:15 +04:00
m.nabokikh 521aa0802f Fix OpenShift connector rootCA option
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2020-05-12 15:31:27 +04:00
Stephan Renatus 4a0feaf589 connector/saml: add 'FilterGroups' setting
This should make AllowedGroups equivalent to an LDAP group filter:

When set to true, only the groups from AllowedGroups will be included in the
user's identity.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2020-05-12 13:29:05 +02:00
poh chiat d87cf1c924
create github oauthconfig with redirecturl (#1700) 2020-05-12 13:23:00 +02:00
Márk Sági-Kazár 336e284a46
Merge pull request #1701 from tkleczek/static_client_secret_fix
allow no secret for static public clients
2020-05-12 13:07:46 +02:00
Tomasz Kleczek c830d49884 allow no secret for static public clients
For statically-configured public clients it should be allowed for both
Secret and SecretEnv fields to be empty.
2020-05-05 17:09:09 +02:00
Martijn 0a85a97ba9
Allow preferred_username claim to be set for Crowd connector (#1684)
* Add atlassiancrowd connector to list in readme

* Add TestIdentityFromCrowdUser

* Set preferred_username claim when configured

* Add preferredUsernameField option to docs

* Log warning when mapping invalid crowd field
2020-04-23 20:14:15 +02:00
Mattias Sjöström cd054c71af
Documentation: Fix typo and add specification in openshift connector doc (#1687)
Serviceaccount annotation in oc patch instruction was malformed. Format
specification of Client ID for a Service Account was missing.
2020-04-14 08:55:51 +02:00
Márk Sági-Kazár 83d8853fd9
Merge pull request #1686 from kenperkins/gh-1682
Adding slack channel to README
2020-04-08 08:42:42 +02:00
Ken Perkins 05b8acb974 Adding slack channel to README 2020-04-07 11:03:48 -07:00
Kyle Travis cfae2eb720
storage/kubernetes: remove shadowed ResourceVersion from Connector (#1673) 2020-04-07 11:02:44 +02:00
Ken Perkins f6476b62f2
Added Email of Keystone to Identity (#1681)
* Added Email of Keystone to Identity

After the successful login to keystone, the Email of the logged in user
is fetch from keystone and provided to `identity.Email`.

This is useful for upstream software that uses the Email as the primary
identification.

* Removed unnecessary code from getUsers

* Changed creation of userResponse in keystone

* Fixing linter error

Co-authored-by: Christoph Glaubitz <christoph.glaubitz@innovo-cloud.de>
2020-04-06 15:40:17 +02:00
Nándor István Krácser ebef257dcd
Merge pull request #1678 from Teeed/auto_consistency_fix
Automatic consistency fixing in case of missing refresh token in db
2020-04-03 14:17:58 +02:00
Tadeusz Magura-Witkowski 0513ce3d6b
Merge branch 'master' into auto_consistency_fix 2020-04-02 10:49:10 +02:00
Nándor István Krácser ec57e31103
Merge pull request #1645 from JerrySunWRS/master
Wrap Kubernetes host address in square brackets
2020-03-27 08:35:30 +01:00
Tadeusz Magura-Witkowski 7b7e2a040d Automatic consistency fixing in case of missing refresh token in db 2020-03-25 13:43:53 +01:00
Márk Sági-Kazár 3693b74791
Merge pull request #1676 from dexidp/lint-timeout
increase go lint timeout
2020-03-19 16:00:56 +01:00
Nándor István Krácser db23367150
increase go lint timeout 2020-03-19 15:50:18 +01:00
Nándor István Krácser 741bf029a1
Merge pull request #1670 from klarose/handle-refresh-no-present
handlers: do not fail login if refresh token gone
2020-03-19 13:44:22 +01:00
Kyle Larose ab5ea03025
handlers: do not fail login if refresh token gone
There is a chance that offline storage could fall out of sync with the
refresh token tables. One example is if dex crashes/is stopped in the
middle of handling a login request. If the old refresh token associated
with the offline session is deleted, and then the process stops, the
offline session will still refer to the old token.

Unfortunately, if this case occurs, there is no way to recover from it,
since further logins will be halted due to dex being unable to clean up
the old tokens till referenced in the offline session: the database is
essentially corrupted.

There doesn't seem to be a good reason to fail the auth request if the
old refresh token is gone. This changes the logic in `handleAuthCode` to
not fail the entire transaction if the old refresh token could not be
deleted because it was not present. This has the effect of installing
the new refresh token, and unpdating the offline storage, thereby fixing
the issue, however it occured.
2020-03-18 12:56:37 -04:00
Nándor István Krácser 277272502b
Merge pull request #1674 from dexidp/githubci-mysql
ci: add mysql service
2020-03-18 15:01:57 +01:00
Nandor Kracser 8ab1ea9334
ci: add mysql service
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2020-03-18 11:58:41 +01:00
Nándor István Krácser d820fd45d8
Merge pull request #1664 from lhotrifork/static-client-env-vars
storage/static.go: expand environment variables in client ID and secret
2020-03-03 11:05:08 +01:00
Yann Soubeyrand 99c3ec6820 Add ability to set ID and Secret from environment variables for static clients
Having ID and Secret in clear inside configuration files for static
clients is not ideal. This commit allows setting these from environment
variables.

Signed-off-by: Yann Soubeyrand <yann.soubeyrand@gmx.fr>
2020-03-03 08:27:13 +01:00
Joel Speed 30ea963bb6
Merge pull request #1656 from taxibeat/oidc-prompt-type
Make prompt configurable for oidc offline_access
2020-02-28 10:56:13 +00:00
Nándor István Krácser b7cf701032
Merge pull request #1515 from flant/atlassian-crowd-connector
new connector for Atlassian Crowd
2020-02-24 10:09:27 +01:00
Nándor István Krácser 2bd4886517
Merge pull request #1661 from sabre1041/openshift-connector-mail
Setting email for OpenShift connector
2020-02-21 17:02:50 +01:00
Andrew Block 76bb453ff3
Setting email for OpenShift connector 2020-02-21 16:53:46 +01:00
Márk Sági-Kazár b9787d48ac
Merge pull request #1660 from dexidp/checkout-v2
ci: use checkout@v2
2020-02-21 16:16:22 +01:00
Nándor István Krácser fab0da7b69
ci: use checkout@v2 2020-02-21 15:53:13 +01:00
Nándor István Krácser edd3a40141
Merge pull request #1659 from dexidp/sql-specific-migrations
storage/sql: allow specifying sql flavor specific migrations
2020-02-21 14:47:14 +01:00
Nandor Kracser c7e9960c7e
storage/mysql: increase auth_request.state length to 4096
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2020-02-21 12:53:18 +01:00
Nandor Kracser 80749ffd3f
storage/sql: allow specifying sql flavor specific migrations
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2020-02-21 12:53:18 +01:00
Nándor István Krácser 1160649c31
Merge pull request #1621 from concourse/pr/passowrd-grant-synced
Rework - add support for Resource Owner Password Credentials Grant
2020-02-20 08:27:50 +01:00
Chris Loukas d33a76fa19 Make prompt configurable for oidc offline_access 2020-02-19 16:10:28 +02:00
Nándor István Krácser f17fa67715
Merge pull request #1653 from sdarwin/doc-dex-healthz
update doc regarding health check
2020-02-19 12:44:17 +01:00
Nándor István Krácser 0f8c4db9f6
Merge pull request #1650 from sdarwin/k8s-doc
update kubernetes.md document
2020-02-18 10:18:10 +01:00
sdarwin 49e85a3cb1 update doc regarding health check 2020-02-14 09:24:26 -06:00
sdarwin 11d91c144f update kubernetes.md document 2020-02-13 14:33:38 -06:00
Nándor István Krácser cf4f88a06e
Merge pull request #1648 from int128/patch-1
Update kubelogin-activedirectory.md for credential plugin mode
2020-02-12 16:15:20 +01:00
Hidetake Iwata 2ec5e5463f
Update kubelogin-activedirectory.md for credential plugin 2020-02-12 21:47:41 +09:00
Jerry Sun 3a3a2bcc86 Wrap Kubernetes host address in square brackets
When constructing the host address string, the address is
not wrapped in square brackets. This does not work in IPv6
Kubernetes deployments. This commit adds square brackets
around the address. IPv4 was also tested to ensure it works
with wrapped address.

Signed-off-by: Jerry Sun <jerry.sun@windriver.com>
2020-02-06 14:52:54 -05:00
Ivan Mikheykin 7ef1179e75 feat: connector for Atlassian Crowd 2020-02-05 12:40:49 +04:00
Márk Sági-Kazár 0014ca3465
Merge pull request #1644 from cmurphy/tpr-to-crds
Fix kubernetes storage link
2020-02-03 23:05:28 +01:00
Colleen Murphy 7319d3796f Fix kubernetes storage link
In 58093dbb2 the kubernetes documentation was updated to refer to CRDs
rather than TPRs when discussing how storage works for dex. However, the
rest of the line was not updated and still referred to the TPR section,
whose anchor link was changed in 395febf80 with the removal of TPR
support. This change updates the kubernetes documentation to point to
the currect section of the storage documentation for CRDs.
2020-02-03 10:11:40 -08:00
Joel Speed 30cd592801
Merge pull request #1612 from vi7/multiple-user-to-group-mapping
connector/ldap: add multiple user to group mapping
2020-02-02 11:09:05 +00:00
Márk Sági-Kazár 7c7c1de798
Merge pull request #1641 from dexidp/vendor
Vendor dependencies
2020-01-31 10:47:59 +01:00
Mark Sagi-Kazar 0f1927a1ba
Vendor dependencies 2020-01-31 10:32:00 +01:00
Márk Sági-Kazár ca2d718fe4
Merge pull request #1640 from dexidp/update-dependencies
Update dependencies
2020-01-31 10:28:48 +01:00
Mark Sagi-Kazar 573bbeb7de
Revert grpc update 2020-01-30 18:18:38 +01:00
Mark Sagi-Kazar 3c26c90dcc
Tidy dependencies 2020-01-30 18:03:28 +01:00
Mark Sagi-Kazar 3b4cf282c8
Update jose library 2020-01-30 18:02:59 +01:00
Mark Sagi-Kazar 2f10b81a20
Update grpc 2020-01-30 18:00:34 +01:00
Mark Sagi-Kazar 52a084edd0
Update google api 2020-01-30 18:00:12 +01:00
Mark Sagi-Kazar a098aa112b
Update prometheus client 2020-01-30 17:58:52 +01:00
Mark Sagi-Kazar 37d0b7465d
Update Postgres library 2020-01-30 17:55:50 +01:00
Mark Sagi-Kazar 0ce0393725
Update httpsnoop 2020-01-30 17:53:51 +01:00
Mark Sagi-Kazar 88fd211fb5
Move up go version 2020-01-30 17:51:35 +01:00
Mark Sagi-Kazar 55b49063f8
Update etcd 2020-01-30 17:50:22 +01:00
Mark Sagi-Kazar 121a55e0bc
Update OIDC client 2020-01-30 17:38:23 +01:00
Mark Sagi-Kazar afbb62206f
Update MySQL driver 2020-01-30 17:34:40 +01:00
Márk Sági-Kazár 26061f9558
Merge pull request #1639 from dexidp/disable-travis
Disable travis
2020-01-30 16:42:27 +01:00
Mark Sagi-Kazar b09b7bbbba
Disable travis 2020-01-30 16:32:48 +01:00
Márk Sági-Kazár bb2733fbdd
Merge pull request #1638 from dexidp/readme
Update readme
2020-01-30 16:28:40 +01:00
Márk Sági-Kazár a6b5405c2e
Merge pull request #1601 from krishnadurai/feature/static_password_env
Option to add staticPasswords from environment variables
2020-01-30 16:22:17 +01:00
Mark Sagi-Kazar 6951c2c269
Add google connector 2020-01-30 16:20:59 +01:00
Mark Sagi-Kazar fb0048d509
Improve badges 2020-01-30 16:15:38 +01:00
Márk Sági-Kazár 8894eed8d3
Merge pull request #1625 from concourse/pr/optional-prometheus-logger-sync
Optional Prometheus Registry
2020-01-21 18:02:20 +01:00
Nándor István Krácser aca67b0839
Merge pull request #1627 from jfrabaute/master
google: Retrieve all the groups for a user
2020-01-20 08:30:17 +01:00
Nándor István Krácser ea43562793
Merge pull request #1628 from linzhaoming/master
Update gitlab.go
2020-01-16 08:33:51 +01:00
linzhaoming 1d3851b0c5
Update gitlab.go
fix typo
2020-01-16 11:26:57 +08:00
Fabrice Rabaute b85d7849ad
google: Retrieve all the groups for a user
The list of groups is paginated (default page is 200), so when a user
has more than 200 groups, only the first 200 are retrieve.

This change is retrieving all the groups for a user by querying all the
pages.
2020-01-14 13:26:37 -08:00
Vitaliy Dmitriev e20a795a2a connector/ldap: backward compatibility with single user to group mapping
Signed-off-by: Vitaliy Dmitriev <vi7alya@gmail.com>
2020-01-14 11:00:32 +01:00
Joshua Winters 76825fef8f Make logger and prometheus optional in server config
Signed-off-by: Josh Winters <jwinters@pivotal.io>
Co-authored-by: Mark Huang <mhuang@pivotal.io>
2020-01-13 15:28:41 -05:00
Nándor István Krácser 1cdb2b1d74
Merge pull request #1622 from chlunde/dex-microsoft-tests
connector/microsoft: Add basic tests
2020-01-13 09:37:33 +01:00
Carl Henrik Lunde 6104295d5e microsoft: Add basic tests
Implemented similar to connector/github/github_test.go
2020-01-13 08:51:22 +01:00
Carl Henrik Lunde 5db29eb087 microsoft: Make interface testable
Enable testing by allowing overriding the API host name in tests
2020-01-13 08:15:07 +01:00
Rui Yang 0f9a74f1d0 Remove uneccesary client verification 2020-01-10 14:52:57 -05:00
Zach Brown 13be146d2a Add support for password grant #926 2020-01-10 13:18:09 -05:00
krishnadurai 321790870f Fixes lint 2020-01-07 16:34:32 -08:00
krishnadurai 2d5619e4e8 Corrects imports after merge 2020-01-07 11:48:35 -08:00
Krishna Durai 9560899496
Merge branch 'master' into feature/static_password_env 2020-01-06 23:21:20 -08:00
Nándor István Krácser 3cbba11012
Merge pull request #1610 from flant/oidc-email-scope-check
Adding oidc email scope check
2020-01-06 10:20:46 +01:00
Nándor István Krácser 53897e831d
Merge pull request #1609 from PeopleRange/master
Fixed mysql EOF issue
2020-01-06 08:39:17 +01:00
Vitaliy Dmitriev f2e7823db9 connector/ldap: add multiple user to group mapping
Add an ability to fetch user's membership from
  groups of a different type by specifying multiple
  group attribute to user attribute value matchers
  in the Dex config:

    userMatchers:
    - userAttr: uid
      groupAttr: memberUid
    - userAttr: DN
      groupAttr: member

  In other words the user's groups can be fetched now from
  ldap structure similar to the following:

    dn: cn=john,ou=People,dc=example,dc=org
    objectClass: person
    objectClass: inetOrgPerson
    sn: doe
    cn: john
    uid: johndoe
    mail: johndoe@example.com
    userpassword: bar

    dn: cn=qa,ou=Groups,ou=Portland,dc=example,dc=org
    objectClass: groupOfNames
    cn: qa
    member: cn=john,ou=People,dc=example,dc=org

    dn: cn=logger,ou=UnixGroups,ou=Portland,dc=example,dc=org
    objectClass: posixGroup
    gidNumber: 1000
    cn: logger
    memberUid: johndoe

Signed-off-by: Vitaliy Dmitriev <vi7alya@gmail.com>
2020-01-03 10:40:21 +01:00
Nándor István Krácser 6318c105ec
Merge pull request #1599 from sabre1041/openshift-connector
OpenShift connector
2020-01-01 12:55:11 +01:00
m.nabokikh 383c2fe8b6 Adding oidc email scope check
This helps to avoid "no email claim" error if email scope was not specified.

Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2019-12-28 15:28:01 +04:00
Aiden Andrews-McDermott 98f78db915 Updated config.go to remove the defaulting idle connection limit of 5 which is an issue for upstream https://github.com/go-sql-driver/mysql/issues/674 2019-12-27 18:08:17 +00:00
Andrew Block d31f6eabd4
Corrected logic in group verification 2019-12-26 20:32:12 -06:00
Andrew Block 296659cb50
Reduced OpenShift scopes and enhanced documentation 2019-12-26 03:14:20 -06:00
Andrew Block 5afa02644a
Added OpenShift documentation to README 2019-12-25 11:52:42 -05:00
Márk Sági-Kazár 789272a0c1
Merge pull request #1576 from flant/icons-proposal
Pick icons on login screen by connector type instead of ID
2019-12-23 13:05:19 +01:00
m.nabokikh 058e72ef50 Pick icons on login screen by connector type instead of ID
Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
2019-12-23 12:38:22 +04:00
Andrew Block 075ab0938e
Fixed formatting 2019-12-22 02:53:10 -05:00
Andrew Block 7e89d8ca24
Resolved newline issues 2019-12-22 02:27:11 -05:00
Andrew Block 02c8f85e4d
Resolved newline issues 2019-12-22 02:27:11 -05:00
Andrew Block db7711d72a
Test cleanup 2019-12-22 02:27:10 -05:00
Andrew Block 5881a2cfca
Test cleanup 2019-12-22 02:27:10 -05:00
Andrew Block 48954ca716
Corrected test formatting 2019-12-22 02:27:09 -05:00
Andrew Block 92e63771ac
Added OpenShift connector 2019-12-22 02:27:09 -05:00
Márk Sági-Kazár 664fdf76ca
Merge pull request #1605 from dexidp/kubernetes-tests
Rewrite kubernetes tests
2019-12-20 11:41:57 +01:00
Nándor István Krácser 1baf48f83c
Merge pull request #1556 from tkleczek/conformance_tests_improvements
storage: conformance tests improvements
2019-12-20 10:03:43 +01:00
Nándor István Krácser f98332595e
Merge branch 'master' into conformance_tests_improvements 2019-12-20 09:56:59 +01:00
Nándor István Krácser ac242a8bc7
Merge pull request #1590 from ChengYanJin/doc/add-issuer-in-template
add issuer in the templates.md
2019-12-20 09:28:40 +01:00
Nándor István Krácser a901e2f204
Merge pull request #1604 from dexidp/fix-linters
Fix linters
2019-12-20 07:10:22 +01:00
Márk Sági-Kazár ff4dee5fdb
Merge pull request #1584 from alrs/remove-deprecated-register-broken-auth-header-provider
Deprecated oauth2.RegisterBrokenAuthHeaderProvider
2019-12-18 18:00:15 +01:00
Lars Lehtonen 8e0ae82034
connector/oidc: replace deprecated oauth2.RegisterBrokenAuthHeaderProvider with oauth2.Endpoint.AuthStyle 2019-12-18 08:27:40 -08:00
Mark Sagi-Kazar 3fb85ab009
Remove instructions for kubernetes tests from docs 2019-12-18 17:23:52 +01:00
Mark Sagi-Kazar e0c58d5449
Remove old kubernetes storage test flow 2019-12-18 17:23:52 +01:00
Mark Sagi-Kazar 309b33d05a
Rewrite kubernetes storage test 2019-12-18 17:23:51 +01:00
Mark Sagi-Kazar 050d5af937
Fix ineffassign 2019-12-18 16:07:06 +01:00
Mark Sagi-Kazar 65c77e9db2
Fix bodyclose 2019-12-18 16:04:03 +01:00
Mark Sagi-Kazar 2f8d1f8e42
Fix unconvert 2019-12-18 15:56:46 +01:00
Mark Sagi-Kazar f141f2133b
Fix whitespace 2019-12-18 15:56:12 +01:00
Mark Sagi-Kazar 9bd5ae5197
Fix goimports 2019-12-18 15:53:34 +01:00
Mark Sagi-Kazar 367b187cf4
Fix missspell 2019-12-18 15:51:44 +01:00
Mark Sagi-Kazar 142c96c210
Fix stylecheck 2019-12-18 15:50:36 +01:00
Mark Sagi-Kazar 8c3dc0ca66
Remove unused code (fixed: unused, structcheck, deadcode linters) 2019-12-18 15:46:49 +01:00
Márk Sági-Kazár e0f927c7a9
Merge pull request #1603 from dexidp/lint
Add golangci linter
2019-12-18 15:41:12 +01:00
Mark Sagi-Kazar bcd47fc6f3
Remove old lint targets 2019-12-18 15:07:53 +01:00
Mark Sagi-Kazar 9346e328ef
Add golangci linter 2019-12-18 14:55:52 +01:00
krishnadurai 9aec1e7db2 Avoids unnecessary escape characters in ENV var for ci.yaml 2019-12-13 17:25:56 -08:00
krishnadurai 1fd5dd7b0e Change env var prefix to DEX and add to ci.yaml 2019-12-13 17:03:56 -08:00
krishnadurai af9c2880a6 Corrects validation logic for static password check 2019-12-13 16:52:10 -08:00
krishnadurai 91cbd466a5 Option to add staticPasswords from environment variables 2019-12-13 16:33:21 -08:00
Nándor István Krácser 64b269d1c1
Merge pull request #1596 from dexidp/github-actions
Add github actions CI flow
2019-12-12 09:53:26 +01:00
Mark Sagi-Kazar 3c7593f87b
Revert using vendored dependencies 2019-12-08 20:44:42 +01:00
Mark Sagi-Kazar 11c2499713
Allow ldap tests 2019-12-08 20:44:41 +01:00
Mark Sagi-Kazar d2095bb2d8
Rewrite LDAP tests to use Docker 2019-12-08 20:21:28 +01:00
Mark Sagi-Kazar 532c120ba7
Use vendored dependencies for CI build 2019-12-07 20:06:26 +01:00
Mark Sagi-Kazar 5d2529f0ad
Enable Kubernetes tests 2019-12-07 19:58:51 +01:00
Mark Sagi-Kazar 0773c6e9f3
Add github actions CI flow 2019-12-07 11:14:30 +01:00
Nándor István Krácser 1ac4f7fe42
Merge pull request #1591 from dexidp/google-group-whitelist
connector/google: support group whitelisting
2019-12-06 15:53:00 +01:00
Nándor István Krácser d5b3fc0478
Merge pull request #1592 from dexidp/go-alpine-update
update go to 1.13 and alpine to 3.10
2019-12-06 15:52:30 +01:00
Nándor István Krácser dc812f5341
Merge pull request #1594 from dexidp/update-maintianers
add @sagikazarmark to MAINTAINERS
2019-12-06 11:13:07 +01:00
Nandor Kracser 9b5b604bab
go mod vendor with 1.13
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2019-12-06 09:24:16 +01:00
Nándor István Krácser 4bb4d49952
add @sagikazarmark to MAINTAINERS 2019-12-06 09:02:34 +01:00
Nandor Kracser dbea20d078
update go to 1.13 and alpine to 3.10
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2019-12-04 10:46:53 +01:00
Nandor Kracser a38e215891
connector/google: support group whitelisting
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2019-12-03 16:27:07 +01:00
Nándor István Krácser c41035732f
Merge pull request #1434 from jacksontj/groups
Add option to enable groups for oidc connectors
2019-11-27 14:00:36 +01:00
Nándor István Krácser 8fdcee7c14
Merge pull request #1185 from JoelSpeed/google-fetch-groups
Fetch groups in a Google Connector
2019-11-27 13:22:45 +01:00
YanJin e11b2ceeee add issuer in the templates.md 2019-11-25 12:15:07 +01:00
Joel Speed 658a2cc477
Make directory service during init 2019-11-19 17:12:44 +00:00
Joel Speed 554870cea0
Add todo for configurable groups key 2019-11-19 17:12:43 +00:00
Joel Speed 94bee18f6b
vendor: make revendor 2019-11-19 17:12:42 +00:00
Joel Speed 9d9a1017e4
Add documentation for google connector 2019-11-19 17:12:41 +00:00
Joel Speed 6a9bc889b5
Update comments 2019-11-19 17:12:40 +00:00
Joel Speed c03c98b951
Check config before getting groups 2019-11-19 17:12:39 +00:00
Joel Speed 3f55e2da72
Get groups from directory api 2019-11-19 17:12:38 +00:00
Joel Speed 36370f8f2a
No need to configure issuer 2019-11-19 17:12:37 +00:00
Joel Speed 97ffa21262
Create separate Google connector 2019-11-19 17:12:36 +00:00
Nándor István Krácser b1e98d8590
Merge pull request #1180 from JoelSpeed/refresh-tokens
Implement refreshing with Google
2019-11-19 17:39:23 +01:00
Joel Speed 3156553843
OIDC: Rename refreshToken to RefreshToken 2019-11-19 15:43:25 +00:00
Joel Speed c782ac809c
Remove defaulting from connector_data column 2019-11-19 15:43:24 +00:00
Joel Speed c4e96dda32
Fix migration of old connector data 2019-11-19 15:43:23 +00:00
Joel Speed d9095073c8
Unindent session updates on finalizeLogin 2019-11-19 15:43:22 +00:00
Joel Speed 77fcf9ad77
Use a struct for connector data within OIDC connector 2019-11-19 15:43:22 +00:00
Joel Speed f6077083c9
Identify error as failure to retrieve refresh token 2019-11-19 15:43:21 +00:00
Joel Speed 8b344fe4d3
Fix Refresh comment 2019-11-19 15:43:20 +00:00
Joel Speed 19ad7daa7f
Use old ConnectorData before session.ConnectorData 2019-11-19 15:43:19 +00:00
Joel Speed 45a40a13a3
Revert "Update Kubernetes storage backend"
This reverts commit 228bdc324877bf67ecdd434503b9c1b25d8e7d28.
2019-11-19 15:43:18 +00:00
Joel Speed 236b25b68e
Revert "Fix ETCD storage backend" 2019-11-19 15:43:17 +00:00
Joel Speed 41b7c855d0
Revert "Update conformance"
This reverts commit 9c7ceabe8aebf6c740c237c5e76c21397179f901.
2019-11-19 15:43:16 +00:00
Joel Speed 9ce4393156
Revert "Update SQL storage backend" 2019-11-19 15:43:15 +00:00
Joel Speed 176ba709a4
Revert "Remove connectordata from other structs"
This reverts commit 27f33516db343bd79b56a47ecef0fe514a35082d.
2019-11-19 15:43:14 +00:00
Joel Speed fea048b3e8
Fix SQL updater func 2019-11-19 15:43:13 +00:00
Joel Speed d38909831c
Fix migration in SQL connector
I didn't realise quite what the migration mechanism was. Have understood
it now.
2019-11-19 15:43:13 +00:00
Joel Speed 433bb2afec
Remove duplicate code 2019-11-19 15:43:12 +00:00
Joel Speed 4076eed17b
Build opts based on scope 2019-11-19 15:43:11 +00:00
Joel Speed 80995dff9b
Fix SQL storage 2019-11-19 15:43:10 +00:00
Joel Speed b9b315dd64
Fix conformance tests 2019-11-19 15:43:09 +00:00
Joel Speed 7a76c767fe
Update Kubernetes storage backend 2019-11-19 15:43:08 +00:00
Joel Speed c54f1656c7
Fix ETCD storage backend 2019-11-19 15:43:07 +00:00
Joel Speed c789c5808e
Update conformance 2019-11-19 15:43:06 +00:00
Joel Speed 7fc3f230df
Update SQL storage backend 2019-11-19 15:43:05 +00:00
Joel Speed 0857a0fe09
Implement refresh in OIDC connector
This has added the access=offline parameter and prompt=consent parameter
to the initial request, this works with google, assuming other providers
will ignore the prompt parameter
2019-11-19 15:43:04 +00:00
Joel Speed 5c88713177
Remove connectordata from other structs 2019-11-19 15:43:03 +00:00
Joel Speed 0352258093
Update handleRefreshToken logic 2019-11-19 15:43:01 +00:00
Joel Speed 575c792156
Store most recent refresh token in offline sessions 2019-11-19 15:40:56 +00:00
Nándor István Krácser c392236f4f
Merge pull request #1586 from serhiimakogon/fix/refresh-handler
preferred_username claim added on refresh token
2019-11-19 15:39:17 +01:00
serhiimakogon b793afd375 preferred_username claim added on refresh token 2019-11-19 16:27:34 +02:00
Nándor István Krácser b7184be3dd
Merge pull request #1569 from bhageena/master
Fix spelling errors in docs
2019-11-05 10:34:40 +01:00
Nándor István Krácser 6d41541964
Merge pull request #1544 from kenperkins/saml-groups
Adding support for allowed groups in SAML Connector
2019-10-30 13:28:34 +01:00
Nándor István Krácser f2590ee07d
Merge pull request #1545 from jacksontj/getUserInfo
Run getUserInfo prior to claim enforcement
2019-10-30 13:26:18 +01:00
Nándor István Krácser d5d3abca6a
Merge pull request #1566 from dexidp/preferred_username
add preffered_username to idToken
2019-10-30 13:25:23 +01:00
Nándor István Krácser 0b56a47571
Merge pull request #1558 from aijingyc/fix_readme_branch
Fix URLs in curl cmd as stated in the overview doc.
2019-10-30 13:20:28 +01:00
Nándor István Krácser 799f29fdb5
Merge pull request #1571 from gosharplite/patch-1
Fix typo
2019-10-30 13:20:04 +01:00
Nándor István Krácser a58d77a499
Merge pull request #1550 from dexidp/mysql-tx-isolation
storage/mysql: support pre-5.7.20 instances with tx_isolation only
2019-10-30 13:14:43 +01:00
Nándor István Krácser 0b55f121b4
Fix missing email in log message
Co-Authored-By: Felix Fontein <ff@dybuster.com>
2019-10-30 13:13:33 +01:00
Nándor István Krácser 3f8fd74185
Merge pull request #1568 from life1347/patch-1
Add note for redirect uri
2019-10-30 13:12:46 +01:00
Nandor Kracser c1b421fa04 add preffered_username to idToken
Signed-off-by: Nandor Kracser <bonifaido@gmail.com>
2019-10-30 13:06:37 +01:00
Tony Hsu 6e35f24399
Fix typo 2019-10-22 11:27:12 +08:00
Chandan Rai efdb5de6d8 Fix spelling errors in docs 2019-10-14 18:52:40 +05:30
Ta-Ching Chen 76c76a0b39
Add note for redirect uri 2019-10-13 15:24:22 +08:00
Joel Speed 4bede5eb80
Merge pull request #1554 from yanniszark/feature-web-templates-use-relative-urls
server: templates: use relative URLs to refer to assets
2019-10-03 10:49:18 +01:00
Yannis Zarkadas 69d13b766d gitignore: add .idea folder
Signed-off-by: Yannis Zarkadas <yanniszark@arrikto.com>
2019-10-02 17:08:06 +03:00
Yannis Zarkadas 59beb7425f web: change header template to use new url function
Signed-off-by: Yannis Zarkadas <yanniszark@arrikto.com>
2019-10-02 17:08:06 +03:00
Yannis Zarkadas 27944d4f8f templates: add new relativeURL function
Signed-off-by: Yannis Zarkadas <yanniszark@arrikto.com>
2019-10-02 17:08:06 +03:00
Yannis Zarkadas 839130f01c handlers: change all handlers to pass down http request
Signed-off-by: Yannis Zarkadas <yanniszark@arrikto.com>
2019-10-02 17:08:06 +03:00
j.ai 2c52c52686 Fix URLs in curl cmd as stated in the overview doc. 2019-09-27 17:45:52 -07:00
Tomasz Kleczek 42d61191c4 storage: conformance tests improvements 2019-09-27 13:54:54 +02:00
Nandor Kracser d2c33db8a8 storage/mysql: support pre-5.7.20 instances with tx_isolation only 2019-09-23 09:36:01 +02:00
Thomas Jackson 21ab30d207 Add option to enable groups for oidc connectors
There's been some discussion in #1065 regarding what to do about
refreshing groups. As it stands today dex doesn't update any of the
claims on refresh (groups would just be another one). The main concern
with enabling it is that group claims may change more frequently. While
we continue to wait on the upstream refresh flows, this adds an option
to enable the group claim. This is disabled by default (so no behavioral
change) but enables those that are willing to have the delay in group
claim change to use oidc IDPs.

Workaround to #1065
2019-09-13 15:50:33 -07:00
Thomas Jackson 512cb3169e Run getUserInfo prior to claim enforcement
If you have an oidc connector configured *and* that IDP provides thin
tokens (e.g. okta) then the majority of the requested claims come in the
getUserInfo call (such as email_verified). So if getUserInfo is
configured it should be run before claims are validated.
2019-09-13 11:10:44 -07:00
Ken Perkins 285c1f162e connector/saml: Adding group filtering
- 4 new tests
- Doc changes to use the group filtering
2019-09-10 10:53:19 -07:00
Stephan Renatus 8427f0f15c
Merge pull request #1543 from wassan128/fix-typo
Fix typo
2019-09-06 08:14:29 +02:00
wassan128 42e8619830 Fix typo 2019-09-06 09:55:09 +09:00
Stephan Renatus 3b7292a08f
Merge pull request #1520 from dexidp/gitlab-groups-scope
gitlab: add groups scope by default when filtering is requested
2019-09-04 12:21:57 +02:00
Joel Speed 179cce36ef
Merge pull request #1540 from stevendanna/ssd/cipher-suites
Use a more conservative set of CipherSuites
2019-09-02 11:36:43 +01:00
Steven Danna 46f48b33a1
Use a more conservative set of CipherSuites
The default cipher suites used by Go include a number of ciphers that
have known weaknesses. In addition to leaving users open to these
weaknesses, the inclusion of these weaker ciphers causes problems with
various automated scanning tools.

This PR disables the CBC-mode, RC4, and 3DES ciphers included in the
Go standard library by passing an explicit cipher suite list.

The ciphers included here are more line with those recommended by
Mozilla for "Intermediate" compatibility. [0]

*Performance Implications*

The Go standard library does capability-based cipher ordering,
preferring AES ciphers if the underlying hardware has AES specific
instructions. [1] Since all of the relevant code is internal modules,
to do the same thing ourselves would require duplicating that
code. Here, I've placed AES based ciphers first.

*Compatibility Implications*

This does reduce the number of clients who will be able to communicate
with dex.

[0] https://ssl-config.mozilla.org/#server=nginx&server-version=1.17.0&config=intermediate&hsts=false&ocsp=false
[1] a8c2e5c6ad/src/crypto/tls/common.go (L1091)

Signed-off-by: Steven Danna <steve@chef.io>
2019-08-31 17:34:55 +01:00
Stephan Renatus c854e760db
Merge pull request #1539 from erwinvaneyk/replace-context-import
Replace x/net/context with stdlib context
2019-08-31 17:52:18 +02:00
erwinvaneyk 3e2217b3f4 Replace x/net/context with context of stdlib 2019-08-30 11:52:46 +02:00
Stephan Renatus 4f3ab1efb7
Merge pull request #1534 from jthabet/master
Pydio Cells adopters list
2019-08-29 16:25:45 +02:00
Stephan Renatus 15ec95bca9
Merge pull request #1521 from erwinvaneyk/patch-1
Clarify the origin of the ca file in the Kubernetes guide
2019-08-29 16:24:48 +02:00
Erwin van Eyk 5c99525ed3 Clarify the origin of openid-ca 2019-08-29 16:15:00 +02:00
j a48f73f14a Pydio Cells adopters list 2019-08-28 16:20:37 +02:00
Stephan Renatus 133c2565be
Merge pull request #1530 from dexidp/ldap-error
connector/ldap: display login error
2019-08-23 12:32:23 +02:00
Stephan Renatus 1f31d1889a
Merge pull request #1529 from dkuerner/golang-update
Dockerfile: build with golang 1.12.9
2019-08-22 16:31:47 +02:00
Nandor Kracser bd61535cb6 connector/ldap: display login error 2019-08-22 15:55:05 +02:00
Daniel Kürner 2dccdc2a1a Dockerfile: build with golang 1.12.9 2019-08-22 08:40:31 +02:00
Joel Speed ab08d7b3a4
Merge pull request #1517 from venezia/iss-1513
storage/kubernetes: Removing Kubernetes TPR support
2019-08-14 14:45:12 +01:00
Michael Venezia 395febf808
storage/kubernetes: Removing Kubernetes TPR support
Third Party Resources (TPR) have been removed from Kubernetes for
roughly 2 years.  This commit removes the support dex had for them.

Documentation has been updated to reflect this and to instruct users
on how to migrate from TPR-powered dex environment to a Custom Resource
Defintion (CRD) based one that dex > v2.17 will support
2019-08-14 09:28:18 -04:00
Nandor Kracser ef08ad8317 gitlab: add groups scope by default when filtering is requested 2019-08-14 13:33:46 +02:00
Stephan Renatus aeb2861a40
Merge pull request #1519 from dexidp/sr/bump-deps-for-http2-issues
bump deps for http2 issues

https://github.com/grpc/grpc-go/releases/tag/v1.23.0

https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA
2019-08-14 11:33:54 +02:00
Stephan Renatus 6e5a2b5ea1
deps: bump go-grpc (1.22.1 -> 1.23.0)
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-08-14 10:27:17 +02:00
Stephan Renatus 27b8426704
Dockerfile: build with golang 1.12.8
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-08-14 10:24:17 +02:00
Stephan Renatus d328a5ebaa
Merge pull request #1516 from tpdownes/doc/oauth2_config
Add examples for recent additions to oauth2 configuration options
2019-08-13 10:24:10 +02:00
Tom Downes 963b8e992d
Add examples for recent additions to oauth2 configuration options 2019-08-09 11:58:37 -05:00
Stephan Renatus d9f6ab4a68
Merge pull request #1512 from venezia/add_reflection
Add reflection to gRPC API (configurable)
2019-08-07 13:56:33 +02:00
Michael Venezia 430357b14e
vendor: revendor 2019-08-07 07:38:09 -04:00
Michael Venezia b65966d744
cmd/dex: adding reflection to grpc api, enabled through configuration 2019-08-07 07:37:39 -04:00
Stephan Renatus e1afe771cb
Merge pull request #1505 from MarcDufresne/show-login-page
Add option to always display connector selection even if there's only one
2019-08-07 09:23:42 +02:00
Stephan Renatus 89e43c198b
Merge pull request #1504 from MarcDufresne/template-custom-data
Allow arbitrary data to be passed to templates
2019-08-07 09:19:14 +02:00
Marc-André Dufresne 0dbb642f2c
Add option to always display connector selection even if there's only one 2019-08-06 13:18:46 -04:00
Marc-André Dufresne d458e882aa
Allow arbitrary data to be passed to templates 2019-08-06 13:14:53 -04:00
Stephan Renatus bc02006b45
Merge pull request #1510 from momokatte/test-invalid-callbacks
Add tests for some callback handler error conditions
2019-08-06 09:58:40 +02:00
Mike O 43d1a044bd Add tests for some callback handler error conditions 2019-08-05 16:02:28 -07:00
Nándor István Krácser 526e078366
Merge pull request #1509 from venezia/fix-go-lint-v2
Adjusting Makefile so that `golint` will compile
2019-08-03 13:56:20 +02:00
Michael Venezia c54ddc460d
Adjusting Makefile so that `golint` will compile 2019-08-02 17:34:25 -04:00
Stephan Renatus d36e6c26ee
Merge pull request #1490 from momokatte/master
Return HTTP 400 for invalid state parameter
2019-08-02 09:12:40 +02:00
Mike O d03a43335e Return HTTP 400 for invalid state parameter 2019-08-01 16:22:53 -07:00
Stephan Renatus 6ae11a1cfe
Merge pull request #1501 from dexidp/sr/bump-all-deps
update all deps
2019-07-31 09:01:39 +02:00
Stephan Renatus 291cd9e01c
regenerate protobuf code
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-31 08:16:18 +02:00
Stephan Renatus ea7fd6d470
cmd/dex: adapt to prometheus API change
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-31 08:09:58 +02:00
Stephan Renatus 076cd77469
run 'go get -u; make revendor'
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-31 08:09:38 +02:00
Stephan Renatus 7c1b4b3005
Merge pull request #1502 from dexidp/sr/fix-log-formatting-in-VerifyPassword-grpc
server/api: fix logging in VerifyPassword
2019-07-30 15:06:48 +02:00
Stephan Renatus 231e571c3c
server/api: fix logging in VerifyPassword
Before:

    msg="api: password check failed : %vcrypto/bcrypt: hashedPassword is not the hash of the given password"

After:

    msg="api: password check failed : crypto/bcrypt: hashedPassword is not the hash of the given password"

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-30 14:53:33 +02:00
Stephan Renatus 128d5da89e
Merge pull request #1500 from dexidp/sr/fix-some-lint-issues
*: fix some lint issues
2019-07-30 11:41:27 +02:00
Stephan Renatus d9487e553b
*: fix some lint issues
Mostly gathered these using golangci-lint's deadcode and ineffassign
linters.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-30 11:29:08 +02:00
Joel Speed e2ddefff31
Merge pull request #1439 from sks/feature/fail_on_invalid_config
Return config validation errors in one go
2019-07-30 11:00:17 +02:00
Nándor István Krácser 72f5596671
Merge pull request #1498 from mkontani/fix/mysql-query-sample
Doc/storage.md: fix mysql sample query
2019-07-29 21:19:41 +02:00
mkontani c067761df6 fix mysql sample query 2019-07-30 03:49:53 +09:00
Nándor István Krácser 0aee5be625
Merge pull request #1497 from dexidp/gitlab-username-as-id
connector/gitlab: implement useLoginAsID as in GitHub connector
2019-07-28 19:56:16 +02:00
Nandor Kracser ff34e570b4 connector/gitlab: implement useLoginAsID as in GitHub connector 2019-07-28 19:49:49 +02:00
Stephan Renatus 6e98c04f9b
Merge pull request #1446 from maksd/microsoft-groups-uuid-whitelist
microsoft: option for group UUIDs instead of name and group whitelist
2019-07-25 16:21:48 +02:00
Stephan Renatus fd53c0a3bb
Merge pull request #1496 from srenatus/sr/add-connector-id-to-example-app
add connector_id to example app
2019-07-25 16:21:28 +02:00
Maxime Desrosiers 458585008b
microsoft: option for group UUIDs instead of name and group whitelist 2019-07-25 09:14:33 -04:00
Stephan Renatus 8561a66365
server/{handler,oauth2}: cleanup error returns
Now, we'll return a standard error, and have the caller act upon this
being an instance of authErr.

Also changes the storage.AuthRequest return to a pointer, and returns
nil in error cases.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-25 13:40:06 +02:00
Stephan Renatus d7c7d42466
cmd/example-app: check all errors, pass claims as string to renderToken
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-24 12:26:51 +02:00
Stephan Renatus c4e0587df1
cmd/example-app: expose connector_id
As a piece of "living documentation" for #1481.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-24 12:17:14 +02:00
Joel Speed 20a858da3b
Merge pull request #1495 from pbochynski/patch-1
Update ADOPTERS.md
2019-07-24 08:51:10 +01:00
Piotr 74023ba9ad
Update ADOPTERS.md
Add Kyma project as an adopter.
2019-07-24 08:50:49 +02:00
Stephan Renatus 9c211132b2
Merge pull request #1494 from tanmaykm/patch-1
Update Adopters.md
2019-07-24 08:27:51 +02:00
Tanmay Mohapatra 56f8e60545 Update Adopters.md
Adding JuliaBox to the list of production adopters of Dex.
2019-07-23 22:48:29 -04:00
Sabith K Soopy 6769a3b18e Errors should not start with caps
- https://github.com/dexidp/dex/pull/1264#discussion_r253264017

Signed-off-by: Sabith <sabithksme@gmail.com>
2019-07-23 08:17:06 -07:00
Sabith K Soopy 6ccb96ff74 Add some test to validate the configuration 2019-07-23 08:16:16 -07:00
Stephan Renatus e3203382fc
Merge pull request #1493 from srenatus/sr/adopters
ADOPTERS: replace Documentation/production-users.md, add Chef
2019-07-23 17:08:11 +02:00
Stephan Renatus 7409d16541
ADOPTERS: add pusher
Co-Authored-By: Joel Speed <Joel.speed@hotmail.co.uk>
2019-07-23 16:58:26 +02:00
Stephan Renatus bc27a617c5
Merge pull request #1485 from bonifaido/mysql-storage
MySQL storage - Take 2
2019-07-23 15:25:15 +02:00
Stephan Renatus b8cdc88803
Merge pull request #1492 from srenatus/sr/add-bonifaido-to-maintainers
MAINTAINERS: add @bonifaido
2019-07-23 15:03:43 +02:00
Nandor Kracser a572ad8fec storage/sql: rework of the original MySQL PR 2019-07-23 14:27:10 +02:00
Pavel Borzenkov e53bdfabb9 storage/sql: initial MySQL storage implementation
It will be shared by both Postgres and MySQL configs.

Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
2019-07-23 14:26:21 +02:00
Stephan Renatus 447f24a81b
ADOPTERS: replace Documentation/production-users.md, add Chef
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-23 14:01:17 +02:00
Stephan Renatus af81297d4e
MAINTAINERS: add @bonifaido
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-23 13:03:18 +02:00
Stephan Renatus 421c26fdf5
Merge pull request #1481 from LanceH/master
Added "connector_id" to skip straight to a connector (similar to when len(connector) is 1.
2019-07-23 11:31:25 +02:00
LanceH 07a77e0dac Use connector_id param to skip directly to a specific connector 2019-07-22 10:47:11 -05:00
Stephan Renatus 6379403a68
Merge pull request #1486 from AlbanSeurat/tc/add-verify-password-api
Add VerifyPassword to API
2019-07-22 10:29:43 +02:00
Tyler Cloke dd84e73c0e Add VerifyPassword to API
It takes in an email and plain text password to verify. If it fails to find a password stored for email, it returns not_found. If it finds the password hash stored but that hash doesn't match the password passed via the API, it returns verified = false, else it returns verified = true.

Co-authored-by: Alban Seurat <alban.seurat@me.com>
2019-07-22 10:23:07 +02:00
Stephan Renatus 92920c86ea
Merge pull request #1480 from srenatus/sr/deduplicate-filter-groups
connectors: refactor filter code into a helper package
2019-07-08 10:29:01 +02:00
Stephan Renatus 10611f3156
deps: revendor (github.com/stretchr/testify)
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-03 13:30:59 +02:00
Stephan Renatus 51f50fcad8
connectors: refactor filter code into a helper package
I hope I didn't miss any :D

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-07-03 13:09:40 +02:00
Eric Chiang 39dc5dcfb7
Merge pull request #1478 from ericchiang/maintainers
MAINTAINERS: remove ericchiang@
2019-07-02 09:10:50 -07:00
Eric Chiang 645a441527 MAINTAINERS: remove ericchiang@
I haven't had time to contribute to dex recently and it's been over a
year since I've worked on Kubernetes. Going to make this official and
remove myself from the MAINTAINERS list. I'll still be around if you
need to know why any of the code is so crazy :)
2019-07-02 07:32:05 -07:00
Stephan Renatus 8b4dbb9fe7
Merge pull request #1473 from alindeman/add-user-endpoint
Add UserInfo endpoint
2019-07-02 09:26:26 +02:00
Andy Lindeman 5b66bf05c8 Fixed shadowed variable declaration 2019-06-27 19:12:18 -04:00
Andy Lindeman 59b6595c37 userinfo_endpoint is required 2019-06-25 12:17:03 -04:00
Andy Lindeman 8959dc4275 ctx is not used 2019-06-24 09:43:12 -04:00
Andy Lindeman 21174c06a1 Remove comment
We have a story around user info now
2019-06-24 09:42:46 -04:00
Andy Lindeman 840065faaf Assert something about the returned userinfo 2019-06-24 09:39:54 -04:00
Andy Lindeman 46f5726d11 Use oidc.Verifier to verify tokens 2019-06-22 13:18:35 -04:00
Andy Lindeman 157c359f3e Bump go-oidc to latest v2 2019-06-20 12:27:47 -04:00
mdbraber 3dd1bac821 Fix comments 2019-06-05 22:14:31 +02:00
Maarten den Braber 74f4e749b9 Formatting 2019-06-05 22:14:31 +02:00
Maarten den Braber d7750b1e26 Fix changes 2019-06-05 22:14:31 +02:00
Maarten den Braber a8d059a237 Add userinfo endpoint
Co-authored-by: Yuxing Li <360983+jackielii@users.noreply.github.com>
Co-authored-by: Francisco Santiago <1737357+fjbsantiago@users.noreply.github.com>
2019-06-05 22:11:21 +02:00
Stephan Renatus d6fad19d95
Merge pull request #1459 from flarno11/master
make userName configurable
2019-06-04 09:47:19 +02:00
Stephan Renatus c19ada3236
Merge pull request #1460 from tanmaykm/tan/linkedin
Update LinkedIn connector to use v2 APIs

This updates LinkedIn connector to use the more recent v2 APIs. Necessary because v1 APIs are not able to retrieve email ids any more with the default permissions.

The API URLs are now different. Fetching the email address is now a separate call, made after fetching the profile details. The r_basicprofile permission is not needed any more, and r_liteprofile (which seems to be the one assigned by default) is sufficient.

The relevant API specifications are at:

    https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api
    https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/primary-contact-api
    https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/migration-faq#how-do-i-retrieve-the-members-email-address
2019-06-03 19:35:55 +02:00
tan 8613c78863 update LinkedIn connector to use v2 APIs
This updates LinkedIn connector to use the more recent v2 APIs. Necessary because v1 APIs are not able to retrieve email ids any more with the default permissions.

The API URLs are now different. Fetching the email address is now a separate call, made after fetching the profile details. The `r_basicprofile` permission is not needed any more, and `r_liteprofile` (which seems to be the one assigned by default) is sufficient.

The relevant API specifications are at:
- https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api
- https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/primary-contact-api
- https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/migration-faq#how-do-i-retrieve-the-members-email-address
2019-06-03 22:59:37 +05:30
flarno11 8c1716d356 make userName configurable 2019-06-03 14:09:07 +02:00
Stephan Renatus dfb2dfd333
Merge pull request #1456 from srenatus/sr/post-1448/fix-1455/restore-error-semantics
connectors/oidc: truely ignore "email_verified" claim if configured that way
2019-05-28 16:23:00 +02:00
Stephan Renatus 4e8cbf0f61
connectors/oidc: truely ignore "email_verified" claim if configured that way
Fixes #1455, I hope.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-05-28 16:15:06 +02:00
Stephan Renatus e137db978d
Merge pull request #1457 from srenatus/sr/travis/use-go-1.1{1,2}.x
travis: replace golang 1.10 and 1.11 with 1.12
2019-05-28 16:14:43 +02:00
Stephan Renatus 11913a28c6
travis: replace golang 1.{10,11}.x with 1.12.x
This is because I suspect the gofmt rules change between these versions to
make half the travis CI tests fail sometimes?

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-05-28 16:07:20 +02:00
Stephan Renatus 49e59fb54f
Merge pull request #1448 from cappyzawa/user-id-key
oidc: Make userID configurable
2019-05-24 13:32:41 +02:00
cappyzawa 9650836851 make userID configurable 2019-05-24 19:52:33 +09:00
Eric Chiang 59560c9919
Merge pull request #1433 from jacksontj/userinfo
Add option in oidc to hit the optional userinfo endpoint
2019-05-23 09:42:13 -07:00
Thomas Jackson 52d09a2dfa Add option in oidc to hit the optional userinfo endpoint
Some oauth providers return "thin tokens" which won't include all of the
claims requested. This simply adds an option which will make the oidc
connector use the userinfo endpoint to fetch all the claims.
2019-05-23 09:20:48 -07:00
jimmythedog b189d07d53 dexidp#1440 Add offline_access scope, if required
Without this scope, a refresh token will not be returned from Microsoft
2019-05-14 05:15:13 +01:00
Eric Chiang cd3c6983da
Merge pull request #1429 from tsuna/master
server: add metrics for CORS handlers.
2019-05-12 10:40:23 -07:00
Eric Chiang 35f51957c0
Merge pull request #1430 from mkontani/fix/typo
fix typo
2019-05-12 10:39:18 -07:00
Eric Chiang 06ec381082
Merge pull request #1432 from alindeman/warnf
Round out logging interface with functions for all levels
2019-05-12 10:38:55 -07:00
Eric Chiang 0babb2df18
Merge pull request #1435 from bonifaido/bitbucket-docs
docs: update bitbucket permission requirements
2019-05-12 10:33:01 -07:00
Stephan Renatus 429bb9303f
Merge pull request #1443 from deric/err
Print appropriate error
2019-05-12 07:58:12 +02:00
Stephan Renatus d8f9634afc
Merge pull request #1436 from bonifaido/gitlab-groups
gitlab: support for group whitelist, add tests
2019-05-08 09:57:51 +02:00
Tomas Barton 55cebd58a8
print appropriate error 2019-05-03 14:19:54 +02:00
Nandor Kracser 7b416b5a8e gitlab: add tests 2019-05-02 08:06:56 +02:00
Nandor Kracser a08a5811d4 gitlab: support for group whitelist 2019-04-25 12:50:29 +02:00
Nandor Kracser b1931fc9bd docs: update bitbucket permission requirements 2019-04-25 10:45:00 +02:00
Andy Lindeman 34c7cfaf82
Round out logging interface with functions for all levels 2019-04-24 09:35:35 -04:00
mkontani 6ae76662de
fix ssoURL 2019-04-20 21:12:01 +09:00
Benoit Sigoure d6ad67a6de server: add metrics for CORS handlers. 2019-04-19 14:32:52 -07:00
Eric Chiang 60f47c4228
Merge pull request #1427 from yann-soubeyrand/static-client-log-name
cmd/dex/serve.go: log static client name instead of ID
2019-04-18 15:21:23 -07:00
Yann Soubeyrand c5f2871ab5 cmd/dex/serve.go: log static client name instead of ID
Signed-off-by: Yann Soubeyrand <yann.soubeyrand@gmx.fr>
2019-04-18 13:56:11 +02:00
Eric Chiang 29d8428387
Merge pull request #1426 from justaugustus/image
Update Docker build/image
2019-04-16 14:47:08 -07:00
Stephen Augustus 56f02b95c6 Update Docker build/image
- Update build container to golang:1.12.4-alpine
- Update dex image to alpine:3.9
- Run dex as non-root user

Signed-off-by: Stephen Augustus <saugustus@vmware.com>
2019-04-16 17:00:05 -04:00
Eric Chiang f6741d1837
Merge pull request #1417 from gezb/feature/odic_add_email_verfied_override
Add option to OIDC connecter to override email_verified to true
2019-03-05 14:49:02 -08:00
Gerald Barker fc723af0fe Add option to OIDC connecter to override email_verified to true 2019-03-05 21:24:02 +00:00
Eric Chiang 83a0326b88
Merge pull request #1412 from okamototk/typo
Fix typo.
2019-02-23 08:51:07 -08:00
Takashi Okamoto ac290f77aa Fix typo. 2019-02-23 16:34:10 +00:00
Eric Chiang c113df2730
Merge pull request #1408 from sagikazarmark/logger-interface
Add logger interface and stop relying on Logrus directly
2019-02-22 12:51:31 -08:00
Mark Sagi-Kazar d877fca092
Fix coding style 2019-02-22 21:43:55 +01:00
Mark Sagi-Kazar 06521ffa49
Remove the logrus logger wrapper 2019-02-22 21:31:46 +01:00
Mark Sagi-Kazar aec2edb441
Match the interface to logrus implementation 2019-02-22 21:27:54 +01:00
Mark Sagi-Kazar d1c8f8d095
Remove structured logging from the logger interface 2019-02-22 21:26:30 +01:00
Eric Chiang e913a252cd
Merge pull request #1410 from sagikazarmark/fix-typo
Fix typo
2019-02-22 12:02:27 -08:00
Mark Sagi-Kazar c48cb36e8f
Fix typo 2019-02-22 20:54:19 +01:00
Eric Chiang 8b4a9bf5ee
Merge pull request #1409 from bonifaido/production-users-banzaicloud
production users: add Banzai Cloud
2019-02-22 11:05:02 -08:00
Nandor Kracser 6c71b330a8 production users: add Banzai Cloud 2019-02-22 16:40:34 +01:00
Mark Sagi-Kazar be581fa7ff
Add logger interface and stop relying on Logrus directly 2019-02-22 13:38:57 +01:00
Stephan Renatus ca66289077
Merge pull request #1402 from lstoll/lstoll-mod-fix
Update modules for go 1.11.4+
2019-02-11 09:40:22 +01:00
Lincoln Stoll b96b02e506
Update modules for go 1.11.4+
Go 1.11.3 changed how checksums are created in some cases, which caused
failures building via modules. (ref golang/go#29278)

Update the checksums for the failing modules.

To catch this is the future, a modules build was added to the build matrix. I
also noted that we were pinning the `.0` patchlevel of each go version which
wouldn't have picked this up, updated it to build with the latest patch
release.
2019-02-09 14:59:30 +02:00
Stephan Renatus 7bd4071b4c
Merge pull request #1396 from jtnord/useLoginId-dexidp
Use github login as the id
2019-02-05 13:54:49 +01:00
Stephan Renatus 815311fa19
Merge pull request #1397 from ericchiang/health-check-endpoint
server: update health check endpoint to query storage periodically
2019-02-04 21:38:58 +01:00
Eric Chiang 8935a1479c server: update health check endpoint to query storage periodically
Instead of querying the storage every time a health check is performed
query it periodically and save the result.
2019-02-04 19:02:41 +00:00
James Nord fe247b106b remove blank line that tripped up `make verify-proto` 2019-02-04 14:06:06 +00:00
James Nord 9840fccdbb rename useLoginAsId -> useLoginAsID 2019-02-04 14:05:57 +00:00
Stephan Renatus be171a2a53
Merge pull request #1395 from hainesc/master
Display access token in example app
2019-02-04 14:24:01 +01:00
Joel Speed 8f113548a5
Merge pull request #1249 from srenatus/sr/add-ldap-filter-test
ldap_test: add filter tests
2019-02-03 15:58:54 +00:00
Stephan Renatus b6f4740a15
Merge pull request #1390 from okamototk/activedirectory
Add Active Directory and kubelogin integration sample.
2019-02-03 11:09:33 +01:00
Stephan Renatus df18cb0c22
ldap_test: add filter tests
The filters for user and group searches hadn't been included in our LDAP
tests. Now they are.

The concrete test cases are somewhat contrived, but that shouldn't
matter too much. Also note that the example queries I've used are not
supported in AD: https://stackoverflow.com/a/10043452

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-02-03 11:06:11 +01:00
James Nord 5822a5ce9e fix formatting of connector/github/github_test.go 2019-02-01 11:47:45 +00:00
James Nord 1911b52c6b Add documentation for the new GitHub useLoginAsId option 2019-02-01 11:37:40 +00:00
James Nord 03ffd0798c Allow an option to use the github user handle rather than an id.
For downstream apps using a github handle is much simpler than working
with numbers.

WHilst the number is stable and the handle is not - GitHUb does give you
a big scary wanring if you try and change it that bad things may happen
to you, and generally few users ever change it.

This can be enabled with a configuration option `useLoginAsId`
2019-02-01 11:37:40 +00:00
Haines Chan 18b6b34b67 Display access token in example app 2019-02-01 15:39:35 +08:00
Stephan Renatus b5826e66f0
Merge pull request #1394 from srenatus/sr/docs/maintainers
update MAINTAINERS, mirror guidelines into dev doc
2019-01-31 17:25:27 +01:00
Stephan Renatus 81f155882a
Merge pull request #1392 from stevendanna/tls-configuration
Bump minimum TLS protocol to TLSv1.2
2019-01-29 12:48:57 +01:00
Steven Danna 59f8b02d47
Set minimum TLS protocol version to TLSv1.2, set PreferServerCipherSuites
Some environments are subject to strict rules about the permitted TLS
protocol verion and available ciphers. Setting TLSv1.2 as the minimum
version ensures we do not use weaker protocols. We've opted against
making this configurable given the age of TLSv1.2 and the increasing
push to deprecate TLSv1.1 and older.

The PreferServerCipherSuites setting is also commonly flagged by SSL
quality scanning tools. Since Go provides a relatively modern set of
default ciphers by default, defaulting this to true is unlikely to
make much practical difference.

Signed-off-by: Steven Danna <steve@chef.io>
2019-01-29 11:18:55 +00:00
Stephan Renatus 4abf3b2102
docs: mirror resolution of #1281 in dev doc
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-01-29 10:29:12 +01:00
Stephan Renatus 2cfadcd95a
MAINTAINERS: add @JoelSpeed
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2019-01-29 10:25:55 +01:00
Takashi Okamoto 337bbe5f09 fix typos. 2019-01-26 10:44:50 +00:00
Takashi Okamoto 1b7b3515d7 Add Active Directory instruction. 2019-01-26 04:26:01 +00:00
Takashi Okamoto fbdb55aba9 Add doc for kubelogin and Active Directory ingtegration sample. 2019-01-26 04:16:55 +00:00
Takashi Okamoto 2d7de4ec70 Add Active Directory and kubeloing integration sample. 2019-01-26 04:15:50 +00:00
Stephan Renatus 5ae094206b
Merge pull request #1389 from ericchiang/bump-go
Dockerfile: update Go to 1.11.5
2019-01-24 08:52:33 +01:00
Eric Chiang 86eeee2ae2 Dockerfile: update Go to 1.11.5 2019-01-23 14:16:50 -08:00
Stephan Renatus f1581ff873
Merge pull request #1374 from kbalka/keystone-connector
PR contains connector for openstack keystone.

Features:

    access tokens
    refresh tokens
    groups

Requirements:

    access to openstack keystone instance
    keystone administrative account credentials

Enabling keystone connector specific tests:

    make sure docker is running
    export DEX_TEST_KEYSTONE=1
    make tests
2019-01-11 15:46:28 +01:00
Krzysztof Balka e8ba848907 keystone: fetching groups only if requested, refactoring. 2019-01-11 15:14:59 +01:00
joannano 88d1e2b041 keystone: test cases, refactoring and cleanup 2019-01-11 15:14:56 +01:00
Krzysztof Balka a965365a2b keystone: refresh token and groups 2019-01-11 15:14:11 +01:00
knangia 0774a89066 keystone: squashed changes from knangia/dex 2019-01-11 15:12:59 +01:00
Stephan Renatus 2d1ac74ec0
Merge pull request #1380 from dkess/emailsuffix
LDAP connector - add emailSuffix config option
2019-01-09 08:16:41 +01:00
Daniel Kessler ee54a50956 LDAP connector - add emailSuffix config option 2019-01-08 19:01:42 -08:00
Eric Chiang 27f66e795e
Merge pull request #1377 from hainesc/master
Replace "GET", "POST" to http.MethodGet and http.MethodPost
2018-12-27 10:41:47 -08:00
Haines Chan b78b8aeee0 Replace "GET", "POST" to http.MethodGet and http.MethodPost 2018-12-27 16:27:36 +08:00
Stephan Renatus 4329f407dc
Merge pull request #1373 from ericchiang/go-1.11.3
Dockerfile: update to Go 1.11.3
2018-12-14 08:43:32 +01:00
Eric Chiang bad15c1c02 Dockerfile: update to Go 1.11.3
Go 1.11.3 and 1.10.6 were released to mitigate security issues.
These don't appear to impact dex, but update anyway.

Ref: https://groups.google.com/forum/#!topic/golang-announce/Kw31K8G7Fi0
2018-12-13 15:12:49 -08:00
Stephan Renatus a3cf7b63b7
Merge pull request #1372 from babiel/configurable-auth-request-expiry
Make expiry of auth requests configurable

This is a band-aid against #1292

I did not change the default from 24h, but I think it should be much lower for safety.
2018-12-13 14:55:42 +01:00
Maximilian Gaß 74f84ce0be Change config test to non-default expiry settings 2018-12-13 14:47:51 +01:00
Maximilian Gaß 468c74d1d2 Make expiry of auth requests configurable 2018-12-13 11:50:34 +01:00
Stephan Renatus aafbaa36c5
Merge pull request #1357 from srenatus/sr/issue-1354
postgres: expose database/sql tunables

Fixes #1354.

I've not had a need for MaxIdleConns and ConnMaxLifetime myself, but it felt weird to only expose of the three settings.
2018-12-06 09:12:42 +01:00
Eric Chiang 60264d440c
Merge pull request #1369 from josdotso/go-modules-docs
Documentation/dev-dependencies.md: Update for Go modules
2018-12-04 13:14:22 -08:00
Joshua M. Dotson 46296ab9d0 Documentation/dev-dependencies.md: Update for Go modules 2018-12-04 20:06:22 +00:00
Stephan Renatus f5befb2e2d
Merge pull request #1368 from ericchiang/makefile-cleanups
Makefile: cleanups for newer versions of Go

Go 1.9 removed "./..." matching the vendor directory while Go 1.10 added
build and test caching. This means we no longer need to grep out
vendored matches (except for golint which doesn't implement the same
behavior), and we no longer need to pre-build packages with "go build -i".

https://golang.org/doc/go1.9#vendor-dotdotdot
https://golang.org/doc/go1.10#build
2018-12-04 08:44:29 +01:00
Eric Chiang 1a565266fc Makefile: cleanups for newer versions of Go
Go 1.9 removed "./..." matching the vendor directory while Go 1.10 added
build and test caching. This means we no longer need to grep out
vendored matches (except for golint which doesn't implement the same
behavior), and we no longer need to pre-build packages with "go build -i".

https://golang.org/doc/go1.9#vendor-dotdotdot
https://golang.org/doc/go1.10#build
2018-12-03 10:01:18 -08:00
Eric Chiang 8a479707b3
Merge pull request #1365 from josdotso/migrate-to-go-modules
Migrate to go modules
2018-12-03 09:55:32 -08:00
Joshua M. Dotson eaeab218b8 vendor: make revendor 2018-12-03 17:13:56 +00:00
Joshua M. Dotson 172df9ccef *: remove glide and add Go module files 2018-12-03 17:13:49 +00:00
Stephan Renatus 17ac7c8a86
Merge pull request #1367 from srenatus/sr/cherry-pick-lib/pq-bump
bump lib/pq

taken from @vito's #1342.
2018-12-02 10:29:35 +01:00
Stephan Renatus 73fdf4f75b
storage/sql/postgres: expose stdlib tunables, set them for tests
- adapted TestUnmarshalConfig to ensure the fields are read in
- added a test to see that at least MaxOpenConns works:
  - this is only exposed through (*db).Stats() in go 1.11, so this test
    has a build tag
  - the other two configurables can't be read back, so we've got to
    trust that the mechanism works given the one instance that's tested..

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-30 09:55:01 +01:00
Alex Suraci badbc8c738
bump lib/pq 2018-11-29 09:10:50 +01:00
Stephan Renatus d91f9fbc51
Merge pull request #1366 from dexidp/revert-1342-pr/retry-on-pg-serialization-error
Revert "retry on serialization errors"

This will come back, as outline here: https://github.com/dexidp/dex/pull/1356#issuecomment-442523779
2018-11-29 09:09:31 +01:00
Stephan Renatus 8f3cca7ba4
Revert "retry on serialization errors" 2018-11-29 08:24:13 +01:00
Stephan Renatus f3acec0b1b
Merge pull request #1275 from ccojocar/client-update-api
Extend the API with a function which updates the client configuration
2018-11-27 11:47:16 +01:00
Cosmin Cojocar 01c6b9dd91 Remove the 'public' field from UpdateClientReq proto message 2018-11-26 19:07:59 +01:00
Stephan Renatus 007e4dae3c
Merge pull request #1358 from OwenTuz/issue-1132-initial-kubernetes-documentation-improvements
Kubernetes docs: clarify steps around use/creation of TLS assets.
2018-11-26 13:54:44 +01:00
Stephan Renatus 5355b81e2a
Merge pull request #1359 from OwenTuz/issue-1190-document-capitalisation-of-dn
LDAP connector - Document that 'DN' must be in capitals
2018-11-26 13:07:35 +01:00
Owen Tuz 9ea2ade208 LDAP docs - remove extra wording re DN 2018-11-26 11:50:44 +00:00
Owen Tuz e603a5e631 LDAP connector - Document that 'DN' must be in capitals 2018-11-26 10:02:41 +00:00
Owen Tuz 9b5122568a Kubernetes docs: replace absolute link with relative 2018-11-23 13:54:49 +00:00
Owen Tuz 72c9cf43a9 Fix comment in LDAP query documentation 2018-11-23 11:00:18 +00:00
Owen Tuz 45eb9b279b Kubernetes docs: wording nitpicks 2018-11-23 10:53:37 +00:00
Owen Tuz 58093dbb29 Kubernetes example: Add RBAC resources and serviceAccount to YAML manifest, remove some references to deprecated TPR approach 2018-11-23 10:48:00 +00:00
Owen Tuz e028b79c97 Kubernetes docs: clarify steps around use/creation of TLS assets. 2018-11-22 13:37:50 +00:00
Stephan Renatus 5f054fcf2e
Merge pull request #1342 from concourse/pr/retry-on-pg-serialization-error
retry on serialization errors
2018-11-21 10:29:46 +01:00
Stephan Renatus f7f7314fdb
Merge pull request #1350 from srenatus/sr/storage/nuke-standup-scripts
storage: nuke standup scripts, adapt dev-integration-test docs
2018-11-20 17:13:31 +01:00
Alex Suraci 85dd0684ba extract and document serialization failure check 2018-11-20 10:50:55 -05:00
Alex Suraci 587081a643 postgres: refactor error handling to fix retrying
prior to this change, many of the functions in the ExecTx callback would
wrap the error before returning it. this made it impossible to check
for the error code.

instead, the error wrapping has been moved to be external to the
`ExecTx` callback, so that the error code can be checked and
serialization failures can be retried.
2018-11-20 10:50:55 -05:00
Alex Suraci 5d67da1472 bump lib/pq 2018-11-20 10:50:55 -05:00
Alex Suraci aa068b667a postgres: improve readability of error check 2018-11-20 10:50:55 -05:00
Alex Suraci 9b9013a560 postgres: use stdlib to set serializable tx level
also use a context for the rollback, which is a bit cleaner since it
only results in one 'defer', rather than N from the loop
2018-11-20 10:50:55 -05:00
Alex Suraci 7e96021428 retry on serialization errors 2018-11-20 10:50:55 -05:00
Stephan Renatus 6182f213ef
storage/conformance: remove old build tags
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-20 16:41:13 +01:00
Stephan Renatus 58b546a5be
dev-integration-test: add etcd notes
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-20 16:41:12 +01:00
Stephan Renatus 0740c2370d
storage/etcd: remove standup.sh
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-20 16:41:12 +01:00
Stephan Renatus cbcb1f61f3
dev-integration-tests: update database steps (just use docker)
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-20 16:41:12 +01:00
Stephan Renatus 1d0568efe9
storage/sql: remove standup.sh
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-20 16:41:12 +01:00
Stephan Renatus efb15205e9
Merge pull request #1352 from concourse/pr/support-pq-host-port
pg: support host:port for backwards-compatibility
2018-11-20 16:38:56 +01:00
Stephan Renatus d40043808b
Merge pull request #1345 from concourse/pr/github-team-name-and-slug
Add 'both' option to use team name AND slug in TeamNameField

This allows the connector to be configured with both so that both team names and slugs can be returned in the groups. This makes configuring teams in an application a bit more foolproof; we would often have confusion over whether the team name or slug should be given by the user, so it's easier to just allow both, since collisions shouldn't be possible anyway.
2018-11-20 16:30:54 +01:00
Alex Suraci 0b856d1a75 pg: support host:port for backwards-compatibility 2018-11-20 10:22:39 -05:00
Josh Winters bb11a1ebee github: add 'both' team name field option
this will result in both the team name *and* the team slug being
returned for each team, allowing a bit more flexibility in auth
validation.

Signed-off-by: Topher Bullock <tbullock@pivotal.io>
Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
2018-11-20 10:12:44 -05:00
Stephan Renatus b1fd2fa8b1
Merge pull request #1346 from concourse/pr/postgres-unix-sockets
Use pq connection parameters instead of URLs for postgres connections

This enables the use of socket paths like /var/run/postgresql for the 'host' instead of requiring TCP. Also, we know allow using a non-default port.
2018-11-20 15:52:40 +01:00
Divya Dadlani f82b904d05 postgres: use connection string instead of url
otherwise it's impossible to use a Unix socket, as the path gets escaped
awkwardly.

Signed-off-by: Ciro S. Costa <cscosta@pivotal.io>
Signed-off-by: Alex Suraci <suraci.alex@gmail.com>
2018-11-20 09:32:44 -05:00
Stephan Renatus 7c8a22443a
Merge pull request #1349 from alexmt/1102-config-to-load-all-groups
Add config to explicitly enable loading all github groups

Follow-up for #1102.
2018-11-20 15:15:25 +01:00
Stephan Renatus 84ea412ca6
Merge pull request #1351 from CognotektGmbH/gypsydiver/1347-pr-gitlab-groups
Gitlab connector should not require the api scope.

Fixes #1347.
2018-11-20 14:49:11 +01:00
gypsydiver f21e6a0f00 gypsydiver/1347-pr-gitlab-groups 2018-11-20 11:18:50 +01:00
Stephan Renatus 42997448a7
Merge pull request #1343 from concourse/pr/remove-mysql-cockroachdb-drivers
remove incomplete mysql and cockroachdb support
2018-11-20 10:01:17 +01:00
Stephan Renatus 4738070951
Merge pull request #1338 from srenatus/sr/update-go-ldap
update go-ldap, improve errors
2018-11-20 08:02:13 +01:00
Alexander Matyushentsev 7bd084bc07 Issue #1102 - Add config to explicitly enable loading all github groups 2018-11-19 10:14:38 -08:00
Alex Suraci 7c63be4104 remove incomplete mysql and cockroachdb support 2018-11-16 18:07:20 +00:00
Stephan Renatus 2425c6ea63
Merge pull request #1340 from alexmt/1184-github-groups
Issue #1184 - Github connector now returns a full group list when no org is specified
2018-11-16 15:48:33 +01:00
Stephan Renatus 13a1679892
Merge pull request #1344 from concourse/pr/fix-conformance-time-comparison
fix bogus conformance failure due to time zones
2018-11-16 08:52:40 +01:00
Alexander Matyushentsev 20bc6cd353 Full list of groups should include group names as well as group_name:team_name 2018-11-15 14:12:50 -08:00
Alex Suraci dcca427592 fix bogus conformance failure due to time zones
this failed on my machine due to the unexported 'loc' field of the time
structure - it was nil in one and set to a ton of tiemzone data in the
other. instead let's just compare the unix timestamp value and zero it
out for the struct comparison.
2018-11-15 13:51:07 -05:00
Stephan Renatus 5236b2c819
Merge pull request #1339 from alexmt/1263-connector-error-message
Issue #1263 - Render error message provided by connector if user authentication failed
2018-11-15 19:06:30 +01:00
Alexander Matyushentsev e5ebcf518a Update github connector documentation 2018-11-15 09:24:21 -08:00
Alexander Matyushentsev ce3cd53a11 Bug fix: take into account 'teamNameField' settings while fetching all user groups 2018-11-15 09:23:57 -08:00
Alexander Matyushentsev e876353128 Rename variables to stop shadowing package name 2018-11-15 09:00:37 -08:00
Alexander Matyushentsev a9f71e378f Update getPagination method comment 2018-11-15 08:57:31 -08:00
Alexander Matyushentsev e10b8232d1 Apply reviewer notes: style changes, make sure unit test verifies pagination 2018-11-15 08:12:28 -08:00
Alexander Matyushentsev 51d9b3d3ca Issue #1184 - Github connector now returns a full group list when no org is specified 2018-11-14 15:31:31 -08:00
Alexander Matyushentsev ff8b44558e Issue #1263 - Render error message provided by connector if user authentication failed 2018-11-13 15:44:28 -08:00
Cosmin Cojocar 281ec27118 Update also to a list of empty redirect URIs and Peers 2018-11-13 09:59:45 +01:00
Cosmin Cojocar 9d1ec6c36b Revert "Avoid overwriting exiting redirect URI and trusted peers when updating the client"
This reverts commit 49fa5ee6e8.
2018-11-13 09:58:17 +01:00
Stephan Renatus c14b2fd5a5
connector/ldap: slightly improve error output
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-13 09:40:40 +01:00
Stephan Renatus 3295084236
deps: revendor
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-13 07:54:16 +01:00
Cosmin Cojocar 49fa5ee6e8 Avoid overwriting exiting redirect URI and trusted peers when updating the client
Also skip configure the Public field.
2018-11-12 21:48:14 +01:00
Stephan Renatus 1723e13fed
glide.yaml: bump gopkg.in/ldap.v2
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-11-12 19:37:37 +01:00
Cosmin Cojocar 6536d97812 Regeneated the gRPC API in order to update the comment 2018-11-12 18:50:12 +01:00
Cosmin Cojocar c9b18b2785 Add tests for UpateClient API 2018-11-12 18:43:48 +01:00
Cosmin Cojocar 6531b256e2 Fix typo 2018-11-12 17:34:13 +01:00
Cosmin Cojocar 9926a0dced Extend the API with a function which updates the client configuration 2018-11-12 17:33:06 +01:00
Eric Chiang 57b1031352
Merge pull request #1334 from tmatias/patch-1
point users to storage/RBAC docs
2018-11-06 21:27:28 -08:00
Eric Chiang 505aac753d
Merge pull request #1333 from SongGithub/master
allow it to disable CRD creation
2018-11-05 18:40:53 -08:00
Song.Jin 5f0a03a06b modify log msg as per suggested 2018-11-06 11:18:55 +11:00
Tiago Matias 44e988fb41
point users to storage/RBAC docs 2018-11-05 17:43:23 -02:00
Song.Jin 9b5bec1ddf check if crd exist before try creating them 2018-11-04 11:43:28 +11:00
Song.Jin d2daa4e2ac allow it to disable CRD creation 2018-11-02 21:13:37 +11:00
Stephan Renatus 65b0c91992
Merge pull request #1245 from scotthew1/mock-connector-refresh
add Refresh() to mock passwordConnector
2018-10-25 16:38:08 +02:00
Stephan Renatus f903a2890e
Merge pull request #1329 from ericchiang/lint
*: vendor golint to prevent upstream changes from breaking the build
2018-10-25 10:56:00 +02:00
Eric Chiang e11446aff0 vendor: make revendor 2018-10-24 14:59:44 -07:00
Eric Chiang 50b96564f5 *: vendor golint to prevent upstream changes from breaking the build
golint has updated or dropped support for old Go versions several times,
causing breaks in our build. Vendor it locally to prevent this.
2018-10-24 14:59:44 -07:00
Eric Chiang 867130e22e
Merge pull request #1325 from ericchiang/go
*: update go version
2018-10-24 14:16:23 -07:00
Eric Chiang 5514805cf0 *: update go version 2018-10-22 17:44:24 -07:00
Eric Chiang 9f91ae0255
Merge pull request #1319 from dannysauer/oidc_doc
Add mention of `scopes` parameter in OIDC doc
2018-10-17 09:16:25 -07:00
Danny Sauer b9b21260bc
Add mention of `scopes` parameter in OIDC doc 2018-10-17 10:48:39 -05:00
Eric Chiang 0db538a4bb
Merge pull request #1316 from edtan/fix-broken-markdown-link
Fix broken link to Bitbucket Cloud documentation
2018-10-14 20:49:00 -07:00
Ed Tan 56eeb07e85 Fix broken link to Bitbucket Cloud documentation 2018-10-14 21:45:21 -04:00
Eric Chiang fcf4371b1b
Merge pull request #1317 from ericchiang/fix-golint-import
.travis.yml: fix golint import
2018-10-14 18:30:50 -07:00
Eric Chiang 73498316c7 .travis.yml: fix golint import 2018-10-14 17:42:51 -07:00
Stephan Renatus e1acb6d577
Merge pull request #1307 from edtan/upstream-add-bitbucket-connector
Add Bitbucket connector
2018-10-12 09:02:21 +02:00
Stephan Renatus a1b6ba9bba
Merge pull request #1311 from dannysauer/speling
minor spelling correction
2018-10-10 10:12:58 +02:00
Danny Sauer 74bfbcefbc
minor spelling correction 2018-10-09 15:57:37 -05:00
Ed Tan 50afa921b5 Remove unused DisplayName 2018-10-06 12:13:55 -04:00
Ed Tan 6ffc8fcd8d Rename bitbucket to bitbucketcloud 2018-10-06 11:45:56 -04:00
Ed Tan d26e23c16f Make suggested code changes 2018-10-05 10:43:49 -04:00
Ed Tan 2c024d8caf Fix golint issues 2018-09-30 15:43:50 -04:00
Ed Tan 8c75d85b60 Add Bitbucket connector 2018-09-30 15:08:07 -04:00
Stephan Renatus b58053eefc
Merge pull request #1305 from srenatus/sr/fix-1304
connector/saml: make unparsable (trailing, non-space/newline) data an error
2018-09-30 11:20:35 +02:00
Stephan Renatus 26c0206627
connector/saml: make unparsable (trailing, non-space/newline) data an error
Fixes #1304, if we want to be harsh.

However, I think if it was the user's intention to pass two certs, and
the second one couldn't be read, that shouldn't just disappear. After
all, when attempting to login later, that might fail because the
expected IdP cert data isn't there.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-29 11:09:33 +02:00
Stephan Renatus ff70c0453f
Merge pull request #1278 from veily/master
Support used self-signed certificates LDAP.
2018-09-22 18:05:26 +02:00
veily 317f433a14
support self-signed certificates ldap
Format ldap.go

Format ldap.go: with a space for golint

with a space

Rename clientCA is to clientCert

Update ldap.go

modified the ldap client certificate file comments.

modified load ldap client cert error.

modified load ldap client cert error: fmt.Errorf("ldap: load client cert failed: %v", err)
2018-09-22 12:15:11 +08:00
Scott Reisor 2707302054 add Refresh() to mock passwordConnector 2018-09-21 11:55:14 -04:00
Eric Chiang 316acbee03
Merge pull request #1299 from fajran/update-go-jose
Update go-jose to v2.1.8
2018-09-18 15:31:32 -07:00
Fajran Iman Rusadi a823c021c8 Update go-jose to v2.1.8 2018-09-18 23:55:14 +02:00
Eric Chiang 06241eae9f
Merge pull request #1297 from tburko/use-github-team-slug-instead-of-name
Allow using GitHub Team slug instead of name via connector config option
2018-09-14 10:26:11 -07:00
Taras Burko bf39130bab Configurable team name field for GitHub connector 2018-09-14 01:09:48 +03:00
Eric Chiang 29bc098620
Merge pull request #1290 from srenatus/sr/release-process/update-quay-notes
release process: update quay notes
2018-09-10 08:58:38 -07:00
Stephan Renatus 1260c62a80
Merge pull request #1296 from srenatus/sr/nuke-check-go-version
scripts,Makefile: nuke check-go-version
2018-09-10 17:55:01 +02:00
Stephan Renatus 86a3346b64 scripts,Makefile: nuke check-go-version
Fixes #1291

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-10 16:34:00 +02:00
Stephan Renatus 666356d22d
Merge pull request #1266 from byxorna/gabe/fix-etcd-timeout-bug
fix timeout bug for etcd3 client connect
2018-09-10 10:36:38 +02:00
Stephan Renatus 4a6da13097
Merge pull request #1253 from vasartori/master
Fix #1252
2018-09-10 08:12:17 +02:00
Victor Sartori 1ea1d809a1 Update alpine to 3.8 2018-09-06 16:31:58 -03:00
Stephan Renatus 9cc85c447c examples/k8s: reference quay.io/dexidp
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-06 09:10:01 +02:00
Stephan Renatus 1309c1f037 dev-releases.md, Makefile: update release process
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-06 09:09:46 +02:00
Eric Chiang bb75dcd793
Merge pull request #1283 from srenatus/sr/move-github-org/fix-imports
Finish GitHub org move
2018-09-05 09:14:06 -07:00
Stephan Renatus 9f10e5d020 revendor
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-05 17:57:08 +02:00
Stephan Renatus 14b89029c9 bill-of-materials: nuke
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-05 17:57:08 +02:00
Stephan Renatus b9f6594bf0 *: github.com/coreos/dex -> github.com/dexidp/dex
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-05 17:57:08 +02:00
Stephan Renatus 974617a426
Merge pull request #1285 from srenatus/sr/ldap/treat-bind-constraint-violation-as-bad-login
connectors/ldap: treat 'constraint violation' on bind as bad credentials
2018-09-05 10:18:51 +02:00
Stephan Renatus 6a2d4ab6b4 connectors/ldap: treat 'constraint violation' on bind as bad credentials
Some directory servers (I think it's Oracle) return

    Constraint Violation: Exceed password retry limit. Account locked.

when attempting to login too many times. While constraint violation can
mean many things, we're checking this as an error on BIND, so it's
more likely that something like this has happened than any other thing.

Hence, we should treat it as an "incorrect password" situation, not an
internal error.

It would of course be preferrable to surface more information about this
precise error (and similar ones), but I think this is beyond this small
change.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-09-05 10:03:17 +02:00
rithu leena john 3bbc2c0bde
Merge pull request #1280 from rithujohn191/maintainer-list
*: update the maintainers list
2018-09-04 10:36:57 -07:00
Eric Chiang 4dc3347106
Merge pull request #1279 from AnianZ/master
fix default baseURL for GitLab connector
2018-09-04 08:09:37 -07:00
Stephan Renatus 4caf82c1e9
Merge pull request #1258 from montaro/fix-odic-doc-broken-link
Fix a broken link in the oidc readme
2018-09-03 09:16:19 +02:00
Stephan Renatus cabdcb1eb0
Merge pull request #1259 from montaro/fix-typo-in-README
fix typo in README
2018-09-03 09:15:18 +02:00
Stephan Renatus e3e37504ca
Merge pull request #1269 from tw3rp/patch-1
[version_update] Update the version to the latest
2018-09-03 09:09:05 +02:00
rithu john 9de19cb899 *: update the maintainers list 2018-08-31 17:26:49 -07:00
Anian Z 5454a4729f fix default baseURL for gitlab connector 2018-08-28 19:05:30 +02:00
tw3rp 49bbcd343f
[version_update] Update the version to the latest
Version mentioned in this example is very old and was causing issues
2018-08-05 15:48:11 -07:00
Gabe Conradi 94bd948aac fix timeout bug for etcd3 client connect 2018-08-02 17:41:38 -04:00
Ahmed ElRefaey b71bec2ba1
fix typo in README 2018-07-04 15:11:52 +02:00
Ahmed ElRefaey 32e9570116
Fix a breoken link in the oidc readme
Fixed a broken link to An overview of OpenID Connect
2018-07-04 14:56:29 +02:00
Victor Sartori 780a359f8e Fix #1252 2018-06-19 10:45:20 -03:00
Eric Chiang 036e5d050d
Merge pull request #1226 from joedborg/examples-cleanup
Removing whitespace
2018-05-14 16:11:00 -07:00
Eric Chiang 384db1f33e
Merge pull request #1231 from mklan/patch-1
Update using-dex.md
2018-05-14 16:10:41 -07:00
Eric Chiang 0822f1d4d3
Merge pull request #1232 from silenceshell/patch-1
fix typo
2018-05-14 16:10:19 -07:00
Eric Chiang bf3ffb53a0
Merge pull request #1233 from kpschuck/master
Updates go to 1.10.2 to support SHA-512 for ldaps
2018-05-14 09:23:00 -07:00
Kevin Schuck ca3d73c36d Updates go to 1.10.2 to support SHA-512 for ldaps 2018-05-10 11:23:50 -05:00
silenceshell 468b5e3f0a
fix typo
Should `pulic`  be `public`?
2018-05-10 11:55:11 +08:00
Matthias Klan 481f1276a8
Update using-dex.md
fix wrong port from example
2018-05-04 16:14:16 +02:00
Joe Borg fc8b20ba35 Removing whitespace 2018-04-27 09:28:52 +01:00
Eric Chiang 0d3edf2456
Merge pull request #1208 from ericchiang/go10
*: update build to Go 1.10
2018-03-20 15:08:43 -07:00
Eric Chiang 264484075a
*: update build to Go 1.10 2018-03-20 14:50:33 -07:00
Eric Chiang f2eac0e723
Merge pull request #1200 from carbin-gun/master
Update check go major version way
2018-03-07 10:38:48 -07:00
charles.deng d92c21b9f9
Update check go major version way
the previous one just keep one prefix number as the major number, it should be the whole number after the dot.
2018-03-07 23:34:08 +08:00
Eric Chiang 218d671a96
Merge pull request #1198 from srenatus/sr/add-test-case-for-tampered-nameid-field-with-comment
saml: add tests case covering tampered NameID field (comment)
2018-03-01 15:17:32 -08:00
Stephan Renatus 608260d0f1 saml: add tests case covering tampered NameID field (comment)
As sketched here:

https://developer.okta.com/blog/2018/02/27/a-breakdown-of-the-new-saml-authentication-bypass-vulnerability

Thought it was interesting to see how our SAML connector behaved. And
it seems to be behaving well. :)

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-02-28 08:42:17 +01:00
Eric Chiang 39a66d1496
Merge pull request #1195 from Skn0tt/patch-1
Add missing word
2018-02-27 10:37:31 -08:00
Simon Knott 822a10cede
Add missing word 2018-02-24 11:31:51 +01:00
Eric Chiang 01d63b086f
Merge pull request #1176 from vyshane/master
New id_provider scope that adds the connector ID and user ID to the ID token claims
2018-02-03 11:47:42 -08:00
Vy-Shane Xie b03c85e56e Add new federated:id scope that causes Dex to add a federated_claims claim containing the connector_id and user_id to the ID token 2018-02-03 18:40:03 +08:00
Eric Chiang ce686390a5
Merge pull request #1144 from srenatus/sr/support-direct-post-without-get-first
handlers/connector_login: update AuthRequest irregardless of method
2018-02-01 11:26:57 -08:00
Eric Chiang c0bcc81997
Merge pull request #1171 from pmcgrath/1170-fix-typos
1170 - Fix comment typos
2018-02-01 11:19:56 -08:00
pmcgrath 4aec353aec 1170 - Fix comment typos
BsaeDN should be BaseDN
2018-01-14 12:34:45 +00:00
Eric Chiang 1dbecefadf
Merge pull request #1166 from ericchiang/coc
automated PR: update CoC and legalese
2018-01-08 15:41:30 -08:00
Eric Chiang f83c86cead
Merge pull request #1168 from ericchiang/connector-docs
README: expand connector docs and assign each a level of support
2018-01-05 09:27:19 -08:00
Eric Chiang ea2c63d7b0 README: expand connector docs and assign each a level of support 2018-01-05 09:06:18 -08:00
Eric Chiang 2851b3c7a6
Merge pull request #1167 from ericchiang/restructure-connector-docs
Documentation: restructure connector docs to a single folder
2018-01-04 13:59:52 -08:00
Eric Chiang 460f48320e Documentation: restructure connector docs to a single folder 2018-01-04 13:50:14 -08:00
Eric Chiang 2215158b2a update CoC and legalese 2018-01-04 12:14:31 -08:00
Eric Chiang 6ef8cd512f
Merge pull request #1155 from brancz/prometheus
Add Prometheus metrics
2017-12-21 12:32:44 -08:00
Frederic Branczyk 0930b09e4e
vendor: Add metrics packages 2017-12-21 21:24:14 +01:00
Frederic Branczyk 5f03479d29
*: Add go runtime, process, HTTP and gRPC metrics 2017-12-21 21:24:09 +01:00
Eric Chiang 053c476c4f
Merge pull request #1157 from ericchiang/conn-oidc-doc-groups
document limitations in the OpenID Connect connector
2017-12-20 17:20:21 -08:00
Eric Chiang 0811d1a07a document limitations in the OpenID Connect connector 2017-12-20 17:12:00 -08:00
Eric Chiang b5baf6b1ca
Merge pull request #1152 from diegs/bom
license: add bill of materials.
2017-12-19 10:31:43 -08:00
Diego Pontoriero 6d4fef4b9a
license: add bill of materials. 2017-12-19 10:23:27 -08:00
Eric Chiang 9d4b1041bd
Merge pull request #1151 from topos-ai/email-address
Clarify email scope description
2017-12-17 10:36:58 -08:00
Eric Buth da45adcb6e email scope only allows access to a user's email address 2017-12-17 12:08:19 -05:00
Stephan Renatus f013a44581 handlers/connector_login: check before update (optimization)
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2017-12-11 08:32:22 +01:00
Eric Chiang ec5e2cc3c6
Merge pull request #1135 from mpashka/master
Update slapd.sh
2017-12-08 15:26:14 -06:00
Pavel Moukhataev 5ef1312b38 Add note for OpenLDAP installation 2017-12-08 23:53:36 +03:00
Stephan Renatus f18d7afc6f handlers/connector_login: update AuthRequest irregardless of method
Before, you could not POST your credentials to a password-connector's
endpoint without GETing that endpoint first. While this makes sense for
browser clients; automated interactions with Dex don't need to look at
the password form to fill it in.

A symptom of that missing GET was that the POST succeeded (!) with

    login successful: connector "", username="admin", email="admin@example.com", groups=[]

Note the connector "". A subsequent call to finalizeLogin would then
fail with

    connector with ID "" not found: failed to get connector object from storage: not found

Now, the connector ID of an auth request will be updated for both GETs
and POSTs.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2017-12-08 11:49:52 +01:00
Eric Chiang 5172a46171
Merge pull request #1143 from wkalt/fix-verifier-creation-typo
Correct "Verifier" method name in using-dex doc
2017-12-05 17:47:11 -05:00
Wyatt Alt e7d57bb31b Correct "Verifier" method name in using-dex doc
Change provider.NewVerifier to provider.Verifier per the godocs:
https://godoc.org/github.com/coreos/go-oidc#Provider.Verifier
2017-12-05 13:38:11 -08:00
Eric Chiang 18da628842
Merge pull request #1142 from zlabjp/status-code
Bugfix: Set a proper status code before sending an error status page
2017-12-04 00:04:28 -05:00
rithu leena john 32257bcf8e
Merge pull request #1140 from ericchiang/fix-proto-build
*: fix proto build
2017-12-01 14:02:11 -08:00
Eric Chiang c5de6fa733 *: regenerate proto 2017-12-01 11:29:33 -08:00
Eric Chiang ab102b8189 *: revendor 2017-12-01 10:32:04 -08:00
Eric Chiang 35063da41e *: pin protoc-gen-go dependencies 2017-12-01 10:32:04 -08:00
Kazumasa Kohtaka 9948228e5b Set a proper status code before sending an error status page 2017-12-01 14:23:45 +09:00
Eric Chiang 861d4ae447
Merge pull request #1131 from pborzenkov/microsoft
Implement Microsoft (Azure AD) connector
2017-11-28 09:33:11 -08:00
Eric Chiang c872938298
Merge pull request #1136 from vyshane/master
Specify Java package for dex Protobuf API
2017-11-28 09:20:59 -08:00
Vy-Shane Xie 19cb2a5ffb Specify Java package option 2017-11-28 20:35:34 +08:00
Pavel Borzenkov 47df6ea2ff connector/microsoft: add support for groups
Microsoft connector now provides support for 'groups' claim in case
'tenant' is configured in Dex config for the connector. It's possible to
deny user authentication if the user is not a member of at least one
configured groups.

Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
2017-11-23 17:01:34 +03:00
Pavel Borzenkov 6193bf5566 connector: implement Microsoft connector
connector/microsoft implements authorization strategy via Microsoft's
OAuth2 endpoint + Graph API. It allows to choose what kind of tenants
are allowed to authenticate in Dex via Microsoft:
  * common - both personal and business/school accounts
  * organizations - only business/school accounts
  * consumers - only personal accounts
  * <tenant uuid> - only account of specific tenant

Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
2017-11-23 17:01:34 +03:00
Eric Chiang f4b6bf2ac3
Merge pull request #1123 from srenatus/sr/back-button-for-password-template
show "back" link for password connectors
2017-11-13 10:58:25 -08:00
rithu leena john bc01767212
Merge pull request #1124 from ericchiang/remove-milestones-link
README.md: remove milestones link
2017-11-13 09:48:42 -08:00
Stephan Renatus 41f663f70c show "back" link for password connectors
This way, the user who has selected, say, "Log in with Email" can make up
their mind, and select a different connector instead.

However, if there's only one connector set up, none of this makes sense -- and
the link will thus not be displayed.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2017-11-13 08:39:59 +01:00
Eric Chiang b746ab4975 README.md: remove milestones link 2017-11-10 11:28:03 -08:00
Eric Chiang 75a07f2bfa
Merge pull request #1116 from srenatus/sr/local-users/say-email-in-login
password connectors: make prompt configurable
2017-11-10 11:25:02 -08:00
Stephan Renatus b09a13458f password connectors: allow overriding the username attribute (password prompt)
This allows users of the LDAP connector to give users of Dex' login
prompt an idea of what they should enter for a username.

Before, irregardless of how the LDAP connector was set up, the prompt
was

    Username
    [_________________]

    Password
    [_________________]

Now, this is configurable, and can be used to say "MyCorp SSO Login" if
that's what it is.

If it's not configured, it will default to "Username".

For the passwordDB connector (local users), it is set to "Email
Address", since this is what it uses.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2017-11-09 09:30:03 +01:00
Eric Chiang 04e276f2df
Merge pull request #1120 from ericchiang/update-maintainers
*: update maintainers
2017-11-08 15:46:31 -08:00
Eric Chiang df075d8bda *: update maintainers 2017-11-08 14:19:07 -08:00
Eric Chiang 97d395e351
Merge pull request #1119 from ericchiang/update-go-requirements
*: Go 1.7 no longer supported and updated build image to 1.9
2017-11-08 13:49:08 -08:00
Eric Chiang b58fba6753 *: Go 1.7 no longer supported and updated build image to 1.9 2017-11-08 13:33:01 -08:00
Eric Chiang ccf85a7269
Merge pull request #1108 from dqminh/etcd-storage
Add etcd backed storage
2017-11-06 08:36:43 -08:00
Daniel Dao e617197871 storage/etcd: document struct tag in code
This explicitly adds struct tags for etcd storage instead of implicitly
depends on yaml/json config serialization.
2017-11-06 14:46:18 +00:00
Daniel Dao a2188bebf1 add documentation for etcd storage
This adds references to etcd storage, including:
- only supports etcd v3
- list of options and their meanings when connecting to etcd cluster
2017-11-06 14:40:25 +00:00
Daniel Dao fc1c60ed8f add etcd to travis CI
This patch uses docker to run an etcd container in travis CI so we can
run storage/etcd conformance tests.
2017-11-06 14:23:25 +00:00
Eric Chiang e623bd626e
Merge pull request #1112 from ggreer/ldap-css
Add tectonic-ldap matching rule to ldap icon.
2017-11-03 11:27:27 -07:00
Geoff Greer 3dfc4b430e Add tectonic-ldap matching rule to ldap icon. Fixes an issue where the ldap icon was missing in the tectonic console. 2017-11-02 15:33:30 -07:00
rithu leena john 42ef8fd802
Merge pull request #1072 from ericchiang/k8s-test
*: run kubernetes tests in travis
2017-10-31 10:34:26 -07:00
Eric Chiang 3d2d92b31b *: run kubernetes tests in travis 2017-10-31 10:29:52 -07:00
Daniel Dao b410622885 vendor etcd dependencies for etcd storage
This change vendors github.com/coreos/etcd related packages to support
etcd storage implementation.
2017-10-31 14:43:13 +00:00
Daniel Dao ca114f7812 storage: add etcd storage
This patch adds etcd storage implementation. This should be useful in
environments where
- we dont want to depends on a separate, hard to maintain SQL cluster
- we dont want to incur the overhead of talking to kubernetes apiservers
- kubernetes is not available yet, or if kubernetes depends on dex
to perform authentication and the operator would like to remove any
circular dependency if possible.
2017-10-31 14:43:13 +00:00
rithu leena john 943e23cd54
Merge pull request #1109 from ericchiang/oidc-test
connector/oidc: remove test that talks to the internet
2017-10-30 11:18:18 -07:00
Eric Chiang 6475ce1f62 connector/oidc: remove test that talks to the internet 2017-10-27 13:40:50 -07:00
Eric Chiang e3b96243b5 Merge pull request #1101 from pborzenkov/linkedin
connector: implement LinkedIn connector
2017-10-27 08:56:58 -07:00
Daniel Dao 2b13bdd12d
storage: fix list connector test
The previous test doesnt actually testing ListConnectors code. For
example the following pseudocode will pass the test:

```
ListConnectors() { return nil, nil }
```

Instead change to actually fetch and compare list of connectors,
ordering by name
2017-10-27 15:26:05 +01:00
Pavel Borzenkov d5a9712aae Documentation: add LinkedIn connector documentation
Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
2017-10-27 12:54:28 +03:00
Pavel Borzenkov 3b5df52c0f connector/linkedin: implement RefreshConnector interface
Do Refresh() by querying user's profile data.

Since LinkedIn doesn't provide refresh tokens at all, and the access
tokens have 60 days expiration, refresh tokens issued by Dex will fail
to update after 60 days.

Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
2017-10-27 12:54:28 +03:00
Pavel Borzenkov ab06119431 connector: implement LinkedIn connector
connector/linkedin implements authorization strategy via LinkedIn's
OAuth2 endpoint + profile API.

It doesn't implement RefreshConnector as LinkedIn doesn't provide any
refresh token at all (https://developer.linkedin.com/docs/oauth2, Step 5
— Refresh your Access Tokens) and recommends ordinary AuthCode exchange
flow when token refresh is required.

Signed-off-by: Pavel Borzenkov <pavel.borzenkov@gmail.com>
2017-10-27 12:54:28 +03:00
Eric Chiang 3d65b774d6 Merge pull request #1103 from stapelberg/authproxy
authproxy.md: strip X-Remote-User
2017-10-26 14:29:43 -07:00
rithu leena john 13b4f84f79 Merge pull request #1104 from ericchiang/authproxy-tweaks
authproxy: update docs and set a userID
2017-10-26 13:19:13 -07:00
Michael Stapelberg 4931f30a80 authproxy.md: strip X-Remote-User
follow-up for https://github.com/coreos/dex/pull/1100
2017-10-26 20:13:37 +02:00
Eric Chiang d099145921 authproxy: update docs and set a userID 2017-10-26 10:47:16 -07:00
Eric Chiang 751c565e9d Merge pull request #1100 from stapelberg/external
Implement the “external” connector (for Apache2 mod_auth etc.)
2017-10-26 09:25:40 -07:00
Michael Stapelberg a41d93db4a Implement the “authproxy” connector (for Apache2 mod_auth etc.) 2017-10-25 21:53:51 +02:00
rithu leena john f3c85e6936 Merge pull request #1096 from ericchiang/ldap-insecure-skip-verify-test
connector/ldap: add test for InsecureSkipVerify option
2017-10-10 11:34:46 -07:00
Eric Chiang 3849abb18a Merge pull request #1097 from cpanato/add_ids_test_automation
tests: add ids to elements for testing automation
2017-10-10 09:39:21 -07:00
cpanato 620695ed2b
tests: add ids to elements for testing automation 2017-10-10 11:38:14 +02:00
Eric Chiang fcf00019de connector/ldap: add test for InsecureSkipVerify option 2017-10-09 14:27:22 -07:00
rithu leena john 10c0ec0d48 Merge pull request #1092 from rithujohn191/bump-go
travis.yml: bump golang version
2017-10-09 11:32:41 -07:00
Eric Chiang 9c176dd1bd Merge pull request #1090 from lsjostro/fix-link-regexp
connector/gitlab: Fix regexp in Link parser
2017-10-09 11:15:49 -07:00
Eric Chiang 5ea886473c Merge pull request #1094 from devonbarrett/supplied-typo
fixes typo: s/suppied/supplied/
2017-10-09 11:08:32 -07:00
Devon Barrett eb14a8245c
fixes typo: s/suppied/supplied/ 2017-10-08 11:29:27 +01:00
rithu john 82879b3b3e travis.yml: bump golang version 2017-10-04 21:15:03 -07:00
Lars Sjöström 4605fdd551 connector/gitlab: Fix regexp in Link parser 2017-09-29 21:35:47 +02:00
rithu leena john fe1516332c Merge pull request #1088 from dpacierpnik/cross-clients-audience-claim-fix
Cross clients improvement - requesting client ID always added to the audience claim
2017-09-29 10:49:46 -07:00
Damian Pacierpnik e3c9b49299 Cross clients improvement - requesting client ID always added to the audience claim 2017-09-28 18:30:15 +02:00
Eric Chiang 0aabf2d1ea Merge pull request #1085 from rphillips/fixes/http_client_timeout
add client request timeout
2017-09-27 13:28:13 -07:00
Ryan Phillips 0318cd99b0 add client request timeout and dialer deadline 2017-09-26 18:52:11 -05:00
Eric Chiang fe2aee364c Merge pull request #1086 from coreos/chancez-patch-1
storage/kubernetes: Log before registering custom resources
2017-09-26 16:49:10 -07:00
Chance Zibolski 9d7b0b59bd storage/kubernetes: Log before registering custom resources
Logging before attempting to make any connection to Kubernetes is useful when the connection hangs and dex is killed before it can log any errors.
2017-09-26 16:23:49 -07:00
rithu leena john 904c3facd9 Merge pull request #1081 from lrolaz/crd_rbac_doc
Add Documentation about customresourcedefinitions creation role
2017-09-26 11:53:46 -07:00
Laurent Rolaz cca0275b0b Add Documentation about customresourcedefinitions creation role 2017-09-26 20:20:05 +02:00
Eric Chiang 2c468ea8a0 Merge pull request #1068 from furuholm/multi-stage-docker-build
Replace docker-build script with multi-stage build
2017-09-21 13:22:05 -07:00
Tobias Furuholm b6c3074ba0 Replace docker-build script with multi-stage build 2017-09-21 22:08:11 +02:00
rithu leena john 64c97c7308 Merge pull request #1071 from rithujohn191/crd-fix
storage/kubernetes: Correct the OfflineSession object CRD definition
2017-09-19 15:22:56 -07:00
rithu john d2706fcab8 storage/kubernetes: Correct the OfflineSession object CRD definition 2017-09-19 14:58:42 -07:00
rithu leena john 4c435db52e Merge pull request #1067 from rithujohn191/migrate-tprs
Documentation: add docs for TPR to CRD migration
2017-09-18 14:41:18 -07:00
rithu john 34dcf6c9a0 Documentation: add docs for TPR to CRD migration 2017-09-18 14:24:50 -07:00
rithu leena john 03de0ecbeb Merge pull request #1062 from rithujohn191/crd-migration
storage/kubernetes: add CRD support
2017-09-14 13:02:51 -07:00
rithu john 1311caf864 storage/kubernetes: add CRD support 2017-09-14 11:48:17 -07:00
Eric Chiang 4d9f5dbaa1 Merge pull request #1063 from amrutac/update-styles
Updates coreos themes and icons for various providers
2017-09-14 11:47:52 -07:00
Eric Chiang 4c0cac64eb Merge pull request #1064 from ericchiang/gofmt-fix
Makefile: error out if go files aren't correctly formatted
2017-09-14 10:34:41 -07:00
Eric Chiang 980400db0b Makefile: error out if go files aren't correctly formatted
Noticed in #1058 that our gofmt make target isn't actually erroring
if someone commits misformatted code.
2017-09-14 09:44:15 -07:00
Amruta Chitnis df8fc84851 Updates coreos themes and icons for various providers 2017-09-14 09:37:07 -07:00
rithu john 146481375e [WIP]: add CRD support 2017-09-13 10:57:54 -07:00
Eric Chiang 38d0de20e3 Merge pull request #1056 from ericchiang/fix-api-panic
server: fix panic caused by deleting refresh token twice through api
2017-09-06 09:56:06 -07:00
Eric Chiang f234e3707e server: fix panic caused by deleting refresh token twice through api 2017-09-05 23:56:34 -07:00
rithu leena john e10fddee2e Merge pull request #1031 from estroz/docs-update
Documentation: fix redirect caveat description
2017-08-25 14:58:40 -07:00
Eric Stroczynski 7079bb5316 Documentation: add org info req, remove redirect caveat
The redirect caveat is being removed to avoid user confusion and is
not important outside of testing.
2017-08-25 14:51:10 -07:00
Eric Stroczynski 9517d17ed2 Merge pull request #1050 from estroz/oidc-certification-docs
Documentation: OIDC conformance test setup
2017-08-25 14:40:53 -07:00
Eric Stroczynski 9c6b6d565e Documentation: oidc conformance test case and issue tables 2017-08-25 13:43:21 -07:00
Eric Stroczynski a065533256 Documentation: OIDC conformance test setup 2017-08-25 01:05:53 -07:00
rithu leena john 3445895647 Merge pull request #1046 from rithujohn191/static-password-fix
storage/static.go: storage backend should not explicitly lower-case email ids.
2017-08-24 17:42:29 -07:00
rithu john fd4f57b5f3 storage/static.go: storage backend should not explicitly lower-case email ids. 2017-08-24 15:50:32 -07:00
rithu leena john e40c01ec39 Merge pull request #1022 from ericchiang/ldap-example
*: add "getting started" example for LDAP
2017-08-22 10:46:55 -07:00
Eric Chiang 50f2905cac *: add standup script for LDAP 2017-08-22 10:37:29 -07:00
Eric Stroczynski 9b46267659 Merge pull request #1040 from estroz/change-bcrypt-default
server: set sane bcrypt cost upper bound
2017-08-21 14:37:04 -07:00
Eric Stroczynski 763e174a7f Merge pull request #1039 from estroz/move-group-scope-check
connector/github: fix groups scope check when 'orgs' is populated
2017-08-21 14:36:44 -07:00
Eric Stroczynski ce9ac761a6 connector/github: abstract scope check and group getter 2017-08-21 14:30:00 -07:00
Eric Stroczynski 2b354c8fdb server: set sane bcrypt cost upper bound 2017-08-21 11:53:46 -07:00
rithu leena john e59d67f466 Merge pull request #1038 from xogroup/github-enterprise
When connecting to GitHub Enterprise, force email verified field to true
2017-08-18 13:58:50 -07:00
Chien Huey 99370b5880 Updated comment to include reference to GitHub Enterprise not supporting verified emails 2017-08-18 11:46:05 -04:00
Eric Stroczynski e92f38f38f connector/github: error if no groups scope without orgs
We should always check if a user is in any orgs or teams specified
in config, and whether the groups scope is also included in client
requests. If not, return an error, because dex wouldn't have required
permissions to do the request anyway (need read:org).
2017-08-17 17:15:45 -07:00
Chien Huey 98f6a217d3 When connecting to GitHub Enterprise, force email verified field to true 2017-08-17 17:26:10 -04:00
Eric Stroczynski 20fd3163d9 Merge pull request #1036 from estroz/debug-to-info-github
connector/github: debug->info logging, informative userInOrg msg
2017-08-17 12:11:10 -07:00
Eric Stroczynski 5894d017d5 connector/github: debug->info logging, more informative userInOrg msg 2017-08-17 11:56:35 -07:00
Eric Stroczynski b84721cbda Merge pull request #1035 from estroz/user-login-github-patch
connector/github: fix username used when making API requests
2017-08-17 11:39:39 -07:00
Eric Stroczynski 484327fd5f connector/github: only user users' login name in API reqs 2017-08-17 10:32:18 -07:00
Eric Stroczynski 7e580ec2b2 Merge pull request #1029 from estroz/doc-link-fix
Documentation: fixed GitHub link syntax
2017-08-16 14:14:22 -07:00
Eric Stroczynski bb36c96674 Documentation: fixed GitHub link syntax 2017-08-16 14:10:23 -07:00
Eric Stroczynski 48bb61cfe0 Merge pull request #1028 from estroz/gitlab-scopes
connector/gitlab: correct scope strings, better default
2017-08-15 14:57:05 -07:00
Eric Stroczynski ca75470ae3 connector/gitlab: correct scope strings, better default 2017-08-15 14:49:00 -07:00
916 changed files with 72502 additions and 429592 deletions

View File

@ -1,3 +1,4 @@
*
!_output/bin
!web
.github/
.gitpod.yml
bin/
tmp/

21
.editorconfig Normal file
View File

@ -0,0 +1,21 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.go]
indent_style = tab
[*.proto]
indent_size = 2
[{Makefile,*.mk}]
indent_style = tab
[{config.yaml.dist,config.dev.yaml}]
indent_size = 2

6
.envrc Normal file
View File

@ -0,0 +1,6 @@
if ! has nix_direnv_version || ! nix_direnv_version 1.5.0; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/1.5.0/direnvrc" "sha256-carKk9aUFHMuHt+IWh74hFj58nY4K3uywpZbwXX0BTI="
fi
use flake
dotenv_if_exists

2
.github/.editorconfig vendored Normal file
View File

@ -0,0 +1,2 @@
[{*.yml,*.yaml}]
indent_size = 2

3
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@ -0,0 +1,3 @@
## Community Code of Conduct
This project follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).

0
DCO → .github/DCO vendored
View File

102
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View File

@ -0,0 +1,102 @@
name: 🐛 Bug report
description: Report a bug to help us improve Dex
body:
- type: markdown
attributes:
value: |
Thank you for submitting a bug report!
Please fill out the template below to make it easier to debug your problem.
If you are not sure if it is a bug or not, you can contact us via the available [support channels](https://github.com/dexidp/dex/issues/new/choose).
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I agree to follow the [Code of Conduct](https://github.com/dexidp/dex/blob/master/.github/CODE_OF_CONDUCT.md) that this project adheres to.
required: true
- label: I have searched the [issue tracker](https://www.github.com/dexidp/dex/issues) for an issue that matches the one I want to file, without success.
required: true
- label: I am not looking for support or already pursued the available [support channels](https://github.com/dexidp/dex/issues/new/choose) without success.
required: true
- type: input
attributes:
label: Version
description: What version of Dex are you running?
placeholder: 2.29.0
validations:
required: true
- type: dropdown
attributes:
label: Storage Type
description: Which persistent storage type are you using?
options:
- etcd
- Kubernetes
- In-memory
- Postgres
- MySQL
- SQLite
validations:
required: true
- type: dropdown
attributes:
label: Installation Type
description: How did you install Dex?
options:
- Binary
- Official container image
- Official Helm chart
- Custom container image
- Custom Helm chart
- Other (specify below)
multiple: true
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Actual Behavior
description: A clear description of what actually happens.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior if it is not self-explanatory.
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
- type: textarea
attributes:
label: Additional Information
description: Links? References? Anything that will give us more context about the issue that you are encountering!
- type: textarea
attributes:
label: Configuration
description: Contents of your configuration file (if relevant).
render: yaml
placeholder: |
issuer: http://127.0.0.1:5556/dex
storage:
# ...
connectors:
# ...
staticClients:
# ...
- type: textarea
attributes:
label: Logs
description: Dex application logs (if relevant).
render: shell

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: ❓ Ask a question
url: https://github.com/dexidp/dex/discussions/new?category=q-a
about: Ask and discuss questions with other Dex community members
- name: 📚 Documentation
url: https://dexidp.io/docs/
about: Check the documentation for help
- name: 💬 Slack channel
url: https://cloud-native.slack.com/messages/dexidp
about: Please ask and answer questions here
- name: 💡 Dex Enhancement Proposal
url: https://github.com/dexidp/dex/tree/master/enhancements/README.md
about: Open a proposal for significant architectural change

View File

@ -0,0 +1,40 @@
name: 🎉 Feature request
description: Suggest an idea for Dex
body:
- type: markdown
attributes:
value: |
Thank you for submitting a feature request!
Please describe what you would like to change/add and why in detail by filling out the template below.
If you are not sure if your request fits into Dex, you can contact us via the available [support channels](https://github.com/dexidp/dex/issues/new/choose).
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I agree to follow the [Code of Conduct](https://github.com/dexidp/dex/blob/master/.github/CODE_OF_CONDUCT.md) that this project adheres to.
required: true
- label: I have searched the [issue tracker](https://www.github.com/dexidp/dex/issues) for an issue that matches the one I want to file, without success.
required: true
- type: textarea
attributes:
label: Problem Description
description: A clear and concise description of the problem you are seeking to solve with this feature request.
validations:
required: true
- type: textarea
attributes:
label: Proposed Solution
description: A clear and concise description of what would you like to happen.
validations:
required: true
- type: textarea
attributes:
label: Alternatives Considered
description: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
attributes:
label: Additional Information
description: Add any other context about the problem here.

35
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,35 @@
<!--
Thank you for sending a pull request! Here are some tips for contributors:
1. Fill the description template below.
2. Sign a DCO (if you haven't already signed it).
3. Include appropriate tests (if necessary). Make sure that all CI checks passed.
4. If the Pull Request is a work in progress, make use of GitHub's "Draft PR" feature and mark it as such.
-->
#### Overview
<!-- Describe your changes briefly here. -->
#### What this PR does / why we need it
<!--
- Please state in detail why we need this PR and what it solves.
- If your PR closes some of the existing issues, please add links to them here.
Mentioned issues will be automatically closed.
Usage: "Closes #<issue number>", or "Closes (paste link of issue)"
-->
#### Special notes for your reviewer
#### Does this PR introduce a user-facing change?
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
```

24
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,24 @@
# Security Policy
## Reporting a vulnerability
To report a vulnerability, send an email to [cncf-dex-maintainers@lists.cncf.io](mailto:cncf-dex-maintainers@lists.cncf.io)
detailing the issue and steps to reproduce. The reporter(s) can expect a
response within 48 hours acknowledging the issue was received. If a response is
not received within 48 hours, please reach out to any maintainer directly
to confirm receipt of the issue.
## Review Process
Once a maintainer has confirmed the relevance of the report, a draft security
advisory will be created on Github. The draft advisory will be used to discuss
the issue with maintainers, the reporter(s).
If the reporter(s) wishes to participate in this discussion, then provide
reporter Github username(s) to be invited to the discussion. If the reporter(s)
does not wish to participate directly in the discussion, then the reporter(s)
can request to be updated regularly via email.
If the vulnerability is accepted, a timeline for developing a patch, public
disclosure, and patch release will be determined. The reporter(s) are expected
to participate in the discussion of the timeline and abide by agreed upon dates
for public disclosure.

30
.github/dependabot.yaml vendored Normal file
View File

@ -0,0 +1,30 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
labels:
- "area/dependencies"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/api/v2"
labels:
- "area/dependencies"
schedule:
interval: "daily"
- package-ecosystem: "docker"
directory: "/"
labels:
- "area/dependencies"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
labels:
- "area/dependencies"
schedule:
interval: "daily"

30
.github/release.yml vendored Normal file
View File

@ -0,0 +1,30 @@
changelog:
exclude:
labels:
- release-note/ignore
categories:
- title: Exciting New Features 🎉
labels:
- kind/feature
- release-note/new-feature
- title: Enhancements 🚀
labels:
- kind/enhancement
- release-note/enhancement
- title: Bug Fixes 🐛
labels:
- kind/bug
- release-note/bug-fix
- title: Breaking Changes 🛠
labels:
- release-note/breaking-change
- title: Deprecations ❌
labels:
- release-note/deprecation
- title: Dependency Updates ⬆️
labels:
- area/dependencies
- release-note/dependency-update
- title: Other Changes
labels:
- "*"

97
.github/workflows/artifacts.yaml vendored Normal file
View File

@ -0,0 +1,97 @@
name: Artifacts
on:
push:
branches:
- master
tags:
- v[0-9]+.[0-9]+.[0-9]+
pull_request:
jobs:
container-images:
name: Container images
runs-on: ubuntu-latest
strategy:
matrix:
variant:
- alpine
- distroless
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Gather metadata
id: meta
uses: docker/metadata-action@v4
with:
images: |
ghcr.io/dexidp/dex
dexidp/dex
flavor: |
latest = false
tags: |
type=ref,event=branch,enable=${{ matrix.variant == 'alpine' }}
type=ref,event=pr,enable=${{ matrix.variant == 'alpine' }}
type=semver,pattern={{raw}},enable=${{ matrix.variant == 'alpine' }}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && matrix.variant == 'alpine' }}
type=ref,event=branch,suffix=-${{ matrix.variant }}
type=ref,event=pr,suffix=-${{ matrix.variant }}
type=semver,pattern={{raw}},suffix=-${{ matrix.variant }}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }},suffix=-${{ matrix.variant }}
labels: |
org.opencontainers.image.documentation=https://dexidp.io/docs/
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}
if: github.event_name == 'push'
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
if: github.event_name == 'push'
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
# cache-from: type=gha
# cache-to: type=gha,mode=max
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
build-args: |
BASE_IMAGE=${{ matrix.variant }}
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
COMMIT_HASH=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
labels: ${{ steps.meta.outputs.labels }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.6.1
with:
image-ref: "ghcr.io/dexidp/dex:${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}"
format: "sarif"
output: "trivy-results.sarif"
if: github.event_name == 'push'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: "trivy-results.sarif"
if: github.event_name == 'push'

18
.github/workflows/checks.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
name: PR Checks
on:
pull_request:
types: [opened, labeled, unlabeled, synchronize]
jobs:
release-label:
name: Release note label
runs-on: ubuntu-latest
steps:
- name: Check minimum labels
uses: mheap/github-action-required-labels@v2
with:
mode: minimum
count: 1
labels: "release-note/ignore, kind/feature, release-note/new-feature, kind/enhancement, release-note/enhancement, kind/bug, release-note/bug-fix, release-note/breaking-change, release-note/deprecation, area/dependencies, release-note/dependency-update"

129
.github/workflows/ci.yaml vendored Normal file
View File

@ -0,0 +1,129 @@
name: CI
on:
push:
branches:
- master
pull_request:
jobs:
build:
name: Build
runs-on: ubuntu-latest
env:
GOFLAGS: -mod=readonly
services:
postgres:
image: postgres:10.8
ports:
- 5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
postgres-ent:
image: postgres:10.8
ports:
- 5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: dex
ports:
- 3306
options: --health-cmd "mysql -proot -e \"show databases;\"" --health-interval 10s --health-timeout 5s --health-retries 5
mysql-ent:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: dex
ports:
- 3306
options: --health-cmd "mysql -proot -e \"show databases;\"" --health-interval 10s --health-timeout 5s --health-retries 5
etcd:
image: gcr.io/etcd-development/etcd:v3.5.0
ports:
- 2379
env:
ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
ETCD_ADVERTISE_CLIENT_URLS: http://0.0.0.0:2379
options: --health-cmd "ETCDCTL_API=3 etcdctl --endpoints http://localhost:2379 endpoint health" --health-interval 10s --health-timeout 5s --health-retries 5
keystone:
image: openio/openstack-keystone:rocky
ports:
- 5000
- 35357
options: --health-cmd "curl --fail http://localhost:5000/v3" --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: Checkout code
uses: actions/checkout@v3
- name: Start services
run: docker-compose -f docker-compose.test.yaml up -d
- name: Create kind cluster
uses: helm/kind-action@v1.3.0
with:
version: v0.11.1
node_image: kindest/node:v1.19.11@sha256:07db187ae84b4b7de440a73886f008cf903fcf5764ba8106a9fd5243d6f32729
- name: Download tool dependencies
run: make deps
- name: Test
run: make testall
env:
DEX_MYSQL_DATABASE: dex
DEX_MYSQL_USER: root
DEX_MYSQL_PASSWORD: root
DEX_MYSQL_HOST: 127.0.0.1
DEX_MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
DEX_MYSQL_ENT_DATABASE: dex
DEX_MYSQL_ENT_USER: root
DEX_MYSQL_ENT_PASSWORD: root
DEX_MYSQL_ENT_HOST: 127.0.0.1
DEX_MYSQL_ENT_PORT: ${{ job.services.mysql-ent.ports[3306] }}
DEX_POSTGRES_DATABASE: postgres
DEX_POSTGRES_USER: postgres
DEX_POSTGRES_PASSWORD: postgres
DEX_POSTGRES_HOST: localhost
DEX_POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }}
DEX_POSTGRES_ENT_DATABASE: postgres
DEX_POSTGRES_ENT_USER: postgres
DEX_POSTGRES_ENT_PASSWORD: postgres
DEX_POSTGRES_ENT_HOST: localhost
DEX_POSTGRES_ENT_PORT: ${{ job.services.postgres-ent.ports[5432] }}
DEX_ETCD_ENDPOINTS: http://localhost:${{ job.services.etcd.ports[2379] }}
DEX_LDAP_HOST: localhost
DEX_LDAP_PORT: 389
DEX_LDAP_TLS_PORT: 636
DEX_KEYSTONE_URL: http://localhost:${{ job.services.keystone.ports[5000] }}
DEX_KEYSTONE_ADMIN_URL: http://localhost:${{ job.services.keystone.ports[35357] }}
DEX_KEYSTONE_ADMIN_USER: demo
DEX_KEYSTONE_ADMIN_PASS: DEMO_PASS
DEX_KUBERNETES_CONFIG_PATH: ~/.kube/config
- name: Lint
run: make lint
# Ensure proto generation doesn't depend on external packages.
- name: Verify proto
run: make verify-proto

67
.github/workflows/codeql-analysis.yaml vendored Normal file
View File

@ -0,0 +1,67 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master, v1 ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '28 10 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

111
.github/workflows/docker.yaml vendored Normal file
View File

@ -0,0 +1,111 @@
name: Docker
on:
# push:
# branches:
# - master
# tags:
# - v[0-9]+.[0-9]+.[0-9]+
pull_request:
jobs:
docker:
name: Docker
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Calculate Docker image tags
id: tags
env:
DOCKER_IMAGES: "ghcr.io/dexidp/dex dexidp/dex"
run: |
case $GITHUB_REF in
refs/tags/*) VERSION=${GITHUB_REF#refs/tags/};;
refs/heads/*) VERSION=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's#/+#-#g');;
refs/pull/*) VERSION=pr-${{ github.event.number }};;
*) VERSION=sha-${GITHUB_SHA::8};;
esac
TAGS=()
for image in $DOCKER_IMAGES; do
TAGS+=("${image}:${VERSION}")
if [[ "${{ github.event.repository.default_branch }}" == "$VERSION" ]]; then
TAGS+=("${image}:latest")
fi
done
echo ::set-output name=version::${VERSION}
echo ::set-output name=tags::$(IFS=,; echo "${TAGS[*]}")
echo ::set-output name=commit_hash::${GITHUB_SHA::8}
echo ::set-output name=build_date::$(git show -s --format=%cI)
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
install: true
version: latest
# TODO: Remove driver-opts once fix is released docker/buildx#386
driver-opts: image=moby/buildkit:master
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}
if: github.event_name == 'push'
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
if: github.event_name == 'push'
- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
# cache-from: type=gha
# cache-to: type=gha,mode=max
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.tags.outputs.tags }}
build-args: |
VERSION=${{ steps.tags.outputs.version }}
COMMIT_HASH=${{ steps.tags.outputs.commit_hash }}
BUILD_DATE=${{ steps.tags.outputs.build_date }}
labels: |
org.opencontainers.image.title=${{ github.event.repository.name }}
org.opencontainers.image.description=${{ github.event.repository.description }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.source=${{ github.event.repository.clone_url }}
org.opencontainers.image.version=${{ steps.tags.outputs.version }}
org.opencontainers.image.created=${{ steps.tags.outputs.build_date }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.licenses=${{ github.event.repository.license.spdx_id }}
org.opencontainers.image.documentation=https://dexidp.io/docs/
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.6.1
with:
image-ref: "ghcr.io/dexidp/dex:${{ steps.tags.outputs.version }}"
format: "template"
template: "@/contrib/sarif.tpl"
output: "trivy-results.sarif"
if: github.event_name == 'push'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: "trivy-results.sarif"
if: github.event_name == 'push'

10
.gitignore vendored
View File

@ -1,3 +1,7 @@
bin
dist
_output
/.direnv/
/.idea/
/bin/
/config.yaml
/docker-compose.override.yaml
/var/
/vendor/

3
.gitpod.yml Normal file
View File

@ -0,0 +1,3 @@
tasks:
- init: go get && go build ./... && go test ./... && make
command: go run

90
.golangci.yml Normal file
View File

@ -0,0 +1,90 @@
run:
timeout: 4m
linters-settings:
depguard:
list-type: blacklist
include-go-root: true
packages:
- io/ioutil
packages-with-error-message:
- io/ioutil: "The 'io/ioutil' package is deprecated. Use corresponding 'os' or 'io' functions instead."
gci:
local-prefixes: github.com/dexidp/dex
goimports:
local-prefixes: github.com/dexidp/dex
linters:
disable-all: true
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- exhaustive
- exportloopref
- gci
- gochecknoinits
- gocritic
- gofmt
- gofumpt
- goimports
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- nolintlint
- prealloc
- revive
- rowserrcheck
- sqlclosecheck
- staticcheck
- structcheck
- stylecheck
- tparallel
- unconvert
- unparam
- unused
- varcheck
- whitespace
# Disable temporarily until everything works with Go 1.18
# - typecheck
# TODO: fix linter errors before enabling
# - exhaustivestruct
# - gochecknoglobals
# - errorlint
# - gocognit
# - godot
# - nlreturn
# - noctx
# - wrapcheck
# TODO: fix linter errors before enabling (from original config)
# - dupl
# - errcheck
# - goconst
# - gocyclo
# - gosec
# - lll
# - scopelint
# unused
# - goheader
# - gomodguard
# don't enable:
# - asciicheck
# - funlen
# - godox
# - goerr113
# - gomnd
# - interfacer
# - maligned
# - nestif
# - testpackage
# - wsl

View File

@ -1,26 +0,0 @@
language: go
sudo: required
go:
- 1.7.5
- 1.8.3
services:
- postgresql
env:
- DEX_POSTGRES_DATABASE=postgres DEX_POSTGRES_USER=postgres DEX_POSTGRES_HOST="localhost" DEX_LDAP_TESTS=1 DEBIAN_FRONTEND=noninteractive
install:
- go get -u github.com/golang/lint/golint
- sudo -E apt-get install -y --force-yes slapd time ldap-utils
- sudo /etc/init.d/slapd stop
script:
- make testall
notifications:
email: false

15
ADOPTERS.md Normal file
View File

@ -0,0 +1,15 @@
# Adopters
This is a list of production adopters of Dex (in alphabetical order):
- [Aspect](https://www.aspect.com/) uses Dex for authenticating users across their Kubernetes infrastructure (using Kubernetes OIDC support).
- [Banzai Cloud](https://banzaicloud.com) is using Dex for authenticating to its Pipeline control plane and also to authenticate users against provisioned Kubernetes clusters (via Kubernetes OIDC support).
- [Chef](https://chef.io) uses Dex for authenticating users in [Chef Automate](https://automate.chef.io/). The code is Open Source, available at [`github.com/chef/automate`](https://github.com/chef/automate).
- [Elastisys](https://elastisys.com) uses Dex for authentication in their [Compliant Kubernetes](https://compliantkubernetes.io) distribution, including SSO to the custom dashboard, Grafana, Kibana, and Harbor.
- [Flant](https://flant.com) uses Dex for providing access to core components of [Managed Kubernetes as a Service](https://flant.com/services/managed-kubernetes-as-a-service), integration with various authentication providers, plugging custom applications.
- [JuliaBox](https://juliabox.com/) is leveraging federated OIDC provided by Dex for authenticating users to their compute infrastructure based on Kubernetes.
- [Kasten](https://www.kasten.io) is using Dex for authenticating access to the dashboard of [K10](https://www.kasten.io/product/), a Kubernetes-native platform for backup, disaster recovery and mobility of Kubernetes applications. K10 is widely used by a variety of customers including large enterprises, financial services, design firms, and IT companies.
- [Kyma](https://kyma-project.io) is using Dex to authenticate access to Kubernetes API server (even for managed Kubernetes like Google Kubernetes Engine or Azure Kubernetes Service) and for protecting web UI of [Kyma Console](https://github.com/kyma-project/console) and other UIs integrated in Kyma ([Grafana](https://github.com/grafana/grafana), [Loki](https://github.com/grafana/loki), and [Jaeger](https://github.com/jaegertracing/jaeger)). Kyma is an open-source project ([`github.com/kyma-project`](https://github.com/kyma-project/kyma)) designed natively on Kubernetes, that allows you to extend and customize your applications in a quick and modern way, using serverless computing or microservice architecture.
- [Pusher](https://pusher.com) uses Dex for authenticating users across their Kubernetes infrastructure (using Kubernetes OIDC support) in conjunction with the [OAuth2 Proxy](https://github.com/pusher/oauth2_proxy) for protecting web UIs.
- [Pydio](https://pydio.com/) Pydio Cells is an open source sync & share platform written in Go. Cells is using Dex as an OIDC service for authentication and authorizations. Check out [Pydio Cells repository](https://github.com/pydio/cells) for more information and/or to contribute.
- [sigstore](https://sigstore.dev) uses Dex for authentication in their public Fulcio instance, which is a certificate authority for code signing certificates bound to OIDC-based identities.

View File

@ -1,23 +1,72 @@
FROM alpine:3.4
ARG BASE_IMAGE=alpine
MAINTAINER Ed Rooth <ed.rooth@coreos.com>
MAINTAINER Lucas Servén <lucas.serven@coreos.com>
MAINTAINER Rithu John <rithu.john@coreos.com>
FROM golang:1.18.4-alpine3.15 AS builder
WORKDIR /usr/local/src/dex
RUN apk add --no-cache --update alpine-sdk ca-certificates openssl
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT=""
ENV GOOS=${TARGETOS} GOARCH=${TARGETARCH} GOARM=${TARGETVARIANT}
ARG GOPROXY
COPY go.mod go.sum ./
COPY api/v2/go.mod api/v2/go.sum ./api/v2/
RUN go mod download
COPY . .
RUN make release-binary
FROM alpine:3.16.2 AS stager
RUN mkdir -p /var/dex
RUN mkdir -p /etc/dex
COPY config.docker.yaml /etc/dex/
FROM alpine:3.16.2 AS gomplate
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
ENV GOMPLATE_VERSION=v3.11.2
RUN wget -O /usr/local/bin/gomplate \
"https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${TARGETOS:-linux}-${TARGETARCH:-amd64}${TARGETVARIANT}" \
&& chmod +x /usr/local/bin/gomplate
# For Dependabot to detect base image versions
FROM alpine:3.16.2 AS alpine
FROM gcr.io/distroless/static:latest AS distroless
FROM $BASE_IMAGE
# Dex connectors, such as GitHub and Google logins require root certificates.
# Proper installations should manage those certificates, but it's a bad user
# experience when this doesn't work out of the box.
#
# OpenSSL is required so wget can query HTTPS endpoints for health checking.
RUN apk add --update ca-certificates openssl
# See https://go.dev/src/crypto/x509/root_linux.go for Go root CA bundle locations.
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY _output/bin/dex /usr/local/bin/dex
COPY --from=stager --chown=1001:1001 /var/dex /var/dex
COPY --from=stager --chown=1001:1001 /etc/dex /etc/dex
# Import frontend assets and set the correct CWD directory so the assets
# are in the default path.
COPY web /web
WORKDIR /
# Copy module files for CVE scanning / dependency analysis.
COPY --from=builder /usr/local/src/dex/go.mod /usr/local/src/dex/go.sum /usr/local/src/dex/
COPY --from=builder /usr/local/src/dex/api/v2/go.mod /usr/local/src/dex/api/v2/go.sum /usr/local/src/dex/api/v2/
ENTRYPOINT ["dex"]
COPY --from=builder /go/bin/dex /usr/local/bin/dex
COPY --from=builder /go/bin/docker-entrypoint /usr/local/bin/docker-entrypoint
COPY --from=builder /usr/local/src/dex/web /srv/dex/web
CMD ["version"]
COPY --from=gomplate /usr/local/bin/gomplate /usr/local/bin/gomplate
USER 1001:1001
ENTRYPOINT ["/usr/local/bin/docker-entrypoint"]
CMD ["dex", "serve", "/etc/dex/config.docker.yaml"]

View File

@ -1,117 +0,0 @@
# The dex API
Dex provides a [gRPC][grpc] service for programmatic modification of dex's state. The API is intended to expose hooks for management applications and is not expected to be used by most installations.
This document is an overview of how to interact with the API.
## Configuration
Admins that wish to expose the gRPC service must add the following entry to the dex config file. This option is off by default.
```
grpc:
# Cannot be the same address as an HTTP(S) service.
addr: 127.0.0.1:5557
# Server certs. If TLS credentials aren't provided dex will generate self-signed ones.
tlsCert: /etc/dex/grpc.crt
tlsKey: /etc/dex/grpc.key
# Client auth CA.
tlsClientCA: /etc/dex/client.crt
```
## Generating clients
gRPC is a suite of tools for generating client and server bindings from a common declarative language. The canonical schema for dex's API can be found in the source tree at [`api/api.proto`][api-proto]. Go bindings are generated and maintained in the same directory for internal use.
To generate a client for your own project install [`protoc`][protoc], install a protobuf generator for your project's language, and download the `api.proto` file. An example for a Go project:
```
# Install protoc-gen-go.
$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
# Download api.proto for a given version.
$ DEX_VERSION=v2.0.0-alpha.5
$ wget https://raw.githubusercontent.com/coreos/dex/${DEX_VERSION}/api/api.proto
# Generate the Go client bindings.
$ protoc --go_out=import_path=dexapi:. api.proto
```
Client programs can then be written using the generated code. A Go client which uses dex's internally generated code might look like the following:
__NOTE:__ Because dex has the `google.golang.org/grpc` package in its `vendor` directory, gRPC code in `github.com/coreos/dex/api` refers to the vendored copy, not copies in a developers GOPATH. Clients must either regenerate the gRPC Go code or vendor dex and remove its `vendor` directory to run this program.
```
package main
import (
"context"
"fmt"
"log"
"github.com/coreos/dex/api"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func newDexClient(hostAndPort, caPath string) (api.DexClient, error) {
creds, err := credentials.NewClientTLSFromFile(caPath, "")
if err != nil {
return nil, fmt.Errorf("load dex cert: %v", err)
}
conn, err := grpc.Dial(hostAndPort, grpc.WithTransportCredentials(creds))
if err != nil {
return nil, fmt.Errorf("dail: %v", err)
}
return api.NewDexClient(conn), nil
}
func main() {
client, err := newDexClient("127.0.0.1:5557", "/etc/dex/grpc.crt")
if err != nil {
log.Fatalf("failed creating dex client: %v ", err)
}
req := &api.CreateClientReq{
Client: &api.Client{
Id: "example-app",
Name: "Example App",
Secret: "ZXhhbXBsZS1hcHAtc2VjcmV0",
RedirectUris: []string{"http://127.0.0.1:5555/callback"},
},
}
if _, err := client.CreateClient(context.TODO(), req); err != nil {
log.Fatalf("failed creating oauth2 client: %v", err)
}
}
```
A clear working example of the Dex gRPC client can be found [here](../examples/grpc-client/README.md).
## Authentication and access control
The dex API does not provide any authentication or authorization beyond TLS client auth.
Projects that wish to add access controls on top of the existing API should build apps which perform such checks. For example to provide a "Change password" screen, a client app could use dex's OpenID Connect flow to authenticate an end user, then call dex's API to update that user's password.
## dexctl?
Dex does not ship with a command line tool for interacting with the API. Command line tools are useful but hard to version, easy to design poorly, and expose another interface which can never be changed in the name of compatibility.
While the dex team would be open to re-implementing `dexctl` for v2 a majority of the work is writing a design document, not the actual programming effort.
## Why not REST or gRPC Gateway?
Between v1 and v2, dex switched from REST to gRPC. This largely stemmed from problems generating documentation, client bindings, and server frameworks that adequately expressed REST semantics. While [Google APIs][google-apis], [Open API/Swagger][open-api], and [gRPC Gateway][grpc-gateway] were evaluated, they often became clunky when trying to use specific HTTP error codes or complex request bodies. As a result, v2's API is entirely gRPC.
Many arguments _against_ gRPC cite short term convenience rather than production use cases. Though this is a recognized shortcoming, dex already implements many features for developer convenience. For instance, users who wish to manually edit clients during testing can use the `staticClients` config field instead of the API.
[grpc]: http://www.grpc.io/
[api-proto]: ../api/api.proto
[protoc]: https://github.com/google/protobuf/releases
[protoc-gen-go]: https://github.com/golang/protobuf
[google-apis]: https://github.com/google/apis-client-generator
[open-api]: https://openapis.org/
[grpc-gateway]: https://github.com/grpc-ecosystem/grpc-gateway

View File

@ -1,89 +0,0 @@
# Custom scopes, claims and client features
This document describes the set of OAuth2 and OpenID Connect features implemented by dex.
## Scopes
The following is the exhaustive list of scopes supported by dex:
| Name | Description |
| ---- | ------------|
| `openid` | Required scope for all login requests. |
| `email` | ID token claims should include the end user's email and if that email was verified by an upstream provider. |
| `profile` | ID token claims should include the username of the end user. |
| `groups` | ID token claims should include a list of groups the end user is a member of. |
| `offline_access` | Token response should include a refresh token. Doesn't work in combinations with some connectors, notability the [SAML connector][saml-connector] ignores this scope. |
| `audience:server:client_id:( client-id )` | Dynamic scope indicating that the ID token should be issued on behalf of another client. See the _"Cross-client trust and authorized party"_ section below. |
## Custom claims
Beyond the [required OpenID Connect claims][core-claims], and a handful of [standard claims][standard-claims], dex implements the following non-standard claims.
| Name | Description |
| ---- | ------------|
| `groups` | A list of strings representing the groups a user is a member of. |
| `email` | The email of the user. |
| `email_verified` | If the upstream provider has verified the email. |
| `name` | User's display name. |
## Cross-client trust and authorized party
Dex has the ability to issue ID tokens to clients on behalf of other clients. In OpenID Connect terms, this means the ID token's `aud` (audience) claim being a different client ID than the client that performed the login.
For example, this feature could be used to allow a web app to generate an ID token on behalf of a command line tool:
```yaml
staticClients:
- id: web-app
redirectURIs:
- 'https://web-app.example.com/callback'
name: 'Web app'
secret: web-app-secret
- id: cli-app
redirectURIs:
- 'https://cli-app.example.com/callback'
name: 'Command line tool'
secret: cli-app-secret
# The command line tool lets the web app issue ID tokens on its behalf.
trustedPeers:
- web-app
```
Note that the command line tool must explicitly trust the web app using the `trustedPeers` field. The web app can then use the following scope to request an ID token that's issued for the command line tool.
```
audience:server:client_id:cli-app
```
The ID token claims will then include the following audience and authorized party:
```
{
"aud": "cli-app",
"azp": "web-app",
"email": "foo@bar.com",
// other claims...
}
```
## Public clients
Public clients are inspired by Google's [_"Installed Applications"_][installed-apps] and are meant to impose restrictions on applications that don't intend to keep their client secret private. Clients can be declared as public using the `public` config option.
```yaml
staticClients:
- id: cli-app
public: true
name: 'CLI app'
secret: cli-app-secret
```
Instead of traditional redirect URIs, public clients are limited to either redirects that begin with "http://localhost" or a special "out-of-browser" URL "urn:ietf:wg:oauth:2.0:oob". The latter triggers dex to display the OAuth2 code in the browser, prompting the end user to manually copy it to their app. It's the client's responsibility to either create a screen or a prompt to receive the code, then perform a code exchange for a token response.
When using the "out-of-browser" flow, an ID Token nonce is strongly recommended.
[saml-connector]: saml-connector.md
[core-claims]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
[standard-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
[installed-apps]: https://developers.google.com/api-client-library/python/auth/installed-app

View File

@ -1,35 +0,0 @@
# Managing dependencies
Dex uses [glide][glide] and [glide-vc][glide-vc] to manage its [`vendor` directory][go-vendor]. A recent version of these are preferred but dex doesn't require any bleeding edge features. Either install these tools using `go get` or take an opportunity to update to a more recent version.
```
go get -u github.com/Masterminds/glide
go get -u github.com/sgotti/glide-vc
```
To add a new dependency to dex or update an existing one:
* Make changes to dex's source code importing the new dependency.
* Edit `glide.yaml` to include the new dependency at a given commit SHA or change a SHA.
* Add all transitive dependencies of the package to prevent unpinned packages.
Tests will fail if transitive dependencies aren't included.
Once `glide.yaml` describes the desired state use `make` to update `glide.lock` and `vendor`. This calls both `glide` and `glide-vc` with the set of flags that dex requires.
```
make revendor
```
When composing commits make sure that updates to `vendor` are in a separate commit from the main changes. GitHub's UI makes commits with a large number of changes unreviewable.
Commit histories should look like the following:
```
connector/ldap: add a LDAP connector
vendor: revendor
```
[glide]: https://github.com/Masterminds/glide
[glide-vc]: https://github.com/sgotti/glide-vc
[go-vendor]: https://golang.org/cmd/go/#hdr-Vendor_Directories

View File

@ -1,138 +0,0 @@
# Running integration tests
## Kubernetes
Kubernetes tests will only run if the `DEX_KUBECONFIG` environment variable is set.
```
$ export DEX_KUBECONFIG=~/.kube/config
$ go test -v -i ./storage/kubernetes
$ go test -v ./storage/kubernetes
```
Because third party resources creation isn't synchronized it's expected that the tests fail the first time. Fear not, and just run them again.
## Postgres
Running database tests locally require:
* A systemd based Linux distro.
* A recent version of [rkt](https://github.com/coreos/rkt) installed.
The `standup.sh` script in the SQL directory is used to run databases in containers with systemd daemonizing the process.
```
$ sudo ./storage/sql/standup.sh create postgres
Starting postgres. To view progress run
journalctl -fu dex-postgres
Running as unit dex-postgres.service.
To run tests export the following environment variables:
export DEX_POSTGRES_DATABASE=postgres; export DEX_POSTGRES_USER=postgres; export DEX_POSTGRES_PASSWORD=postgres; export DEX_POSTGRES_HOST=172.16.28.3:5432
```
Exporting the variables will cause the database tests to be run, rather than skipped.
```
$ # sqlite3 takes forever to compile, be sure to install test dependencies
$ go test -v -i ./storage/sql
$ go test -v ./storage/sql
```
When you're done, tear down the unit using the `standup.sh` script.
```
$ sudo ./storage/sql/standup.sh destroy postgres
```
## LDAP
To run LDAP tests locally, you require a container running OpenLDAP.
Run OpenLDAP docker image:
```
$ sudo docker run --hostname ldap.example.org --name openldap-container --detach osixia/openldap:1.1.6
```
By default TLS is enabled and a certificate is created with the container hostname, which in this case is "ldap.example.org". It will create an empty LDAP for the company Example Inc. and the domain example.org. By default the admin has the password admin.
Add new users and groups (sample .ldif file included at the end):
```
$ sudo docker exec openldap-container ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f <path to .ldif> -h ldap.example.org -ZZ
```
Verify that the added entries are in your directory with ldapsearch :
```
$ sudo docker exec openldap-container ldapsearch -x -h localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
```
The .ldif file should contain seed data. Example file contents:
```
dn: cn=Test1,dc=example,dc=org
objectClass: organizationalRole
cn: Test1
dn: cn=Test2,dc=example,dc=org
objectClass: organizationalRole
cn: Test2
dn: ou=groups,dc=example,dc=org
ou: groups
objectClass: top
objectClass: organizationalUnit
dn: cn=tstgrp,ou=groups,dc=example,dc=org
objectClass: top
objectClass: groupOfNames
member: cn=Test1,dc=example,dc=org
cn: tstgrp
```
## SAML
### Okta
The Okta identity provider supports free accounts for developers to test their implementation against. This document describes configuring an Okta application to test dex's SAML connector.
First, [sign up for a developer account][okta-sign-up]. Then, to create a SAML application:
* Go to the admin screen.
* Click "Add application"
* Click "Create New App"
* Choose "SAML 2.0" and press "Create"
* Configure SAML
* Enter `http://127.0.0.1:5556/dex/callback` for "Single sign on URL"
* Enter `http://127.0.0.1:5556/dex/callback` for "Audience URI (SP Entity ID)"
* Under "ATTRIBUTE STATEMENTS (OPTIONAL)" add an "email" and "name" attribute. The values should be something like `user:email` and `user:firstName`, respectively.
* Under "GROUP ATTRIBUTE STATEMENTS (OPTIONAL)" add a "groups" attribute. Use the "Regexp" filter `.*`.
After the application's created, assign yourself to the app.
* "Applications" > "Applications"
* Click on your application then under the "People" tab press the "Assign to People" button and add yourself.
At the app, go to the "Sign On" tab and then click "View Setup Instructions". Use those values to fill out the following connector in `examples/config-dev.yaml`.
```yaml
connectors:
- type: saml
id: saml
name: Okta
config:
ssoURL: ( "Identity Provider Single Sign-On URL" )
caData: ( base64'd value of "X.509 Certificate" )
redirectURI: http://127.0.0.1:5556/dex/callback
usernameAttr: name
emailAttr: email
groupsAttr: groups
```
Start both dex and the example app, and try logging in (requires not requesting a refresh token).
[okta-sign-up]: https://www.okta.com/developer/signup/

View File

@ -1,81 +0,0 @@
# Releases
Making a dex release involves:
* Tagging a git commit and pushing the tag to GitHub.
* Building and pushing a Docker image.
This requires the following tools.
* Docker
And the following permissions.
* Push access to the github.com/coreos/dex git repo.
* Push access to the quay.io/coreos/dex Docker repo.
## Tagging the release
Make sure you've [uploaded your GPG key](https://github.com/settings/keys) and
configured git to [use that signing key](
https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) either globally or
for the Dex repo. Note that the email the key is issued for must be the email
you use for git.
```
git config [--global] user.signingkey "{{ GPG key ID }}"
git config [--global] user.email "{{ Email associated with key }}"
```
Create a signed tag at the commit you wish to release. This action will prompt
you to enter a tag message, which can just be the release version.
```
git tag -s v2.0.0 ea4c04fde83bd6c48f4d43862c406deb4ea9dba2
```
Push that tag to the CoreOS repo.
```
git push git@github.com:coreos/dex.git v2.0.0
```
Draft releases on GitHub and summarize the changes since the last release. See
previous releases for the expected format.
https://github.com/coreos/dex/releases
## Minor releases - create a branch
If the release is a minor release (2.1.0, 2.2.0, etc.) create a branch for future patch releases.
```bash
git checkout -b v2.1.x tags/v2.1.0
git push git@github.com:coreos/dex.git v2.1.x
```
## Patch releases - cherry pick required commits
If the release is a patch release (2.0.1, 2.0.2, etc.) checkout the desired release branch and cherry pick specific commits. A patch release is only meant for urgent bug or security fixes.
```bash
RELEASE_BRANCH="v2.0.x"
git checkout $RELEASE_BRANCH
git checkout -b "cherry-picked-change"
git cherry-pick (SHA of change)
git push origin "cherry-picked-change"
```
Open a PR onto $RELEASE_BRANCH to get the changes approved.
## Building the Docker image
Build the Docker image and push to Quay.
```bash
# checkout the tag
git checkout tags/v2.1.0
# will prompt for sudo password
make docker-image
sudo docker push quay.io/coreos/dex:v2.1.0
```

View File

@ -1,50 +0,0 @@
# Getting started
## Building the dex binary
Dex requires a Go installation and a GOPATH configured. For setting up a Go workspace, refer to the [official documentation][go-setup]. Clone it down the correct place, and simply type `make` to compile the dex binary.
```
$ go get github.com/coreos/dex
$ cd $GOPATH/src/github.com/coreos/dex
$ make
```
## Configuration
Dex exclusively pulls configuration options from a config file. Use the [example config][example-config] file found in the `examples/` directory to start an instance of dex with an in-memory data store and a set of predefined OAuth2 clients.
```
./bin/dex serve examples/config-dev.yaml
```
The [example config][example-config] file documents many of the configuration options through inline comments. For extra config options, look at that file.
## Running a client
Dex operates like most other OAuth2 providers. Users are redirected from a client app to dex to login. Dex ships with an example client app (also built with the `make` command), for testing and demos.
By default, the example client is configured with the same OAuth2 credentials defined in `examples/config-dev.yaml` to talk to dex. Running the example app will cause it to query dex's [discovery endpoint][oidc-discovery] and determine the OAuth2 endpoints.
```
./bin/example-app
```
Login to dex through the example app using the following steps.
1. Navigate to the example app in your browser at http://localhost:5555/ in your browser.
2. Hit "login" on the example app to be redirected to dex.
3. Choose the "Login with Email" and enter "admin@example.com" and "password"
4. Approve the example app's request.
5. See the resulting token the example app claims from dex.
## Further reading
Dex is generally used as a building block to drive authentication for other apps. See [_"Writing apps that use dex"_][using-dex] for an overview of instrumenting apps to work with dex.
Check out the Documentation directory for further reading on setting up different storages, interacting with the dex API, intros for OpenID Connect, and logging in through other identity providers such as Google, GitHub, or LDAP.
[go-setup]: https://golang.org/doc/install
[example-config]: ../examples/config-dev.yaml
[oidc-discovery]: https://openid.net/specs/openid-connect-discovery-1_0-17.html#ProviderMetadata
[using-dex]: using-dex.md

View File

@ -1,110 +0,0 @@
# Authentication through GitHub
## Overview
One of the login options for dex uses the GitHub OAuth2 flow to identify the end user through their GitHub account.
When a client redeems a refresh token through dex, dex will re-query GitHub to update user information in the ID Token. To do this, __dex stores a readonly GitHub access token in its backing datastore.__ Users that reject dex's access through GitHub will also revoke all dex clients which authenticated them through GitHub.
## Caveats
* The GitHub API calls dex uses requires a user to have their organization membership visibility set to public. This can be done on the ["request access from org" page](github-request-org-access) which GitHub will skip if the client app is an existing authorized application. The current workaround is as follows: the user should log into their GitHub account, go to Settings -> Authorized OAuth Apps, click 'Revoke' to revoke the application's grant, and restart the dex login process. This will force the "request access from org" page to be shown, allowing the user to request that the organization owner make their membership public.
* Note: GitHub [organizations][github-orgs] are different from GitHub [teams][github-teams]
## Configuration
Register a new application with [GitHub][github-oauth2] ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`.
The following is an example of a configuration for `examples/config-dev.yaml`:
```yaml
connectors:
- type: github
# Required field for connector id.
id: github
# Required field for connector name.
name: GitHub
config:
# Credentials can be string literals or pulled from the environment.
clientID: $GITHUB_CLIENT_ID
clientSecret: $GITHUB_CLIENT_SECRET
redirectURI: http://127.0.0.1:5556/dex/callback
# Optional organizations and teams, communicated through the "groups" scope.
#
# NOTE: This is an EXPERIMENTAL config option and will likely change.
#
# Legacy 'org' field. 'org' and 'orgs' cannot be used simultaneously. A user
# MUST be a member of the following org to authenticate with dex.
# org: my-organization
#
# Dex queries the following organizations for group information if the
# "groups" scope is provided. Group claims are formatted as "(org):(team)".
# For example if a user is part of the "engineering" team of the "coreos"
# org, the group claim would include "coreos:engineering".
#
# A user MUST be a member of at least one of the following orgs to
# authenticate with dex.
orgs:
- name: my-organization
# Include all teams as claims.
- name: my-organization-with-teams
# A white list of teams. Only include group claims for these teams.
teams:
- read-team
- blue-team
```
## GitHub Enterprise
Users can use their GitHub Enterprise account to login to dex. The following configuration can be used to enable a GitHub Enterprise connector on dex:
```yaml
connectors:
- type: github
# Required field for connector id.
id: github
# Required field for connector name.
name: GitHub
config:
# Required fields. Dex must be pre-registered with GitHub Enterprise
# to get the following values.
# Credentials can be string literals or pulled from the environment.
clientID: $GITHUB_CLIENT_ID
clientSecret: $GITHUB_CLIENT_SECRET
redirectURI: http://127.0.0.1:5556/dex/callback
# Optional organizations and teams, communicated through the "groups" scope.
#
# NOTE: This is an EXPERIMENTAL config option and will likely change.
#
# Legacy 'org' field. 'org' and 'orgs' cannot be used simultaneously. A user
# MUST be a member of the following org to authenticate with dex.
# org: my-organization
#
# Dex queries the following organizations for group information if the
# "groups" scope is provided. Group claims are formatted as "(org):(team)".
# For example if a user is part of the "engineering" team of the "coreos"
# org, the group claim would include "coreos:engineering".
#
# A user MUST be a member of at least one of the following orgs to
# authenticate with dex.
orgs:
- name: my-organization
# Include all teams as claims.
- name: my-organization-with-teams
# A white list of teams. Only include group claims for these teams.
teams:
- read-team
- blue-team
# Required ONLY for GitHub Enterprise.
# This is the Hostname of the GitHub Enterprise account listed on the
# management console. Ensure this domain is routable on your network.
hostName: git.example.com
# ONLY for GitHub Enterprise. Optional field.
# Used to support self-signed or untrusted CA root certificates.
rootCA: /etc/dex/ca.crt
```
[github-oauth2]: https://github.com/settings/applications/new
[github-orgs]: https://developer.github.com/v3/orgs/
[github-teams]: https://developer.github.com/v3/orgs/teams/
[github-request-org-access]: https://help.github.com/articles/requesting-organization-approval-for-oauth-apps/

View File

@ -1,29 +0,0 @@
# Authentication through Gitlab
## Overview
GitLab is a web-based Git repository manager with wiki and issue tracking features, using an open source license, developed by GitLab Inc. One of the login options for dex uses the GitLab OAuth2 flow to identify the end user through their GitLab account. You can use this option with [gitlab.com](gitlab.com), GitLab community or enterprise edition.
When a client redeems a refresh token through dex, dex will re-query GitLab to update user information in the ID Token. To do this, __dex stores a readonly GitLab access token in its backing datastore.__ Users that reject dex's access through GitLab will also revoke all dex clients which authenticated them through GitLab.
## Configuration
Register a new application via `User Settings -> Applications` ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`.
The following is an example of a configuration for `examples/config-dev.yaml`:
```yaml
connectors:
- type: gitlab
# Required field for connector id.
id: gitlab
# Required field for connector name.
name: GitLab
config:
# optional, default = https://www.gitlab.com
baseURL: https://www.gitlab.com
# Credentials can be string literals or pulled from the environment.
clientID: $GITLAB_APPLICATION_ID
clientSecret: $GITLAB_CLIENT_SECRET
redirectURI: http://127.0.0.1:5556/dex/callback
```

View File

@ -1,6 +0,0 @@
# Integrations
This document tracks the libraries and tools that are compatible with dex. [Join the community](https://github.com/coreos/dex/), and help us keep the list up-to-date.
## Tools
## Projects with a dex dependency

View File

@ -1,127 +0,0 @@
# Kubernetes authentication through dex
## Overview
This document covers setting up the [Kubernetes OpenID Connect token authenticator plugin][k8s-oidc] with dex.
Token responses from OpenID Connect providers include a signed JWT called an ID Token. ID Tokens contain names, emails, unique identifiers, and in dex's case, a set of groups that can be used to identify the user. OpenID Connect providers, like dex, publish public keys; the Kubernetes API server understands how to use these to verify ID Tokens.
The authentication flow looks like:
1. OAuth2 client logs a user in through dex.
2. That client uses the returned ID Token as a bearer token when talking to the Kubernetes API.
3. Kubernetes uses dex's public keys to verify the ID Token.
4. A claim designated as the username (and optionally group information) will be associated with that request.
Username and group information can be combined with Kubernetes [authorization plugins][k8s-authz], such as roles based access control (RBAC), to enforce policy.
## Configuring the OpenID Connect plugin
Configuring the API server to use the OpenID Connect [authentication plugin][k8s-oidc] requires:
* Deploying an API server with specific flags.
* Dex is running on HTTPS.
* Custom CA files must be accessible by the API server (likely through volume mounts).
* Dex is accessible to both your browser and the Kubernetes API server.
Use the following flags to point your API server(s) at dex. `dex.example.com` should be replaced by whatever DNS name or IP address dex is running under.
```
--oidc-issuer-url=https://dex.example.com:32000
--oidc-client-id=example-app
--oidc-ca-file=/etc/kubernetes/ssl/openid-ca.pem
--oidc-username-claim=email
--oidc-groups-claim=groups
```
Additional notes:
* The API server configured with OpenID Connect flags doesn't require dex to be available upfront.
* Other authenticators, such as client certs, can still be used.
* Dex doesn't need to be running when you start your API server.
* Kubernetes only trusts ID Tokens issued to a single client.
* As a work around dex allows clients to [trust other clients][trusted-peers] to mint tokens on their behalf.
* If a claim other than "email" is used for username, for example "sub", it will be prefixed by `"(value of --oidc-issuer-url)#"`. This is to namespace user controlled claims which may be used for privilege escalation.
## Deploying dex on Kubernetes
The dex repo contains scripts for running dex on a Kubernetes cluster with authentication through GitHub. The dex service is exposed using a [node port][node-port] on port 32000. This likely requires a custom `/etc/hosts` entry pointed at one of the cluster's workers.
Because dex uses `ThirdPartyResources` to store state, no external database is needed. For more details see the [storage documentation](storage.md#kubernetes-third-party-resources).
There are many different ways to spin up a Kubernetes development cluster, each with different host requirements and support for API server reconfiguration. At this time, this guide does not have copy-pastable examples, but can recommend the following methods for spinning up a cluster:
* [coreos-kubernetes][coreos-kubernetes] repo for vagrant and VirtualBox users.
* [coreos-baremetal][coreos-baremetal] repo for Linux QEMU/KVM users.
To run dex on Kubernetes perform the following steps:
1. Generate TLS assets for dex.
2. Spin up a Kubernetes cluster with the appropriate flags and CA volume mount.
3. Create a secret containing your [GitHub OAuth2 client credentials][github-oauth2].
4. Deploy dex.
5. Create and assign 'dex' cluster role to dex service account (if RBAC authorization is used).
The TLS assets can be created using the following command:
```
$ cd examples/k8s
$ ./gencert.sh
```
The created `ssl/ca.pem` must then be mounted into your API server deployment. Once the cluster is up and correctly configured, use kubectl to add the serving certs as secrets.
```
$ kubectl create secret tls dex.example.com.tls --cert=ssl/cert.pem --key=ssl/key.pem
```
Then create a secret for the GitHub OAuth2 client.
```
$ kubectl create secret \
generic github-client \
--from-literal=client-id=$GITHUB_CLIENT_ID \
--from-literal=client-secret=$GITHUB_CLIENT_SECRET
```
Create the dex deployment, configmap, and node port service.
```
$ kubectl create -f dex.yaml
```
Assign cluster role to dex service account so it can create third party resources [Kubernetes third party resources](storage.md).
__Caveats:__ No health checking is configured because dex does its own TLS termination complicating the setup. This is a known issue and can be tracked [here][dex-healthz].
## Logging into the cluster
The `example-app` can be used to log into the cluster and get an ID Token. To build the app, you can run `make` in the root of the repo and it will build the `example-app` binary in the repo's `bin` directory. To build the `example-app` requires at least a 1.7 version of Go.
```
$ ./bin/example-app --issuer https://dex.example.com:32000 --issuer-root-ca examples/k8s/ssl/ca.pem
```
Please note that the `example-app` will listen at http://127.0.0.1:5555 and can be changed with the `--listen` flag.
Once the example app is running, choose the GitHub option and grant access to dex to view your profile.
The default redirect uri is http://127.0.0.1:5555/callback and can be changed with the `--redirect-uri` flag and should correspond with your configmap.
The printed ID Token can then be used as a bearer token to authenticate against the API server.
```
$ token='(id token)'
$ curl -H "Authorization: Bearer $token" -k https://( API server host ):443/api/v1/nodes
```
[k8s-authz]: http://kubernetes.io/docs/admin/authorization/
[k8s-oidc]: http://kubernetes.io/docs/admin/authentication/#openid-connect-tokens
[trusted-peers]: https://godoc.org/github.com/coreos/dex/storage#Client
[coreos-kubernetes]: https://github.com/coreos/coreos-kubernetes/
[coreos-baremetal]: https://github.com/coreos/coreos-baremetal/
[dex-healthz]: https://github.com/coreos/dex/issues/682
[github-oauth2]: https://github.com/settings/applications/new
[node-port]: http://kubernetes.io/docs/user-guide/services/#type-nodeport
[coreos-kubernetes]: https://github.com/coreos/coreos-kubernetes
[coreos-baremetal]: https://github.com/coreos/coreos-baremetal

View File

@ -1,254 +0,0 @@
# Authentication through LDAP
## Overview
The LDAP connector allows email/password based authentication, backed by a LDAP directory.
The connector executes two primary queries:
1. Finding the user based on the end user's credentials.
2. Searching for groups using the user entry.
## Security considerations
Dex attempts to bind with the backing LDAP server using the end user's _plain text password_. Though some LDAP implementations allow passing hashed passwords, dex doesn't support hashing and instead _strongly recommends that all administrators just use TLS_. This can often be achieved by using port 636 instead of 389, and administrators that choose 389 are actively leaking passwords.
Dex currently allows insecure connections because the project is still verifying that dex works with the wide variety of LDAP implementations. However, dex may remove this transport option, and _users who configure LDAP login using 389 are not covered by any compatibility guarantees with future releases._
## Configuration
User entries are expected to have an email attribute (configurable through `emailAttr`), and a display name attribute (configurable through `nameAttr`). `*Attr` attributes could be set to "DN" in situations where it is needed but not available elsewhere, and if "DN" attribute does not exist in the record.
The following is an example config file that can be used by the LDAP connector to authenticate a user.
```yaml
connectors:
- type: ldap
# Required field for connector id.
id: ldap
# Required field for connector name.
name: LDAP
config:
# Host and optional port of the LDAP server in the form "host:port".
# If the port is not supplied, it will be guessed based on "insecureNoSSL",
# and "startTLS" flags. 389 for insecure or StartTLS connections, 636
# otherwise.
host: ldap.example.com:636
# Following field is required if the LDAP host is not using TLS (port 389).
# Because this option inherently leaks passwords to anyone on the same network
# as dex, THIS OPTION MAY BE REMOVED WITHOUT WARNING IN A FUTURE RELEASE.
#
# insecureNoSSL: true
# If a custom certificate isn't provide, this option can be used to turn on
# TLS certificate checks. As noted, it is insecure and shouldn't be used outside
# of explorative phases.
#
# insecureSkipVerify: true
# When connecting to the server, connect using the ldap:// protocol then issue
# a StartTLS command. If unspecified, connections will use the ldaps:// protocol
#
# startTLS: true
# Path to a trusted root certificate file. Default: use the host's root CA.
rootCA: /etc/dex/ldap.ca
# A raw certificate file can also be provided inline.
# rootCAData: ( base64 encoded PEM file )
# The DN and password for an application service account. The connector uses
# these credentials to search for users and groups. Not required if the LDAP
# server provides access for anonymous auth.
# Please note that if the bind password contains a `$`, it has to be saved in an
# environment variable which should be given as the value to `bindPW`.
bindDN: uid=seviceaccount,cn=users,dc=example,dc=com
bindPW: password
# User search maps a username and password entered by a user to a LDAP entry.
userSearch:
# BaseDN to start the search from. It will translate to the query
# "(&(objectClass=person)(uid=<username>))".
baseDN: cn=users,dc=example,dc=com
# Optional filter to apply when searching the directory.
filter: "(objectClass=person)"
# username attribute used for comparing user entries. This will be translated
# and combined with the other filter as "(<attr>=<username>)".
username: uid
# The following three fields are direct mappings of attributes on the user entry.
# String representation of the user.
idAttr: uid
# Required. Attribute to map to Email.
emailAttr: mail
# Maps to display name of users. No default value.
nameAttr: name
# Group search queries for groups given a user entry.
groupSearch:
# BaseDN to start the search from. It will translate to the query
# "(&(objectClass=group)(member=<user uid>))".
baseDN: cn=groups,dc=freeipa,dc=example,dc=com
# Optional filter to apply when searching the directory.
filter: "(objectClass=group)"
# Following two fields are used to match a user to a group. It adds an additional
# requirement to the filter that an attribute in the group must match the user's
# attribute value.
userAttr: uid
groupAttr: member
# Represents group name.
nameAttr: name
```
The LDAP connector first initializes a connection to the LDAP directory using the `bindDN` and `bindPW`. It then tries to search for the given `username` and bind as that user to verify their password.
Searches that return multiple entries are considered ambiguous and will return an error.
## Example: Mapping a schema to a search config
Writing a search configuration often involves mapping an existing LDAP schema to the various options dex provides. To query an existing LDAP schema install the OpenLDAP tool `ldapsearch`. For `rpm` based distros run:
```
sudo dnf install openldap-clients
```
For `apt-get`:
```
sudo apt-get install ldap-utils
```
For smaller user directories it may be practical to dump the entire contents and search by hand.
```
ldapsearch -x -h ldap.example.org -b 'dc=example,dc=org' | less
```
First, find a user entry. User entries declare users who can login to LDAP connector using username and password.
```
dn: uid=jdoe,cn=users,cn=compat,dc=example,dc=org
cn: Jane Doe
objectClass: posixAccount
objectClass: ipaOverrideTarget
objectClass: top
gidNumber: 200015
gecos: Jane Doe
uidNumber: 200015
loginShell: /bin/bash
homeDirectory: /home/jdoe
mail: jane.doe@example.com
uid: janedoe
```
Compose a user search which returns this user.
```yaml
userSearch:
# The directory directly above the user entry.
baseDN: cn=users,cn=compat,dc=example,dc=org
filter: "(objectClass=posixAccount)"
# Expect user to enter "janedoe" when logging in.
username: uid
# Use the full DN as an ID.
idAttr: DN
# When an email address is not available, use another value unique to the user, like uid.
emailAttr: mail
nameAttr: gecos
```
Second, find a group entry.
```
dn: cn=developers,cn=groups,cn=compat,dc=example,dc=org
memberUid: janedoe
memberUid: johndoe
gidNumber: 200115
objectClass: posixGroup
objectClass: ipaOverrideTarget
objectClass: top
cn: developers
```
Group searches must match a user attribute to a group attribute. In this example, the search returns users whose uid is found in the group's list of memberUid attributes.
```yaml
groupSearch:
# The directory directly above the group entry.
baseDN: cn=groups,cn=compat,dc=example,dc=org
filter: "(objectClass=posixGroup)"
# The group search needs to match the "uid" attribute on
# the user with the "memberUid" attribute on the group.
userAttr: uid
groupAttr: memberUid
# Unique name of the group.
nameAttr: cn
```
To extract group specific information the `DN` can be used in the `userAttr` field.
```
# Top level object example.coma in LDIF file.
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
```
The following is an example of a group query would match any entry with member=<user DN>:
```yaml
groupSearch:
# BaseDN to start the search from. It will translate to the query
# "(&(objectClass=group)(member=<user DN>))".
baseDN: cn=groups,cn=compat,dc=example,dc=com
# Optional filter to apply when searching the directory.
filter: "(objectClass=group)"
userAttr: DN # Use "DN" here not "uid"
groupAttr: member
nameAttr: name
```
## Example: Searching a FreeIPA server with groups
The following configuration will allow the LDAP connector to search a FreeIPA directory using an LDAP filter.
```yaml
connectors:
- type: ldap
id: ldap
name: LDAP
config:
# host and port of the LDAP server in form "host:port".
host: freeipa.example.com:636
# freeIPA server's CA
rootCA: ca.crt
userSearch:
# Would translate to the query "(&(objectClass=person)(uid=<username>))".
baseDN: cn=users,dc=freeipa,dc=example,dc=com
filter: "(objectClass=posixAccount)"
username: uid
idAttr: uid
# Required. Attribute to map to Email.
emailAttr: mail
# Entity attribute to map to display name of users.
groupSearch:
# Would translate to the query "(&(objectClass=group)(member=<user uid>))".
baseDN: cn=groups,dc=freeipa,dc=example,dc=com
filter: "(objectClass=group)"
userAttr: uid
groupAttr: member
nameAttr: name
```
If the search finds an entry, it will attempt to use the provided password to bind as that user entry.

View File

@ -1,56 +0,0 @@
# Authentication through an OpenID Connect provider
## Overview
Dex is able to use another OpenID Connect provider as an authentication source. When logging in, dex will redirect to the upstream provider and perform the necessary OAuth2 flows to determine the end users email, username, etc. More details on the OpenID Connect protocol can be found in [_An overview of OpenID Connect_][oidc-doc].
Prominent examples of OpenID Connect providers include Google Accounts, Salesforce, and Azure AD v2 ([not v1][azure-ad-v1]).
## Caveats
Many OpenID Connect providers implement different restrictions on refresh tokens. For example, Google will only issue the first login attempt a refresh token, then not return one after. Because of this, this connector does not refresh the id_token claims when a client of dex redeems a refresh token, which can result in stale user info.
It's generally recommended to avoid using refresh tokens with the `oidc` connector.
Progress on this caveat can be tracked in [issue #863][google-refreshing].
## Configuration
```yaml
connectors:
- type: oidc
id: google
name: Google
config:
# Canonical URL of the provider, also used for configuration discovery.
# This value MUST match the value returned in the provider config discovery.
#
# See: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
issuer: https://accounts.google.com
# Connector config values starting with a "$" will read from the environment.
clientID: $GOOGLE_CLIENT_ID
clientSecret: $GOOGLE_CLIENT_SECRET
# Dex's issuer URL + "/callback"
redirectURI: http://127.0.0.1:5556/callback
# Some providers require passing client_secret via POST parameters instead
# of basic auth, despite the OAuth2 RFC discouraging it. Many of these
# cases are caught internally, but some may need to uncommented the
# following field.
#
# basicAuthUnsupported: true
# Google supports whitelisting allowed domains when using G Suite
# (Google Apps). The following field can be set to a list of domains
# that can log in:
#
# hostedDomains:
# - example.com
```
[oidc-doc]: openid-connect.md
[google-refreshing]: https://github.com/coreos/dex/issues/863
[azure-ad-v1]: https://github.com/coreos/go-oidc/issues/133

View File

@ -1,141 +0,0 @@
# An overview of OpenID Connect
This document attempts to provide a general overview of the [OpenID Connect protocol](https://openid.net/connect/), a flavor of OAuth2 that dex implements. While this document isn't complete, we hope it provides enough information to get users up and running.
For an overview of custom claims, scopes, and client features implemented by dex, see [this document][scopes-claims-clients].
## OAuth2
OAuth2 should be familiar to anyone who's used something similar to a "Login
with Facebook" button. In these cases an application has chosen to let an
outside provider, in this case Facebook, attest to your identity instead of
having you set a username and password with the app itself.
The general flow for server side apps is:
1. A new user visits an application.
1. The application redirects the user to Facebook.
1. The user logs into Facebook, then is asked if it's okay to let the
application view the user's profile, post on their behalf, etc.
1. If the user clicks okay, Facebook redirects the user back to the application
with a code.
1. The application redeems that code with provider for a token that can be used
to access the authorized actions, such as viewing a users profile or posting on
their wall.
In these cases, dex is acting as Facebook (called the "provider" in OpenID
Connect) while clients apps redirect to it for the end user's identity.
## ID Tokens
Unfortunately the access token applications get from OAuth2 providers is
completely opaque to the client and unique to the provider. The token you
receive from Facebook will be completely different from the one you'd get from
Twitter or GitHub.
OpenID Connect's primary extension of OAuth2 is an additional token returned in
the token response called the ID Token. This token is a [JSON Web Token](
https://tools.ietf.org/html/rfc7519) signed by the OpenID Connect server, with
well known fields for user ID, name, email, etc. A typical token response from
an OpenID Connect looks like (with less whitespace):
```
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
}
```
That ID Token is a JWT with three base64'd fields separated by dots. The first
is a header, the second is a payload, and the third is a signature of the first
two fields. When parsed we can see the payload of this value is.
```
{
"iss": "http://server.example.com",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"nonce": "n-0S6_WzA2Mj",
"exp": 1311281970,
"iat": 1311280970
}
```
This has a few interesting fields such as
* The server that issued this token (`iss`).
* The token's subject (`sub`). In this case a unique ID of the end user.
* The token's audience (`aud`). The ID of the OAuth2 client this was issued for.
TODO: Add examples of payloads with "email" fields.
## Discovery
OpenID Connect servers have a discovery mechanism for OAuth2 endpoints, scopes
supported, and indications of various other OpenID Connect features.
```
$ curl http://127.0.0.1:5556/.well-known/openid-configuration
{
"issuer": "http://127.0.0.1:5556",
"authorization_endpoint": "http://127.0.0.1:5556/auth",
"token_endpoint": "http://127.0.0.1:5556/token",
"jwks_uri": "http://127.0.0.1:5556/keys",
"response_types_supported": [
"code"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"scopes_supported": [
"openid",
"email",
"profile"
]
}
```
Importantly, we've discovered the authorization endpoint, token endpoint, and
the location of the server's public keys. OAuth2 clients should be able to use
the token and auth endpoints immediately, while a JOSE library can be used to
parse the keys. The keys endpoint returns a [JSON Web Key](
https://tools.ietf.org/html/rfc7517) Set of public keys that will look
something like this:
```
$ curl http://127.0.0.1:5556/keys
{
"keys": [
{
"use": "sig",
"kty": "RSA",
"kid": "5d19a0fde5547960f4edaa1e1e8293e5534169ba",
"alg": "RS256",
"n": "5TAXCxkAQqHEqO0InP81z5F59PUzCe5ZNaDsD1SXzFe54BtXKn_V2a3K-BUNVliqMKhC2LByWLuI-A5ZlA5kXkbRFT05G0rusiM0rbkN2uvRmRCia4QlywE02xJKzeZV3KH6PldYqV_Jd06q1NV3WNqtcHN6MhnwRBfvkEIm7qWdPZ_mVK7vayfEnOCFRa7EZqr-U_X84T0-50wWkHTa0AfnyVvSMK1eKL-4yc26OWkmjh5ALfQFtnsz30Y2TOJdXtEfn35Y_882dNBDYBxtJV4PaSjXCxhiaIuBHp5uRS1INyMXCx2ve22ASNx_ERorv6BlXQoMDqaML2bSiN9N8Q",
"e": "AQAB"
}
]
}
```
[scopes-claims-clients]: custom-scopes-claims-clients.md

View File

@ -1,3 +0,0 @@
# Production users
This document tracks people and use cases for dex in production. [Join the community](https://github.com/coreos/dex/), and help us keep the list up-to-date.

View File

@ -1,82 +0,0 @@
# Proposal: design for revoking refresh tokens.
Refresh tokens are issued to the client by the authorization server and are used
to request a new access token when the current access token becomes invalid or expires.
It is a common usecase for the end users to revoke client access to their identity.
This proposal defines the changes needed in Dex v2 to support refresh token revocation.
## Motivation
1. Currently refresh tokens are not associated with the user. Need a new "session object" for this.
2. Need an API to list refresh tokens based on the UserID.
3. We need a way for users to login to dex and revoke a client.
4. Limit the number refresh tokens for each user-client pair to 1.
## Details
Currently in Dex when an end user successfully logs in via a connector and has the OfflineAccess
scope set to true, a refresh token is created and stored in the backing datastore. There is no
association between the end user and the refresh token. Hence if we want to support the functionality
of users being able to revoke refresh tokens, the first step is to have a structure in place that allows
us retrieve a list of refresh tokens depending on the authenticated user.
```go
// Reference object for RefreshToken containing only metadata.
type RefreshTokenRef struct {
// ID of the RefreshToken
ID string
CreatedAt time.Time
LastUsed time.Time
}
// Session objects pertaining to users with refresh tokens.
//
// Will have to handle garbage collection i.e. if no refresh token exists for a user,
// this object must be cleaned up.
type OfflineSession struct {
// UserID of an end user who has logged in to the server.
UserID string
// The ID of the connector used to login the user.
ConnID string
// List of pointers to RefreshTokens issued for SessionID
Refresh []*RefreshTokenRef
}
// Retrieve OfflineSession obj for given userId and connID
func getOfflineSession (userId string, connID string)
```
### Changes in Dex CodeFlows
1. Client requests a refresh token:
Try to retrieve the `OfflineSession` object for the User with the given `UserID + ConnID`.
This leads to two possibilities:
* Object exists: This means a Refresh token already exists for the user.
Update the existing `OffilineSession` object with the newly received token as follows:
* CreateRefresh() will create a new `RefreshToken` obj in the storage.
* Update the `Refresh` list with the new `RefreshToken` pointer.
* Delete the old refresh token in storage.
* No object found: This implies that this will be the first refresh token for the user.
* CreateRefresh() will create a new `RefreshToken` obj in the storage.
* Create an OfflineSession for the user and add the new `RefreshToken` pointer to
the `Refresh` list.
2. Refresh token rotation:
There will be no change to this codeflow. When the client refreshes a refresh token, the `TokenID`
still remains intact and only the `RefreshToken` obj gets updated with a new nonce. We do not need
any additional checks in the OfflineSession objects as the `RefreshToken` pointers still remain intact.
3. User revokes a refresh token (New functionality):
A user that has been authenticated externally will have the ability to revoke their refresh tokens.
Please note that Dex's API does not perform the authentication, this will have to be done by an
external app.
Steps involved:
* Get `OfflineSession` obj with given UserID + ConnID.
* If a refresh token exists in `Refresh`, delete the `RefreshToken` (handle this in storage)
and its pointer value in `Refresh`. Clean up the OfflineSession object.
* If there is no refresh token found, handle error case.
NOTE: To avoid race conditions between “requesting a refresh token” and “revoking a refresh token”, use
locking mechanism when updating an `OfflineSession` object.

View File

@ -1,165 +0,0 @@
# Proposal: upstream refreshing
## TL;DR
Today, if a user deletes their GitHub account, dex will keep allowing clients to
refresh tokens on that user's behalf because dex never checks back in with
GitHub.
This is a proposal to change the connector package so the dex can check back
in with GitHub.
## The problem
When dex is federaing to an upstream identity provider (IDP), we want to ensure
claims being passed onto clients remain fresh. This includes data such as Google
accounts display names, LDAP group membership, account deactivations. Changes to
these on an upstream IDP should always be reflected in the claims dex passes to
its own clients.
Refresh tokens make this complicated. When refreshing a token, unlike normal
logins, dex doesn't have the opportunity to prompt for user interaction. For
example, if dex is proxying to a LDAP server, it won't have the user's username
and passwords.
Dex can't do this today because connectors have no concept of checking back in
with an upstream provider (with the sole exception of groups). They're only
called during the initial login, and never consulted when dex needs to mint a
new refresh token for a client. Additionally, connectors aren't actually aware
of the scopes being requested by the client, so they don't know when they should
setup the ability to check back in and have to treat every request identically.
## Changes to the connector package
The biggest changes proposed impact the connector package and connector
implementations.
1. Connectors should be consulted when dex attempts to refresh a token.
2. Connectors should be aware of the scopes requested by the client.
The second bullet is important because of the first. If a client isn't
requesting a refresh token, the connector shouldn't do the extra work, such as
requesting additional upstream scopes.
to address the first point, a top level `Scopes` object will be added to the
connector package to express the scopes requested by the client. The
`CallbackConnector` and `PasswordConnector` will be updated accordingly.
```go
// Scopes represents additional data requested by the clients about the end user.
type Scopes struct{
// The client has requested a refresh token from the server.
OfflineAccess bool
// The client has requested group information about the end user.
Groups bool
}
// CallbackConnector is an interface implemented by connectors which use an OAuth
// style redirect flow to determine user information.
type CallbackConnector interface {
// The initial URL to redirect the user to.
//
// OAuth2 implementations should request different scopes from the upstream
// identity provider based on the scopes requested by the downstream client.
// For example, if the downstream client requests a refresh token from the
// server, the connector should also request a token from the provider.
LoginURL(s Scopes, callbackURL, state string) (string, error)
// Handle the callback to the server and return an identity.
HandleCallback(s Scopes, r *http.Request) (identity Identity, state string, err error)
}
// PasswordConnector is an interface implemented by connectors which take a
// username and password.
type PasswordConnector interface {
Login(s Scopes, username, password string) (identity Identity, validPassword bool, err error)
}
```
The existing `GroupsConnector` plays two roles.
1. The connector only attempts to grab groups when the downstream client requests it.
2. Allow group information to be refreshed.
The first issue is remedied by the added `Scopes` struct. This proposal also
hopes to generalize the need of the second role by adding a more general
`RefreshConnector`:
```go
type Identity struct {
// Existing fields...
// Groups are added to the identity object, since connectors are now told
// if they're being requested.
// The set of groups a user is a member of.
Groups []string
}
// RefreshConnector is a connector that can update the client claims.
type RefreshConnector interface {
// Refresh is called when a client attempts to claim a refresh token. The
// connector should attempt to update the identity object to reflect any
// changes since the token was last refreshed.
Refresh(s Scopes, identity Identity) (Identity, error)
// TODO(ericchiang): Should we allow connectors to indicate that the user has
// been delete or an upstream token has been revoked? This would allow us to
// know when we should remove the downstream refresh token, and when there was
// just a server error, but might be hard to determine for certain protocols.
// Might be safer to always delete the downstream token if the Refresh()
// method returns an error.
}
```
## Example changes to the "passwordDB" connector
The `passwordDB` connector is the internal connector maintained by the server.
As an example, these are the changes to that connector if this change was
accepted.
```go
func (db passwordDB) Login(s connector.Scopes, username, password string) (connector.Identity, bool, error) {
// No change to existing implementation. Scopes can be ignored since we'll
// always have access to the password objects.
}
func (db passwordDB) Refresh(s connector.Scopes, identity connector.Identity) (connector.Identity, error) {
// If the user has been deleted, the refresh token will be rejected.
p, err := db.s.GetPassword(identity.Email)
if err != nil {
if err == storage.ErrNotFound {
return connector.Identity{}, errors.New("user not found")
}
return connector.Identity{}, fmt.Errorf("get password: %v", err)
}
// User removed but a new user with the same email exists.
if p.UserID != identity.UserID {
return connector.Identity{}, errors.New("user not found")
}
// If a user has updated their username, that will be reflected in the
// refreshed token.
identity.Username = p.Username
return identity, nil
}
```
## Caveats
Certain providers, such as Google, will only grant a single refresh token for each
client + end user pair. The second time one's requested, no refresh token is
returned. This means refresh tokens must be stored by dex as objects on an
upstream identity rather than part of a downstream refresh even.
Right now `ConnectorData` is too general for this since it is only stored with a
refresh token and can't be shared between sessions. This should be rethought in
combination with the [`user-object.md`](./user-object.md) proposal to see if
there are reasonable ways for us to do this.
This isn't a problem for providers like GitHub because they return the same
refresh token every time. We don't need to track a token per client.

View File

@ -1,146 +0,0 @@
# Proposal: user objects for revoking refresh tokens and merging accounts
Certain operations require tracking users the have logged in through the server
and storing them in the backend. Namely, allowing end users to revoke refresh
tokens and merging existing accounts with upstream providers.
While revoking refresh tokens is relatively easy, merging accounts is a
difficult problem. What if display names or emails are different? What happens
to a user with two remote identities with the same upstream service? Should
this be presented differently for a user with remote identities for different
upstream services? This proposal only covers a minimal merging implementation
by guaranteeing that merged accounts will always be presented to clients with
the same user ID.
This proposal defines the following objects and methods to be added to the
storage package to allow user information to be persisted.
```go
// User is an end user which has logged in to the server.
//
// Users do not hold additional data, such as emails, because claim information
// is always supplied by an upstream provider during the auth flow. The ID is
// the only information from this object which overrides the claims produced by
// connectors.
//
// Clients which wish to associate additional data with a user must do so on
// their own. The server only guarantees that IDs will be constant for an end
// user, no matter what backend they use to login.
type User struct {
// A string which uniquely identifies the user for the server. This overrides
// the ID provided by the connector in the ID Token claims.
ID string
// A list of clients who have been issued refresh tokens for this user.
//
// When a refresh token is redeemed, the server will check this field to
// ensure that the client is still on this list. To revoke a client,
// remove it from here.
AuthorizedClients []AuthorizedClient
// A set of remote identities which are able to login as this user.
RemoteIdentities []RemoteIdentity
}
// AuthorizedClient is a client that has a refresh token out for this user.
type AuthorizedClient struct {
// The ID of the client.
ClientID string
// The last time a token was refreshed.
LastRefreshed time.Time
}
// RemoteIdentity is the smallest amount of information that identifies a user
// with a remote service. It indicates which remote identities should be able
// to login as a specific user.
//
// RemoteIdentity contains an username so an end user can be displayed this
// object and reason about what upstream profile it represents. It is not used
// to cache claims, such as groups or emails, because these are always provided
// by the upstream identity system during login.
type RemoteIdentity struct {
// The ID of the connector used to login the user.
ConnectorID string
// A string which uniquely identifies the user with the remote system.
ConnectorUserID stirng
// Optional, human readable name for this remote identity. Only used when
// displaying the remote identity to the end user (e.g. when merging
// accounts). NOT used for determining ID Token claims.
Username string
}
```
`UserID` fields will be added to the `AuthRequest`, `AuthCode` and `RefreshToken`
structs. When a user logs in successfully through a connector
[here](https://github.com/coreos/dex/blob/95a61454b522edd6643ced36b9d4b9baa8059556/server/handlers.go#L227),
the server will attempt to either get the user, or create one if none exists with
the remote identity.
`AuthorizedClients` serves two roles. First is makes displaying the set of
clients a user is logged into easy. Second, because we don't assume multi-object
transactions, we can't ensure deleting all refresh tokens a client has for a
user. Between listing the set of refresh tokens and deleting a token, a client
may have already redeemed the token and created a new one.
When an OAuth2 client exchanges a code for a token, the following steps are
taken to populate the `AuthorizedClients`:
1. Get token where the user has authorized the `offline_access` scope.
1. Update the user checking authorized clients. If client is not in the list,
add it.
1. Create a refresh token and return the token.
When a OAuth2 client attempts to renew a refresh token, the server ensures that
the token hasn't been revoked.
1. Check authorized clients and update the `LastRefreshed` timestamp. If client
isn't in list error out and delete the refresh token.
1. Continue renewing the refresh token.
When the end user revokes a client, the following steps are used to.
1. Update the authorized clients by removing the client from the list. This
atomic action causes any renew attempts to fail.
1. Iterate through list of refresh tokens and garbage collect any tokens issued
by the user for the client. This isn't atomic, but exists so a user can
re-authorize a client at a later time without authorizing old refresh tokens.
This is clunky due to the lack of multi-object transactions. E.g. we can't delete
all the refresh tokens at once because we don't have that guarantee.
Merging accounts becomes extremely simple. Just add another remote identity to
the user object.
We hope to provide a web interface that a user can login to to perform these
actions. Perhaps using a well known client issued exclusively for the server.
The new `User` object requires adding the following methods to the storage
interface, and (as a nice side effect) deleting the `ListRefreshTokens()` method.
```go
type Storage interface {
// ...
CreateUser(u User) error
DeleteUser(id string) error
GetUser(id string) error
GetUserByRemoteIdentity(connectorID, connectorUserID string) (User, error)
// Updates are assumed to be atomic.
//
// When a UpdateUser is called, if clients are removed from the
// AuthorizedClients list, the underlying storage SHOULD clean up refresh
// tokens issued for the removed clients. This allows backends with
// multi-transactional capabilities to utilize them, while key-value stores
// only guarantee best effort.
UpdateUser(id string, updater func(old User) (User, error)) error
}
```
Importantly, this will be the first object which has a secondary index.
The Kubernetes client will simply list all the users in memory then iterate over
them to support this (possibly followed by a "watch" based optimization). SQL
implementations will have an easier time.

View File

@ -1,105 +0,0 @@
# Authentication through SAML 2.0
## Overview
The SAML provider allows authentication through the SAML 2.0 HTTP POST binding. The connector maps attribute values in the SAML assertion to user info, such as username, email, and groups.
The connector uses the value of the `NameID` element as the user's unique identifier which dex assumes is both unique and never changes. Use the `nameIDPolicyFormat` to ensure this is set to a value which satisfies these requirements.
Unlike some clients which will process unprompted AuthnResponses, dex must send the initial AuthnRequest and validates the response's InResponseTo value.
## Caveats
__The connector doesn't support refresh tokens__ since the SAML 2.0 protocol doesn't provide a way to requery a provider without interaction. If the "offline_access" scope is requested, it will be ignored.
The connector doesn't support signed AuthnRequests or encrypted attributes.
## Configuration
```yaml
connectors:
- type: saml
# Required field for connector id.
id: saml
# Required field for connector name.
name: SAML
config:
# SSO URL used for POST value.
ssoURL: https://saml.example.com/sso
# CA to use when validating the signature of the SAML response.
ca: /path/to/ca.pem
# Dex's callback URL.
#
# If the response assertion status value contains a Destination element, it
# must match this value exactly.
#
# This is also used as the expected audience for AudienceRestriction elements
# if entityIssuer isn't specified.
redirectURI: https://dex.example.com/callback
# Name of attributes in the returned assertions to map to ID token claims.
usernameAttr: name
emailAttr: email
groupsAttr: groups # optional
# CA's can also be provided inline as a base64'd blob.
#
# caData: ( RAW base64'd PEM encoded CA )
# To skip signature validation, uncomment the following field. This should
# only be used during testing and may be removed in the future.
#
# insecureSkipSignatureValidation: true
# Optional: Manually specify dex's Issuer value.
#
# When provided dex will include this as the Issuer value during AuthnRequest.
# It will also override the redirectURI as the required audience when evaluating
# AudienceRestriction elements in the response.
entityIssuer: https://dex.example.com/callback
# Optional: Issuer value expected in the SAML response.
ssoIssuer: https://saml.example.com/sso
# Optional: Delimiter for splitting groups returned as a single string.
#
# By default, multiple groups are assumed to be represented as multiple
# attributes with the same name.
#
# If "groupsDelim" is provided groups are assumed to be represented as a
# single attribute and the delimiter is used to split the attribute's value
# into multiple groups.
groupsDelim: ", "
# Optional: Requested format of the NameID.
#
# The NameID value is is mapped to the user ID of the user. This can be an
# abbreviated form of the full URI with just the last component. For example,
# if this value is set to "emailAddress" the format will resolve to:
#
# urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
#
# If no value is specified, this value defaults to:
#
# urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
#
nameIDPolicyFormat: persistent
```
A minimal working configuration might look like:
```yaml
connectors:
- type: saml
id: okta
name: Okta
config:
ssoURL: https://dev-111102.oktapreview.com/app/foo/exk91cb99lKkKSYoy0h7/sso/saml
ca: /etc/dex/saml-ca.pem
redirectURI: http://127.0.0.1:5556/dex/callback
usernameAttr: name
emailAttr: email
groupsAttr: groups
```

View File

@ -1,168 +0,0 @@
# Storage options
Dex requires persisting state to perform various tasks such as track refresh tokens, preventing replays, and rotating keys. This document is a summary of the storage configurations supported by dex.
Storage breaches are serious as they can affect applications that rely on dex. Dex saves sensitive data in its backing storage, including signing keys and bcrypt'd passwords. As such, transport security and database ACLs should both be used, no matter which storage option is chosen.
## Kubernetes third party resources
__NOTE:__ Dex requires Kubernetes version 1.4+.
Kubernetes third party resources are a way for applications to create new resources types in the Kubernetes API. This allows dex to run on top of an existing Kubernetes cluster without the need for an external database. While this storage may not be appropriate for a large number of users, it's extremely effective for many Kubernetes use cases.
The rest of this section will explore internal details of how dex uses `ThirdPartyResources`. __Admins should not interact with these resources directly__, except when debugging. These resources are only designed to store state and aren't meant to be consumed by humans. For modifying dex's state dynamically see the [API documentation](api.md).
The `ThirdPartyResource` type acts as a description for the new resource a user wishes to create. The following an example of a resource managed by dex:
```
kind: ThirdPartyResource
apiVersion: extensions/v1beta1
metadata:
name: o-auth2-client.oidc.coreos.com
versions:
- name: v1
description: "An OAuth2 client."
```
Once the `ThirdPartyResource` is created, custom resources can be created at a namespace level (though there will be a gap between the `ThirdPartyResource` being created and the API server accepting the custom resource). While most fields are user defined, the API server still respects the common `ObjectMeta` and `TypeMeta` values. For example names are still restricted to a small set of characters, and the `resourceVersion` field can be used for an [atomic compare and swap][k8s-api].
The following is an example of a custom `OAuth2Client` resource:
```
# Standard Kubernetes resource fields
kind: OAuth2Client
apiVersion: oidc.coreos.com/v1
metadata:
namespace: foobar
name: ( opaque hash )
# Custom fields defined by dex.
clientID: "aclientid"
clientSecret: "clientsecret"
redirectURIs:
- "https://app.example.com/callback"
```
The `ThirdPartyResource` type and the custom resources can be queried, deleted, and edited like any other resource using `kubectl`.
```
kubectl get thirdpartyresources # list third party resources registered on the clusters
kubectl get --namespace=foobar oauth2clients # list oauth2 clients in a given namespace
```
To reduce administrative overhead, dex creates and manages its own third party resources and may create new ones during upgrades. While not strictly required we feel this is important for reasonable updates. Though, as a result, dex requires access to the non-namespaced `ThirdPartyResource` type. For example, clusters using RBAC authorization would need to create the following roles and bindings:
```
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
name: dex
rules:
- apiGroups: ["oidc.coreos.com"] # API group created by dex
resources: ["*"]
verbs: ["*"]
nonResourceURLs: []
- apiGroups: ["extensions"]
resources: ["thirdpartyresources"]
verbs: ["create"] # To manage its own resources identity must be able to create thirdpartyresources.
nonResourceURLs: []
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
name: dex
subjects:
- kind: ServiceAccount
name: dex # Service account assigned to the dex pod.
namespace: demo-namespace # The namespace dex is running in.
roleRef:
kind: ClusterRole
name: identity
apiVersion: rbac.authorization.k8s.io/v1alpha1
```
The storage configuration is extremely limited since installations running outside a Kubernetes cluster would likely prefer a different storage option. An example configuration for dex running inside Kubernetes:
```
storage:
type: kubernetes
config:
inCluster: true
```
Dex determines the namespace it's running in by parsing the service account token automatically mounted into its pod.
## SQL
Dex supports two flavors of SQL, SQLite3 and Postgres. MySQL and CockroachDB may be added at a later time.
Migrations are performed automatically on the first connection to the SQL server (it does not support rolling back). Because of this dex requires privileges to add and alter the tables for its database.
__NOTE:__ Previous versions of dex required symmetric keys to encrypt certain values before sending them to the database. This feature has not yet been ported to dex v2. If it is added later there may not be a migration path for current v2 users.
### SQLite3
SQLite3 is the recommended storage for users who want to stand up dex quickly. It is __not__ appropriate for real workloads.
The SQLite3 configuration takes a single argument, the database file.
```
storage:
type: sqlite3
config:
file: /var/dex/dex.db
```
Because SQLite3 uses file locks to prevent race conditions, if the ":memory:" value is provided dex will automatically disable support for concurrent database queries.
### Postgres
When using Postgres, admins may want to dedicate a database to dex for the following reasons:
1. Dex requires privileged access to its database because it performs migrations.
2. Dex's database table names are not configurable; when shared with other applications there may be table name clashes.
```
CREATE DATABASE dex_db;
CREATE USER dex WITH PASSWORD '66964843358242dbaaa7778d8477c288';
GRANT ALL PRIVILEGES ON DATABASE dex_db TO dex;
```
An example config for Postgres setup using these values:
```
storage:
type: postgres
config:
database: dex_db
user: dex
password: 66964843358242dbaaa7778d8477c288
ssl:
mode: verify-ca
caFile: /etc/dex/postgres.ca
```
The SSL "mode" corresponds to the `github.com/lib/pq` package [connection options][psql-conn-options]. If unspecified, dex defaults to the strictest mode "verify-full".
## Adding a new storage options
Each storage implementation bears a large ongoing maintenance cost and needs to be updated every time a feature requires storing a new type. Bugs often require in depth knowledge of the backing software, and much of this work will be done by developers who are not the original author. Changes to dex which add new storage implementations are not merged lightly.
### New storage option references
Those who still want to construct a proposal for a new storage should review the following packages:
* `github.com/coreos/dex/storage`: Interface definitions which the storage must implement. __NOTE:__ This package is not stable.
* `github.com/coreos/dex/storage/conformance`: Conformance tests which storage implementations must pass.
### New storage option requirements
Any proposal to add a new implementation must address the following:
* Integration testing setups (Travis and developer workstations).
* Transactional requirements: atomic deletes, updates, etc.
* Is there an established and reasonable Go client?
[issues-transaction-tests]: https://github.com/coreos/dex/issues/600
[k8s-api]: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/api-conventions.md#concurrency-control-and-consistency
[psql-conn-options]: https://godoc.org/github.com/lib/pq#hdr-Connection_String_Parameters

View File

@ -1,191 +0,0 @@
# Writing apps that use dex
Once you have dex up and running, the next step is to write applications that use dex to drive authentication. Apps that interact with dex generally fall into one of two categories:
1. Apps that request OpenID Connect ID tokens to authenticate users.
* Used for authenticating an end user.
* Must be web based.
2. Apps that consume ID tokens from other apps.
* Needs to verify that a client is acting on behalf of a user.
The first category of apps are standard OAuth2 clients. Users show up at a website, and the application wants to authenticate those end users by pulling claims out of the ID token.
The second category of apps consume ID tokens as credentials. This lets another service handle OAuth2 flows, then use the ID token retrieved from dex to act on the end user's behalf with the app. An example of an app that falls into this category is the [Kubernetes API server][api-server].
## Requesting an ID token from dex
Apps that directly use dex to authenticate a user use OAuth2 code flows to request a token response. The exact steps taken are:
* User visits client app.
* Client app redirects user to dex with an OAuth2 request.
* Dex determines user's identity.
* Dex redirects user to client with a code.
* Client exchanges code with dex for an id_token.
![][dex-flow]
The dex repo contains a small [example app][example-app] as a working, self contained app that performs this flow.
The rest of this section explores the code sections which to help explain how to implementing this logic in your own app.
### Configuring your app
The example app uses the following Go packages to perform the code flow:
* [github.com/coreos/go-oidc][go-oidc]
* [golang.org/x/oauth2][go-oauth2]
First, client details should be present in the dex configuration. For example, we could register an app with dex with the following section:
```yaml
staticClients:
- id: example-app
secret: example-app-secret
name: 'Example App'
# Where the app will be running.
redirectURIs:
- 'http://127.0.0.1:5555/callback'
```
In this case, the Go code would configured as:
```go
// Initialize a provider by specifying dex's issuer URL.
provider, err := oidc.NewProvider(ctx, "https://dex-issuer-url.com")
if err != nil {
// handle error
}
// Configure the OAuth2 config with the client values.
oauth2Config := oauth2.Config{
// client_id and client_secret of the client.
ClientID: "example-app",
ClientSecret: "example-app-secret",
// The redirectURL.
RedirectURL: "http://127.0.0.1:5556/callback",
// Discovery returns the OAuth2 endpoints.
Endpoint: provider.Endpoint(),
// "openid" is a required scope for OpenID Connect flows.
//
// Other scopes, such as "groups" can be requested.
Scopes: []string{oidc.ScopeOpenID, "profile", "email", "groups"},
}
// Create an ID token parser.
idTokenVerifier := provider.NewVerifier(&oidc.Config{ClientID: "example-app"})
```
The HTTP server should then redirect unauthenticated users to dex to initialize the OAuth2 flow.
```go
// handleRedirect is used to start an OAuth2 flow with the dex server.
func handleRedirect(w http.ResponseWriter, r *http.Request) {
state := newState()
http.Redirect(w, r, oauth2Config.AuthCodeURL(state), http.StatusFound)
}
```
After dex verifies the user's identity it redirects the user back to the client app with a code that can be exchanged for an ID token. The ID token can then be parsed by the verifier created above. This immediately
```go
func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
state := r.URL.Query().Get("state")
// Verify state.
oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
if err != nil {
// handle error
}
// Extract the ID Token from OAuth2 token.
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
if !ok {
// handle missing token
}
// Parse and verify ID Token payload.
idToken, err := idTokenVerifier.Verify(ctx, rawIDToken)
if err != nil {
// handle error
}
// Extract custom claims.
var claims struct {
Email string `json:"email"`
Verified bool `json:"email_verified"`
Groups []string `json:"groups"`
}
if err := idToken.Claims(&claims); err != nil {
// handle error
}
}
```
### State tokens
The state parameter is an arbitrary string that dex will always return with the callback. It plays a security role, preventing certain kinds of OAuth2 attacks. Specifically it can be used by clients to ensure:
* The user who started the flow is the one who finished it, by linking the user's session with the state token. For example, by setting the state as an HTTP cookie, then comparing it when the user returns to the app.
* The request hasn't been replayed. This could be accomplished by associating some nonce in the state.
A more thorough discussion of these kinds of best practices can be found in the [_"OAuth 2.0 Threat Model and Security Considerations"_][oauth2-threat-model] RFC.
## Consuming ID tokens
Apps can also choose to consume ID tokens, letting other trusted clients handle the web flows for login. Clients pass along the ID tokens they receive from dex, usually as a bearer token, letting them act as the user to the backend service.
![][dex-backend-flow]
To accept ID tokens as user credentials, an app would construct an OpenID Connect verifier similarly to the above example. The verifier validates the ID token's signature, ensures it hasn't expired, etc. An important part of this code is that the verifier only trusts the example app's client. This ensures the example app is the one who's using the ID token, and not another, untrusted client.
```go
// Initialize a provider by specifying dex's issuer URL.
provider, err := oidc.NewProvider(ctx, "https://dex-issuer-url.com")
if err != nil {
// handle error
}
// Create an ID token parser, but only trust ID tokens issued to "example-app"
idTokenVerifier := provider.NewVerifier(&oidc.Config{ClientID: "example-app"})
```
The verifier can then be used to pull user info out of tokens:
```go
type user struct {
email string
groups []string
}
// authorize verifies a bearer token and pulls user information form the claims.
func authorize(ctx context.Context, bearerToken string) (*user, error) {
idToken, err := idTokenVerifier.Verify(ctx, bearerToken)
if err != nil {
return nil, fmt.Errorf("could not verify bearer token: %v", err)
}
// Extract custom claims.
var claims struct {
Email string `json:"email"`
Verified bool `json:"email_verified"`
Groups []string `json:"groups"`
}
if err := idToken.Claims(&claims); err != nil {
return nil, fmt.Errorf("failed to parse claims: %v", err)
}
if !claims.Verified {
return nil, fmt.Errorf("email (%q) in returned claims was not verified", claims.Email)
}
return &user{claims.Email, claims.Groups}, nil
}
```
[api-server]: https://kubernetes.io/docs/admin/authentication/#openid-connect-tokens
[dex-flow]: img/dex-flow.png
[dex-backend-flow]: img/dex-backend-flow.png
[example-app]: ../cmd/example-app
[oauth2-threat-model]: https://tools.ietf.org/html/rfc6819
[go-oidc]: https://godoc.org/github.com/coreos/go-oidc
[go-oauth2]: https://godoc.org/golang.org/x/oauth2

View File

@ -1,47 +0,0 @@
# Dex v2
## Streamlined deployments
Many of the changes between v1 and v2 were aimed at making dex easier to deploy and manage, perhaps the biggest pain point for dex v1. Dex is now a single, scalable binary with a sole source of configuration. Many components which previously had to be set through the API, such as OAuth2 clients and IDP connectors can now be specified statically. The new architecture lacks a singleton component eliminating deployment ordering. There are no more special development modes; instructions for running dex on a workstation translate with minimal changes to a production system.
All of this results in a much simpler deployment story. Write a config file, run the dex binary, and that's it.
## More storage backends
Dex's internal storage interface has been improved to support multiple backing databases including Postgres, SQLite3, and the Kubernetes API through Third Party Resources. This allows dex to meet a more diverse set of use cases instead of insisting on one particular deployment pattern. For example, The Kubernetes API implementation, a [key value store][k8s-api-docs], allows dex to be run natively on top of a Kubernetes cluster with extremely little administrative overhead. Starting with support for multiple storage backends also should help ensure that the dex storage interface is actually pluggable, rather than being coupled too tightly with a single implementation.
A more in depth discussion of existing storage options and how to add new ones can be found [here][storage-docs].
## Additional improvements
The rewrite came with several, miscellaneous improvements including:
* More powerful connectors. For example the GitHub connector can now query for teams.
* Combined the two APIs into a single [gRPC API][api-docs] with no complex authorization rules.
* Expanded OAuth2 capabilities such as the implicit flow.
* Simplified codebase and improved testing.
## Rethinking registration
Dex v1 performed well when it could manage users. It provided features such as registration, email invites, password resets, administrative abilities, etc. However, login flows and APIs remain tightly coupled with concepts like registration and admin users even when v1 federated to an upstream identity provider (IDP) where it likely only had read only access to the actual user database.
Many of v2's use cases focus on federation to other IPDs rather than managing users itself. Because of this, options associated with registration, such as SMTP credentials, have been removed. We hope to add registration and user management back into the project through orthogonal applications using the [gRPC API][api-docs], but in a way that doesn't impact other use cases.
## Removed features
Dex v2 lacks certain features present in v1. For the most part _we aim to add most of these features back into v2_, but in a way that installations have to _opt in_ to a feature instead of burdening every deployment with extra configuration.
Notable missing features include:
* Registration flows.
* Local user management.
* SMTP configuration and email verification.
* Several of the login connectors that have yet to be ported.
## Support for dex v1
Dex v1 will continue to live under the `github.com/coreos/dex` repo on a branch. Bug fixes and minor changes will continue to be accepted, but development of new features by the dex team will largely cease.
[k8s-api-docs]: http://kubernetes.io/docs/api/
[storage-docs]: ./storage.md
[api-docs]: ./api.md

View File

@ -1,3 +1,6 @@
Ed Rooth <ed.rooth@coreos.com> (@sym3tri)
Lucas Servén <lucas.serven@coreos.com> (@squat)
Rithu John <rithu.john@coreos.com> (@rithujohn191)
Joel Speed <Joel.speed@hotmail.co.uk> (@JoelSpeed)
Maksim Nabokikh <max.nabokih@gmail.com> (@nabokihms)
Mark Sagi-Kazar <mark.sagikazar@gmail.com> (@sagikazarmark)
Nandor Kracser <bonifaido@gmail.com> (@bonifaido)
Rithu John <rithujohn191@gmail.com> (@rithujohn191)
Stephen Augustus <foo@auggie.dev> (@justaugustus)

179
Makefile
View File

@ -1,99 +1,162 @@
OS = $(shell uname | tr A-Z a-z)
export PATH := $(abspath bin/protoc/bin/):$(abspath bin/):${PATH}
PROJ=dex
ORG_PATH=github.com/coreos
ORG_PATH=github.com/dexidp
REPO_PATH=$(ORG_PATH)/$(PROJ)
export PATH := $(PWD)/bin:$(PATH)
VERSION ?= $(shell ./scripts/git-version)
DOCKER_REPO=quay.io/coreos/dex
DOCKER_REPO=quay.io/dexidp/dex
DOCKER_IMAGE=$(DOCKER_REPO):$(VERSION)
$( shell mkdir -p bin )
$( shell mkdir -p _output/images )
$( shell mkdir -p _output/bin )
user=$(shell id -u -n)
group=$(shell id -g -n)
export GOBIN=$(PWD)/bin
LD_FLAGS="-w -X $(REPO_PATH)/version.Version=$(VERSION)"
LD_FLAGS="-w -X main.version=$(VERSION)"
build: bin/dex bin/example-app bin/grpc-client
# Dependency versions
bin/dex: check-go-version
KIND_NODE_IMAGE = "kindest/node:v1.19.11@sha256:07db187ae84b4b7de440a73886f008cf903fcf5764ba8106a9fd5243d6f32729"
KIND_TMP_DIR = "$(PWD)/bin/test/dex-kind-kubeconfig"
.PHONY: generate
generate:
@go generate $(REPO_PATH)/storage/ent/
build: generate bin/dex
bin/dex:
@mkdir -p bin/
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex
bin/example-app: check-go-version
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/example-app
examples: bin/grpc-client bin/example-app
bin/grpc-client: check-go-version
@go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/examples/grpc-client
bin/grpc-client:
@mkdir -p bin/
@cd examples/ && go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/examples/grpc-client
bin/example-app:
@mkdir -p bin/
@cd examples/ && go install -v -ldflags $(LD_FLAGS) $(REPO_PATH)/examples/example-app
.PHONY: release-binary
release-binary:
release-binary: LD_FLAGS = "-w -X main.version=$(VERSION) -extldflags \"-static\""
release-binary: generate
@go build -o /go/bin/dex -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex
@go build -o /go/bin/docker-entrypoint -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/docker-entrypoint
.PHONY: revendor
revendor:
@glide up -v
@glide-vc --use-lock-file --no-tests --only-code
docker-compose.override.yaml:
cp docker-compose.override.yaml.dist docker-compose.override.yaml
.PHONY: up
up: docker-compose.override.yaml ## Launch the development environment
@ if [ docker-compose.override.yaml -ot docker-compose.override.yaml.dist ]; then diff -u docker-compose.override.yaml docker-compose.override.yaml.dist || (echo "!!! The distributed docker-compose.override.yaml example changed. Please update your file accordingly (or at least touch it). !!!" && false); fi
docker-compose up -d
.PHONY: down
down: clear ## Destroy the development environment
docker-compose down --volumes --remove-orphans --rmi local
test:
@go test -v -i $(shell go list ./... | grep -v '/vendor/')
@go test -v $(shell go list ./... | grep -v '/vendor/')
@go test -v ./...
testrace:
@go test -v -i --race $(shell go list ./... | grep -v '/vendor/')
@go test -v --race $(shell go list ./... | grep -v '/vendor/')
@go test -v --race ./...
vet:
@go vet $(shell go list ./... | grep -v '/vendor/')
.PHONY: kind-up kind-down kind-tests
kind-up:
@mkdir -p bin/test
@kind create cluster --image ${KIND_NODE_IMAGE} --kubeconfig ${KIND_TMP_DIR}
fmt:
@go fmt $(shell go list ./... | grep -v '/vendor/')
kind-down:
@kind delete cluster
rm ${KIND_TMP_DIR}
lint:
@for package in $(shell go list ./... | grep -v '/vendor/' | grep -v '/api' | grep -v '/server/internal'); do \
golint -set_exit_status $$package $$i || exit 1; \
done
kind-tests: export DEX_KUBERNETES_CONFIG_PATH=${KIND_TMP_DIR}
kind-tests: testall
_output/bin/dex:
@./scripts/docker-build
@sudo chown $(user):$(group) _output/bin/dex
.PHONY: lint lint-fix
lint: ## Run linter
golangci-lint run
.PHONY: fix
fix: ## Fix lint violations
golangci-lint run --fix
.PHONY: docker-image
docker-image: clean-release _output/bin/dex
docker-image:
@sudo docker build -t $(DOCKER_IMAGE) .
.PHONY: proto
proto: api/api.pb.go server/internal/types.pb.go
.PHONY: verify-proto
verify-proto: proto
@./scripts/git-diff
api/api.pb.go: api/api.proto bin/protoc bin/protoc-gen-go
@./bin/protoc --go_out=plugins=grpc:. --plugin=protoc-gen-go=./bin/protoc-gen-go api/*.proto
server/internal/types.pb.go: server/internal/types.proto bin/protoc bin/protoc-gen-go
@./bin/protoc --go_out=. --plugin=protoc-gen-go=./bin/protoc-gen-go server/internal/*.proto
bin/protoc: scripts/get-protoc
@./scripts/get-protoc bin/protoc
bin/protoc-gen-go:
@go install -v $(REPO_PATH)/vendor/github.com/golang/protobuf/protoc-gen-go
.PHONY: check-go-version
check-go-version:
@./scripts/check-go-version
clean: clean-release
clean:
@rm -rf bin/
.PHONY: clean-release
clean-release:
@rm -rf _output/
testall: testrace vet fmt lint
testall: testrace
FORCE:
.PHONY: test testrace vet fmt lint testall
.PHONY: test testrace testall
.PHONY: proto
proto:
@protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. api/v2/*.proto
@protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. api/*.proto
#@cp api/v2/*.proto api/
.PHONY: proto-internal
proto-internal:
@protoc --go_out=paths=source_relative:. server/internal/*.proto
# Dependency versions
GOLANGCI_VERSION = 1.46.0
GOTESTSUM_VERSION ?= 1.7.0
PROTOC_VERSION = 3.15.6
PROTOC_GEN_GO_VERSION = 1.26.0
PROTOC_GEN_GO_GRPC_VERSION = 1.1.0
KIND_VERSION = 0.11.1
deps: bin/gotestsum bin/golangci-lint bin/protoc bin/protoc-gen-go bin/protoc-gen-go-grpc bin/kind
bin/gotestsum:
@mkdir -p bin
curl -L https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_$(shell uname | tr A-Z a-z)_amd64.tar.gz | tar -zOxf - gotestsum > ./bin/gotestsum
@chmod +x ./bin/gotestsum
bin/golangci-lint:
@mkdir -p bin
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | BINARY=golangci-lint bash -s -- v${GOLANGCI_VERSION}
bin/protoc:
@mkdir -p bin/protoc
ifeq ($(shell uname | tr A-Z a-z), darwin)
curl -L https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-osx-x86_64.zip > bin/protoc.zip
endif
ifeq ($(shell uname | tr A-Z a-z), linux)
curl -L https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip > bin/protoc.zip
endif
unzip bin/protoc.zip -d bin/protoc
rm bin/protoc.zip
bin/protoc-gen-go:
@mkdir -p bin
curl -L https://github.com/protocolbuffers/protobuf-go/releases/download/v${PROTOC_GEN_GO_VERSION}/protoc-gen-go.v${PROTOC_GEN_GO_VERSION}.$(shell uname | tr A-Z a-z).amd64.tar.gz | tar -zOxf - protoc-gen-go > ./bin/protoc-gen-go
@chmod +x ./bin/protoc-gen-go
bin/protoc-gen-go-grpc:
@mkdir -p bin
curl -L https://github.com/grpc/grpc-go/releases/download/cmd/protoc-gen-go-grpc/v${PROTOC_GEN_GO_GRPC_VERSION}/protoc-gen-go-grpc.v${PROTOC_GEN_GO_GRPC_VERSION}.$(shell uname | tr A-Z a-z).amd64.tar.gz | tar -zOxf - ./protoc-gen-go-grpc > ./bin/protoc-gen-go-grpc
@chmod +x ./bin/protoc-gen-go-grpc
bin/kind:
@mkdir -p bin
curl -L https://github.com/kubernetes-sigs/kind/releases/download/v${KIND_VERSION}/kind-$(shell uname | tr A-Z a-z)-amd64 > ./bin/kind
@chmod +x ./bin/kind

114
README.md
View File

@ -1,14 +1,14 @@
# dex - A federated OpenID Connect provider
[![Travis](https://api.travis-ci.org/coreos/dex.svg)](https://travis-ci.org/coreos/dex)
[![GoDoc](https://godoc.org/github.com/coreos/dex?status.svg)](https://godoc.org/github.com/coreos/dex)
[![Go Report Card](https://goreportcard.com/badge/github.com/coreos/dex)](https://goreportcard.com/report/github.com/coreos/dex)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/dexidp/dex/CI?style=flat-square)
[![Go Report Card](https://goreportcard.com/badge/github.com/dexidp/dex?style=flat-square)](https://goreportcard.com/report/github.com/dexidp/dex)
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/dexidp/dex)
![logo](Documentation/logos/dex-horizontal-color.png)
![logo](docs/logos/dex-horizontal-color.png)
Dex is an identity service that uses [OpenID Connect][openid-connect] to drive authentication for other apps.
Dex is NOT a user-management system, but acts as a portal to other identity providers through "connectors." This lets dex defer authentication to LDAP servers, SAML providers, or established identity providers like GitHub, Google, and Active Directory. Clients write their authentication logic once to talk to dex, then dex handles the protocols for a given backend.
Dex acts as a portal to other identity providers through ["connectors."](#connectors) This lets dex defer authentication to LDAP servers, SAML providers, or established identity providers like GitHub, Google, and Active Directory. Clients write their authentication logic once to talk to dex, then dex handles the protocols for a given backend.
## ID Tokens
@ -45,51 +45,99 @@ Because these tokens are signed by dex and [contain standard-based claims][stand
For details on how to request or validate an ID Token, see [_"Writing apps that use dex"_][using-dex].
## Kubernetes + dex
## Kubernetes and Dex
Dex's main production use is as an auth-N addon in CoreOS's enterprise Kubernetes solution, [Tectonic][tectonic]. Dex runs natively on top of any Kubernetes cluster using Third Party Resources and can drive API server authentication through the OpenID Connect plugin. Clients, such as the [Tectonic Console][tectonic-console] and `kubectl`, can act on behalf users who can login to the cluster through any identity provider dex supports.
Dex runs natively on top of any Kubernetes cluster using Custom Resource Definitions and can drive API server authentication through the OpenID Connect plugin. Clients, such as the [`kubernetes-dashboard`](https://github.com/kubernetes/dashboard) and `kubectl`, can act on behalf of users who can login to the cluster through any identity provider dex supports.
More docs for running dex as a Kubernetes authenticator can be found [here](Documentation/kubernetes.md).
* More docs for running dex as a Kubernetes authenticator can be found [here](https://dexidp.io/docs/kubernetes/).
* You can find more about companies and projects, which uses dex, [here](./ADOPTERS.md).
## Connectors
When a user logs in through dex, the user's identity is usually stored in another user-management system: a LDAP directory, a GitHub org, etc. Dex acts as a shim between a client app and the upstream identity provider. The client only needs to understand OpenID Connect to query dex, while dex implements an array of protocols for querying other user-management systems.
![](docs/img/dex-flow.png)
A "connector" is a strategy used by dex for authenticating a user against another identity provider. Dex implements connectors that target specific platforms such as GitHub, LinkedIn, and Microsoft as well as established protocols like LDAP and SAML.
Depending on the connectors limitations in protocols can prevent dex from issuing [refresh tokens][scopes] or returning [group membership][scopes] claims. For example, because SAML doesn't provide a non-interactive way to refresh assertions, if a user logs in through the SAML connector dex won't issue a refresh token to its client. Refresh token support is required for clients that require offline access, such as `kubectl`.
Dex implements the following connectors:
| Name | supports refresh tokens | supports groups claim | supports preferred_username claim | status | notes |
| ---- | ----------------------- | --------------------- | --------------------------------- | ------ | ----- |
| [LDAP](https://dexidp.io/docs/connectors/ldap/) | yes | yes | yes | stable | |
| [GitHub](https://dexidp.io/docs/connectors/github/) | yes | yes | yes | stable | |
| [SAML 2.0](https://dexidp.io/docs/connectors/saml/) | no | yes | no | stable | WARNING: Unmaintained and likely vulnerable to auth bypasses ([#1884](https://github.com/dexidp/dex/discussions/1884)) |
| [GitLab](https://dexidp.io/docs/connectors/gitlab/) | yes | yes | yes | beta | |
| [OpenID Connect](https://dexidp.io/docs/connectors/oidc/) | yes | yes | yes | beta | Includes Salesforce, Azure, etc. |
| [OAuth 2.0](https://dexidp.io/docs/connectors/oauth/) | no | yes | yes | alpha | |
| [Google](https://dexidp.io/docs/connectors/google/) | yes | yes | yes | alpha | |
| [LinkedIn](https://dexidp.io/docs/connectors/linkedin/) | yes | no | no | beta | |
| [Microsoft](https://dexidp.io/docs/connectors/microsoft/) | yes | yes | no | beta | |
| [AuthProxy](https://dexidp.io/docs/connectors/authproxy/) | no | yes | no | alpha | Authentication proxies such as Apache2 mod_auth, etc. |
| [Bitbucket Cloud](https://dexidp.io/docs/connectors/bitbucketcloud/) | yes | yes | no | alpha | |
| [OpenShift](https://dexidp.io/docs/connectors/openshift/) | no | yes | no | alpha | |
| [Atlassian Crowd](https://dexidp.io/docs/connectors/atlassiancrowd/) | yes | yes | yes * | beta | preferred_username claim must be configured through config |
| [Gitea](https://dexidp.io/docs/connectors/gitea/) | yes | no | yes | beta | |
| [OpenStack Keystone](https://dexidp.io/docs/connectors/keystone/) | yes | yes | no | alpha | |
Stable, beta, and alpha are defined as:
* Stable: well tested, in active use, and will not change in backward incompatible ways.
* Beta: tested and unlikely to change in backward incompatible ways.
* Alpha: may be untested by core maintainers and is subject to change in backward incompatible ways.
All changes or deprecations of connector features will be announced in the [release notes][release-notes].
## Documentation
* [Getting started](Documentation/getting-started.md)
* [Intro to OpenID Connect](Documentation/openid-connect.md)
* [Getting started](https://dexidp.io/docs/getting-started/)
* [Intro to OpenID Connect](https://dexidp.io/docs/openid-connect/)
* [Writing apps that use dex][using-dex]
* [What's new in v2](Documentation/v2.md)
* [Custom scopes, claims, and client features](Documentation/custom-scopes-claims-clients.md)
* [Storage options](Documentation/storage.md)
* [gRPC API](Documentation/api.md)
* [Using Kubernetes with dex](Documentation/kubernetes.md)
* Identity provider logins
* [LDAP](Documentation/ldap-connector.md)
* [GitHub](Documentation/github-connector.md)
* [GitLab](Documentation/gitlab-connector.md)
* [SAML 2.0](Documentation/saml-connector.md)
* [OpenID Connect](Documentation/oidc-connector.md) (includes Google, Salesforce, Azure, etc.)
* [What's new in v2](https://dexidp.io/docs/v2/)
* [Custom scopes, claims, and client features](https://dexidp.io/docs/custom-scopes-claims-clients/)
* [Storage options](https://dexidp.io/docs/storage/)
* [gRPC API](https://dexidp.io/docs/api/)
* [Using Kubernetes with dex](https://dexidp.io/docs/kubernetes/)
* Client libraries
* [Go][go-oidc]
## Reporting a security vulnerability
## Reporting a vulnerability
Due to their public nature, GitHub and mailing lists are NOT appropriate places for reporting vulnerabilities. Please refer to CoreOS's [security disclosure][disclosure] process when reporting issues that may be security related.
Please see our [security policy](.github/SECURITY.md) for details about reporting vulnerabilities.
## Getting help
* For feature requests and bugs, file an [issue][issues].
* For general discussion about both using and developing dex, join the [dex-dev][dex-dev] mailing list.
* For more details on dex development plans, check out the GitHub [milestones][milestones].
- For feature requests and bugs, file an [issue](https://github.com/dexidp/dex/issues).
- For general discussion about both using and developing Dex:
- join the [#dexidp](https://cloud-native.slack.com/messages/dexidp) on the CNCF Slack
- open a new [discussion](https://github.com/dexidp/dex/discussions)
- join the [dex-dev](https://groups.google.com/forum/#!forum/dex-dev) mailing list
[openid-connect]: https://openid.net/connect/
[standard-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
[using-dex]: Documentation/using-dex.md
[scopes]: https://dexidp.io/docs/custom-scopes-claims-clients/#scopes
[using-dex]: https://dexidp.io/docs/using-dex/
[jwt-io]: https://jwt.io/
[kubernetes]: http://kubernetes.io/docs/admin/authentication/#openid-connect-tokens
[aws-sts]: https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html
[tectonic]: https://tectonic.com/
[tectonic-console]: https://tectonic.com/enterprise/docs/latest/usage/index.html#tectonic-console
[go-oidc]: https://github.com/coreos/go-oidc
[issues]: https://github.com/coreos/dex/issues
[dex-dev]: https://groups.google.com/forum/#!forum/dex-dev
[milestones]: https://github.com/coreos/dex/milestones
[disclosure]: https://coreos.com/security/disclosure/
[issue-1065]: https://github.com/dexidp/dex/issues/1065
[release-notes]: https://github.com/dexidp/dex/releases
## Development
When all coding and testing is done, please run the test suite:
```shell
make testall
```
For the best developer experience, install [Nix](https://builtwithnix.org/) and [direnv](https://direnv.net/).
Alternatively, install Go and Docker manually or using a package manager. Install the rest of the dependencies by running `make deps`.
## License
The project is licensed under the [Apache License, Version 2.0](LICENSE).

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,9 @@ syntax = "proto3";
package api;
option java_package = "com.coreos.dex.api";
option go_package = "github.com/dexidp/dex/api";
// Client represents an OAuth2 client.
message Client {
string id = 1;
@ -21,7 +24,7 @@ message CreateClientReq {
// CreateClientResp returns the response from creating a client.
message CreateClientResp {
bool already_exists = 1;
Client client = 2;
Client client = 2;
}
// DeleteClientReq is a request to delete a client.
@ -30,11 +33,25 @@ message DeleteClientReq {
string id = 1;
}
// DeleteClientResp determines if the client is deleted successfully.
// DeleteClientResp determines if the client is deleted successfully.
message DeleteClientResp {
bool not_found = 1;
}
// UpdateClientReq is a request to update an existing client.
message UpdateClientReq {
string id = 1;
repeated string redirect_uris = 2;
repeated string trusted_peers = 3;
string name = 4;
string logo_url = 5;
}
// UpdateClientResp returns the response from updating a client.
message UpdateClientResp {
bool not_found = 1;
}
// TODO(ericchiang): expand this.
// Password is an email for password mapping managed by the storage.
@ -65,7 +82,7 @@ message UpdatePasswordReq {
string new_username = 3;
}
// UpdatePasswordResp returns the response from modifying an existing password.
// UpdatePasswordResp returns the response from modifying an existing password.
message UpdatePasswordResp {
bool not_found = 1;
}
@ -75,7 +92,7 @@ message DeletePasswordReq {
string email = 1;
}
// DeletePasswordResp returns the response from deleting a password.
// DeletePasswordResp returns the response from deleting a password.
message DeletePasswordResp {
bool not_found = 1;
}
@ -127,16 +144,28 @@ message RevokeRefreshReq {
string client_id = 2;
}
// RevokeRefreshResp determines if the refresh token is revoked successfully.
// RevokeRefreshResp determines if the refresh token is revoked successfully.
message RevokeRefreshResp {
// Set to true is refresh token was not found and token could not be revoked.
bool not_found = 1;
}
message VerifyPasswordReq {
string email = 1;
string password = 2;
}
message VerifyPasswordResp {
bool verified = 1;
bool not_found = 2;
}
// Dex represents the dex gRPC service.
service Dex {
// CreateClient creates a client.
rpc CreateClient(CreateClientReq) returns (CreateClientResp) {};
// UpdateClient updates an existing client
rpc UpdateClient(UpdateClientReq) returns (UpdateClientResp) {};
// DeleteClient deletes the provided client.
rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
// CreatePassword creates a password.
@ -155,4 +184,6 @@ service Dex {
//
// Note that each user-client pair can have only one refresh token at a time.
rpc RevokeRefresh(RevokeRefreshReq) returns (RevokeRefreshResp) {};
// VerifyPassword returns whether a password matches a hash for a specific email or not.
rpc VerifyPassword(VerifyPasswordReq) returns (VerifyPasswordResp) {};
}

487
api/api_grpc.pb.go Normal file
View File

@ -0,0 +1,487 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package api
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// DexClient is the client API for Dex service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type DexClient interface {
// CreateClient creates a client.
CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error)
// UpdateClient updates an existing client
UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error)
// DeleteClient deletes the provided client.
DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error)
// CreatePassword creates a password.
CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error)
// UpdatePassword modifies existing password.
UpdatePassword(ctx context.Context, in *UpdatePasswordReq, opts ...grpc.CallOption) (*UpdatePasswordResp, error)
// DeletePassword deletes the password.
DeletePassword(ctx context.Context, in *DeletePasswordReq, opts ...grpc.CallOption) (*DeletePasswordResp, error)
// ListPassword lists all password entries.
ListPasswords(ctx context.Context, in *ListPasswordReq, opts ...grpc.CallOption) (*ListPasswordResp, error)
// GetVersion returns version information of the server.
GetVersion(ctx context.Context, in *VersionReq, opts ...grpc.CallOption) (*VersionResp, error)
// ListRefresh lists all the refresh token entries for a particular user.
ListRefresh(ctx context.Context, in *ListRefreshReq, opts ...grpc.CallOption) (*ListRefreshResp, error)
// RevokeRefresh revokes the refresh token for the provided user-client pair.
//
// Note that each user-client pair can have only one refresh token at a time.
RevokeRefresh(ctx context.Context, in *RevokeRefreshReq, opts ...grpc.CallOption) (*RevokeRefreshResp, error)
// VerifyPassword returns whether a password matches a hash for a specific email or not.
VerifyPassword(ctx context.Context, in *VerifyPasswordReq, opts ...grpc.CallOption) (*VerifyPasswordResp, error)
}
type dexClient struct {
cc grpc.ClientConnInterface
}
func NewDexClient(cc grpc.ClientConnInterface) DexClient {
return &dexClient{cc}
}
func (c *dexClient) CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error) {
out := new(CreateClientResp)
err := c.cc.Invoke(ctx, "/api.Dex/CreateClient", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error) {
out := new(UpdateClientResp)
err := c.cc.Invoke(ctx, "/api.Dex/UpdateClient", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error) {
out := new(DeleteClientResp)
err := c.cc.Invoke(ctx, "/api.Dex/DeleteClient", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error) {
out := new(CreatePasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/CreatePassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) UpdatePassword(ctx context.Context, in *UpdatePasswordReq, opts ...grpc.CallOption) (*UpdatePasswordResp, error) {
out := new(UpdatePasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/UpdatePassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) DeletePassword(ctx context.Context, in *DeletePasswordReq, opts ...grpc.CallOption) (*DeletePasswordResp, error) {
out := new(DeletePasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/DeletePassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) ListPasswords(ctx context.Context, in *ListPasswordReq, opts ...grpc.CallOption) (*ListPasswordResp, error) {
out := new(ListPasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/ListPasswords", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) GetVersion(ctx context.Context, in *VersionReq, opts ...grpc.CallOption) (*VersionResp, error) {
out := new(VersionResp)
err := c.cc.Invoke(ctx, "/api.Dex/GetVersion", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) ListRefresh(ctx context.Context, in *ListRefreshReq, opts ...grpc.CallOption) (*ListRefreshResp, error) {
out := new(ListRefreshResp)
err := c.cc.Invoke(ctx, "/api.Dex/ListRefresh", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) RevokeRefresh(ctx context.Context, in *RevokeRefreshReq, opts ...grpc.CallOption) (*RevokeRefreshResp, error) {
out := new(RevokeRefreshResp)
err := c.cc.Invoke(ctx, "/api.Dex/RevokeRefresh", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) VerifyPassword(ctx context.Context, in *VerifyPasswordReq, opts ...grpc.CallOption) (*VerifyPasswordResp, error) {
out := new(VerifyPasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/VerifyPassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DexServer is the server API for Dex service.
// All implementations must embed UnimplementedDexServer
// for forward compatibility
type DexServer interface {
// CreateClient creates a client.
CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error)
// UpdateClient updates an existing client
UpdateClient(context.Context, *UpdateClientReq) (*UpdateClientResp, error)
// DeleteClient deletes the provided client.
DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error)
// CreatePassword creates a password.
CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error)
// UpdatePassword modifies existing password.
UpdatePassword(context.Context, *UpdatePasswordReq) (*UpdatePasswordResp, error)
// DeletePassword deletes the password.
DeletePassword(context.Context, *DeletePasswordReq) (*DeletePasswordResp, error)
// ListPassword lists all password entries.
ListPasswords(context.Context, *ListPasswordReq) (*ListPasswordResp, error)
// GetVersion returns version information of the server.
GetVersion(context.Context, *VersionReq) (*VersionResp, error)
// ListRefresh lists all the refresh token entries for a particular user.
ListRefresh(context.Context, *ListRefreshReq) (*ListRefreshResp, error)
// RevokeRefresh revokes the refresh token for the provided user-client pair.
//
// Note that each user-client pair can have only one refresh token at a time.
RevokeRefresh(context.Context, *RevokeRefreshReq) (*RevokeRefreshResp, error)
// VerifyPassword returns whether a password matches a hash for a specific email or not.
VerifyPassword(context.Context, *VerifyPasswordReq) (*VerifyPasswordResp, error)
mustEmbedUnimplementedDexServer()
}
// UnimplementedDexServer must be embedded to have forward compatible implementations.
type UnimplementedDexServer struct {
}
func (UnimplementedDexServer) CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateClient not implemented")
}
func (UnimplementedDexServer) UpdateClient(context.Context, *UpdateClientReq) (*UpdateClientResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateClient not implemented")
}
func (UnimplementedDexServer) DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteClient not implemented")
}
func (UnimplementedDexServer) CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreatePassword not implemented")
}
func (UnimplementedDexServer) UpdatePassword(context.Context, *UpdatePasswordReq) (*UpdatePasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdatePassword not implemented")
}
func (UnimplementedDexServer) DeletePassword(context.Context, *DeletePasswordReq) (*DeletePasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeletePassword not implemented")
}
func (UnimplementedDexServer) ListPasswords(context.Context, *ListPasswordReq) (*ListPasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListPasswords not implemented")
}
func (UnimplementedDexServer) GetVersion(context.Context, *VersionReq) (*VersionResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented")
}
func (UnimplementedDexServer) ListRefresh(context.Context, *ListRefreshReq) (*ListRefreshResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListRefresh not implemented")
}
func (UnimplementedDexServer) RevokeRefresh(context.Context, *RevokeRefreshReq) (*RevokeRefreshResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method RevokeRefresh not implemented")
}
func (UnimplementedDexServer) VerifyPassword(context.Context, *VerifyPasswordReq) (*VerifyPasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method VerifyPassword not implemented")
}
func (UnimplementedDexServer) mustEmbedUnimplementedDexServer() {}
// UnsafeDexServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DexServer will
// result in compilation errors.
type UnsafeDexServer interface {
mustEmbedUnimplementedDexServer()
}
func RegisterDexServer(s grpc.ServiceRegistrar, srv DexServer) {
s.RegisterService(&Dex_ServiceDesc, srv)
}
func _Dex_CreateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).CreateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/CreateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).CreateClient(ctx, req.(*CreateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_UpdateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).UpdateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/UpdateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).UpdateClient(ctx, req.(*UpdateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_DeleteClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).DeleteClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/DeleteClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).DeleteClient(ctx, req.(*DeleteClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_CreatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreatePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).CreatePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/CreatePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).CreatePassword(ctx, req.(*CreatePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_UpdatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdatePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).UpdatePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/UpdatePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).UpdatePassword(ctx, req.(*UpdatePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_DeletePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeletePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).DeletePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/DeletePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).DeletePassword(ctx, req.(*DeletePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_ListPasswords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListPasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).ListPasswords(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/ListPasswords",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).ListPasswords(ctx, req.(*ListPasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VersionReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).GetVersion(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/GetVersion",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).GetVersion(ctx, req.(*VersionReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_ListRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListRefreshReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).ListRefresh(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/ListRefresh",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).ListRefresh(ctx, req.(*ListRefreshReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_RevokeRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RevokeRefreshReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).RevokeRefresh(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/RevokeRefresh",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).RevokeRefresh(ctx, req.(*RevokeRefreshReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_VerifyPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VerifyPasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).VerifyPassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/VerifyPassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).VerifyPassword(ctx, req.(*VerifyPasswordReq))
}
return interceptor(ctx, in, info, handler)
}
// Dex_ServiceDesc is the grpc.ServiceDesc for Dex service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Dex_ServiceDesc = grpc.ServiceDesc{
ServiceName: "api.Dex",
HandlerType: (*DexServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateClient",
Handler: _Dex_CreateClient_Handler,
},
{
MethodName: "UpdateClient",
Handler: _Dex_UpdateClient_Handler,
},
{
MethodName: "DeleteClient",
Handler: _Dex_DeleteClient_Handler,
},
{
MethodName: "CreatePassword",
Handler: _Dex_CreatePassword_Handler,
},
{
MethodName: "UpdatePassword",
Handler: _Dex_UpdatePassword_Handler,
},
{
MethodName: "DeletePassword",
Handler: _Dex_DeletePassword_Handler,
},
{
MethodName: "ListPasswords",
Handler: _Dex_ListPasswords_Handler,
},
{
MethodName: "GetVersion",
Handler: _Dex_GetVersion_Handler,
},
{
MethodName: "ListRefresh",
Handler: _Dex_ListRefresh_Handler,
},
{
MethodName: "RevokeRefresh",
Handler: _Dex_RevokeRefresh_Handler,
},
{
MethodName: "VerifyPassword",
Handler: _Dex_VerifyPassword_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/api.proto",
}

1965
api/v2/api.pb.go Normal file

File diff suppressed because it is too large Load Diff

189
api/v2/api.proto Normal file
View File

@ -0,0 +1,189 @@
syntax = "proto3";
package api;
option java_package = "com.coreos.dex.api";
option go_package = "github.com/dexidp/dex/api/v2;api";
// Client represents an OAuth2 client.
message Client {
string id = 1;
string secret = 2;
repeated string redirect_uris = 3;
repeated string trusted_peers = 4;
bool public = 5;
string name = 6;
string logo_url = 7;
}
// CreateClientReq is a request to make a client.
message CreateClientReq {
Client client = 1;
}
// CreateClientResp returns the response from creating a client.
message CreateClientResp {
bool already_exists = 1;
Client client = 2;
}
// DeleteClientReq is a request to delete a client.
message DeleteClientReq {
// The ID of the client.
string id = 1;
}
// DeleteClientResp determines if the client is deleted successfully.
message DeleteClientResp {
bool not_found = 1;
}
// UpdateClientReq is a request to update an existing client.
message UpdateClientReq {
string id = 1;
repeated string redirect_uris = 2;
repeated string trusted_peers = 3;
string name = 4;
string logo_url = 5;
}
// UpdateClientResp returns the response from updating a client.
message UpdateClientResp {
bool not_found = 1;
}
// TODO(ericchiang): expand this.
// Password is an email for password mapping managed by the storage.
message Password {
string email = 1;
// Currently we do not accept plain text passwords. Could be an option in the future.
bytes hash = 2;
string username = 3;
string user_id = 4;
}
// CreatePasswordReq is a request to make a password.
message CreatePasswordReq {
Password password = 1;
}
// CreatePasswordResp returns the response from creating a password.
message CreatePasswordResp {
bool already_exists = 1;
}
// UpdatePasswordReq is a request to modify an existing password.
message UpdatePasswordReq {
// The email used to lookup the password. This field cannot be modified
string email = 1;
bytes new_hash = 2;
string new_username = 3;
}
// UpdatePasswordResp returns the response from modifying an existing password.
message UpdatePasswordResp {
bool not_found = 1;
}
// DeletePasswordReq is a request to delete a password.
message DeletePasswordReq {
string email = 1;
}
// DeletePasswordResp returns the response from deleting a password.
message DeletePasswordResp {
bool not_found = 1;
}
// ListPasswordReq is a request to enumerate passwords.
message ListPasswordReq {}
// ListPasswordResp returns a list of passwords.
message ListPasswordResp {
repeated Password passwords = 1;
}
// VersionReq is a request to fetch version info.
message VersionReq {}
// VersionResp holds the version info of components.
message VersionResp {
// Semantic version of the server.
string server = 1;
// Numeric version of the API. It increases everytime a new call is added to the API.
// Clients should use this info to determine if the server supports specific features.
int32 api = 2;
}
// RefreshTokenRef contains the metadata for a refresh token that is managed by the storage.
message RefreshTokenRef {
// ID of the refresh token.
string id = 1;
string client_id = 2;
int64 created_at = 5;
int64 last_used = 6;
}
// ListRefreshReq is a request to enumerate the refresh tokens of a user.
message ListRefreshReq {
// The "sub" claim returned in the ID Token.
string user_id = 1;
}
// ListRefreshResp returns a list of refresh tokens for a user.
message ListRefreshResp {
repeated RefreshTokenRef refresh_tokens = 1;
}
// RevokeRefreshReq is a request to revoke the refresh token of the user-client pair.
message RevokeRefreshReq {
// The "sub" claim returned in the ID Token.
string user_id = 1;
string client_id = 2;
}
// RevokeRefreshResp determines if the refresh token is revoked successfully.
message RevokeRefreshResp {
// Set to true is refresh token was not found and token could not be revoked.
bool not_found = 1;
}
message VerifyPasswordReq {
string email = 1;
string password = 2;
}
message VerifyPasswordResp {
bool verified = 1;
bool not_found = 2;
}
// Dex represents the dex gRPC service.
service Dex {
// CreateClient creates a client.
rpc CreateClient(CreateClientReq) returns (CreateClientResp) {};
// UpdateClient updates an existing client
rpc UpdateClient(UpdateClientReq) returns (UpdateClientResp) {};
// DeleteClient deletes the provided client.
rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
// CreatePassword creates a password.
rpc CreatePassword(CreatePasswordReq) returns (CreatePasswordResp) {};
// UpdatePassword modifies existing password.
rpc UpdatePassword(UpdatePasswordReq) returns (UpdatePasswordResp) {};
// DeletePassword deletes the password.
rpc DeletePassword(DeletePasswordReq) returns (DeletePasswordResp) {};
// ListPassword lists all password entries.
rpc ListPasswords(ListPasswordReq) returns (ListPasswordResp) {};
// GetVersion returns version information of the server.
rpc GetVersion(VersionReq) returns (VersionResp) {};
// ListRefresh lists all the refresh token entries for a particular user.
rpc ListRefresh(ListRefreshReq) returns (ListRefreshResp) {};
// RevokeRefresh revokes the refresh token for the provided user-client pair.
//
// Note that each user-client pair can have only one refresh token at a time.
rpc RevokeRefresh(RevokeRefreshReq) returns (RevokeRefreshResp) {};
// VerifyPassword returns whether a password matches a hash for a specific email or not.
rpc VerifyPassword(VerifyPasswordReq) returns (VerifyPasswordResp) {};
}

487
api/v2/api_grpc.pb.go Normal file
View File

@ -0,0 +1,487 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package api
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// DexClient is the client API for Dex service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type DexClient interface {
// CreateClient creates a client.
CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error)
// UpdateClient updates an existing client
UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error)
// DeleteClient deletes the provided client.
DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error)
// CreatePassword creates a password.
CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error)
// UpdatePassword modifies existing password.
UpdatePassword(ctx context.Context, in *UpdatePasswordReq, opts ...grpc.CallOption) (*UpdatePasswordResp, error)
// DeletePassword deletes the password.
DeletePassword(ctx context.Context, in *DeletePasswordReq, opts ...grpc.CallOption) (*DeletePasswordResp, error)
// ListPassword lists all password entries.
ListPasswords(ctx context.Context, in *ListPasswordReq, opts ...grpc.CallOption) (*ListPasswordResp, error)
// GetVersion returns version information of the server.
GetVersion(ctx context.Context, in *VersionReq, opts ...grpc.CallOption) (*VersionResp, error)
// ListRefresh lists all the refresh token entries for a particular user.
ListRefresh(ctx context.Context, in *ListRefreshReq, opts ...grpc.CallOption) (*ListRefreshResp, error)
// RevokeRefresh revokes the refresh token for the provided user-client pair.
//
// Note that each user-client pair can have only one refresh token at a time.
RevokeRefresh(ctx context.Context, in *RevokeRefreshReq, opts ...grpc.CallOption) (*RevokeRefreshResp, error)
// VerifyPassword returns whether a password matches a hash for a specific email or not.
VerifyPassword(ctx context.Context, in *VerifyPasswordReq, opts ...grpc.CallOption) (*VerifyPasswordResp, error)
}
type dexClient struct {
cc grpc.ClientConnInterface
}
func NewDexClient(cc grpc.ClientConnInterface) DexClient {
return &dexClient{cc}
}
func (c *dexClient) CreateClient(ctx context.Context, in *CreateClientReq, opts ...grpc.CallOption) (*CreateClientResp, error) {
out := new(CreateClientResp)
err := c.cc.Invoke(ctx, "/api.Dex/CreateClient", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) UpdateClient(ctx context.Context, in *UpdateClientReq, opts ...grpc.CallOption) (*UpdateClientResp, error) {
out := new(UpdateClientResp)
err := c.cc.Invoke(ctx, "/api.Dex/UpdateClient", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) DeleteClient(ctx context.Context, in *DeleteClientReq, opts ...grpc.CallOption) (*DeleteClientResp, error) {
out := new(DeleteClientResp)
err := c.cc.Invoke(ctx, "/api.Dex/DeleteClient", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) CreatePassword(ctx context.Context, in *CreatePasswordReq, opts ...grpc.CallOption) (*CreatePasswordResp, error) {
out := new(CreatePasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/CreatePassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) UpdatePassword(ctx context.Context, in *UpdatePasswordReq, opts ...grpc.CallOption) (*UpdatePasswordResp, error) {
out := new(UpdatePasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/UpdatePassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) DeletePassword(ctx context.Context, in *DeletePasswordReq, opts ...grpc.CallOption) (*DeletePasswordResp, error) {
out := new(DeletePasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/DeletePassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) ListPasswords(ctx context.Context, in *ListPasswordReq, opts ...grpc.CallOption) (*ListPasswordResp, error) {
out := new(ListPasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/ListPasswords", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) GetVersion(ctx context.Context, in *VersionReq, opts ...grpc.CallOption) (*VersionResp, error) {
out := new(VersionResp)
err := c.cc.Invoke(ctx, "/api.Dex/GetVersion", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) ListRefresh(ctx context.Context, in *ListRefreshReq, opts ...grpc.CallOption) (*ListRefreshResp, error) {
out := new(ListRefreshResp)
err := c.cc.Invoke(ctx, "/api.Dex/ListRefresh", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) RevokeRefresh(ctx context.Context, in *RevokeRefreshReq, opts ...grpc.CallOption) (*RevokeRefreshResp, error) {
out := new(RevokeRefreshResp)
err := c.cc.Invoke(ctx, "/api.Dex/RevokeRefresh", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *dexClient) VerifyPassword(ctx context.Context, in *VerifyPasswordReq, opts ...grpc.CallOption) (*VerifyPasswordResp, error) {
out := new(VerifyPasswordResp)
err := c.cc.Invoke(ctx, "/api.Dex/VerifyPassword", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DexServer is the server API for Dex service.
// All implementations must embed UnimplementedDexServer
// for forward compatibility
type DexServer interface {
// CreateClient creates a client.
CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error)
// UpdateClient updates an existing client
UpdateClient(context.Context, *UpdateClientReq) (*UpdateClientResp, error)
// DeleteClient deletes the provided client.
DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error)
// CreatePassword creates a password.
CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error)
// UpdatePassword modifies existing password.
UpdatePassword(context.Context, *UpdatePasswordReq) (*UpdatePasswordResp, error)
// DeletePassword deletes the password.
DeletePassword(context.Context, *DeletePasswordReq) (*DeletePasswordResp, error)
// ListPassword lists all password entries.
ListPasswords(context.Context, *ListPasswordReq) (*ListPasswordResp, error)
// GetVersion returns version information of the server.
GetVersion(context.Context, *VersionReq) (*VersionResp, error)
// ListRefresh lists all the refresh token entries for a particular user.
ListRefresh(context.Context, *ListRefreshReq) (*ListRefreshResp, error)
// RevokeRefresh revokes the refresh token for the provided user-client pair.
//
// Note that each user-client pair can have only one refresh token at a time.
RevokeRefresh(context.Context, *RevokeRefreshReq) (*RevokeRefreshResp, error)
// VerifyPassword returns whether a password matches a hash for a specific email or not.
VerifyPassword(context.Context, *VerifyPasswordReq) (*VerifyPasswordResp, error)
mustEmbedUnimplementedDexServer()
}
// UnimplementedDexServer must be embedded to have forward compatible implementations.
type UnimplementedDexServer struct {
}
func (UnimplementedDexServer) CreateClient(context.Context, *CreateClientReq) (*CreateClientResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateClient not implemented")
}
func (UnimplementedDexServer) UpdateClient(context.Context, *UpdateClientReq) (*UpdateClientResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateClient not implemented")
}
func (UnimplementedDexServer) DeleteClient(context.Context, *DeleteClientReq) (*DeleteClientResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteClient not implemented")
}
func (UnimplementedDexServer) CreatePassword(context.Context, *CreatePasswordReq) (*CreatePasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreatePassword not implemented")
}
func (UnimplementedDexServer) UpdatePassword(context.Context, *UpdatePasswordReq) (*UpdatePasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdatePassword not implemented")
}
func (UnimplementedDexServer) DeletePassword(context.Context, *DeletePasswordReq) (*DeletePasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeletePassword not implemented")
}
func (UnimplementedDexServer) ListPasswords(context.Context, *ListPasswordReq) (*ListPasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListPasswords not implemented")
}
func (UnimplementedDexServer) GetVersion(context.Context, *VersionReq) (*VersionResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented")
}
func (UnimplementedDexServer) ListRefresh(context.Context, *ListRefreshReq) (*ListRefreshResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListRefresh not implemented")
}
func (UnimplementedDexServer) RevokeRefresh(context.Context, *RevokeRefreshReq) (*RevokeRefreshResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method RevokeRefresh not implemented")
}
func (UnimplementedDexServer) VerifyPassword(context.Context, *VerifyPasswordReq) (*VerifyPasswordResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method VerifyPassword not implemented")
}
func (UnimplementedDexServer) mustEmbedUnimplementedDexServer() {}
// UnsafeDexServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DexServer will
// result in compilation errors.
type UnsafeDexServer interface {
mustEmbedUnimplementedDexServer()
}
func RegisterDexServer(s grpc.ServiceRegistrar, srv DexServer) {
s.RegisterService(&Dex_ServiceDesc, srv)
}
func _Dex_CreateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).CreateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/CreateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).CreateClient(ctx, req.(*CreateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_UpdateClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).UpdateClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/UpdateClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).UpdateClient(ctx, req.(*UpdateClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_DeleteClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteClientReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).DeleteClient(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/DeleteClient",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).DeleteClient(ctx, req.(*DeleteClientReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_CreatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreatePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).CreatePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/CreatePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).CreatePassword(ctx, req.(*CreatePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_UpdatePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdatePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).UpdatePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/UpdatePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).UpdatePassword(ctx, req.(*UpdatePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_DeletePassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeletePasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).DeletePassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/DeletePassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).DeletePassword(ctx, req.(*DeletePasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_ListPasswords_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListPasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).ListPasswords(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/ListPasswords",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).ListPasswords(ctx, req.(*ListPasswordReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VersionReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).GetVersion(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/GetVersion",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).GetVersion(ctx, req.(*VersionReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_ListRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListRefreshReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).ListRefresh(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/ListRefresh",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).ListRefresh(ctx, req.(*ListRefreshReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_RevokeRefresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RevokeRefreshReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).RevokeRefresh(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/RevokeRefresh",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).RevokeRefresh(ctx, req.(*RevokeRefreshReq))
}
return interceptor(ctx, in, info, handler)
}
func _Dex_VerifyPassword_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VerifyPasswordReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DexServer).VerifyPassword(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.Dex/VerifyPassword",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DexServer).VerifyPassword(ctx, req.(*VerifyPasswordReq))
}
return interceptor(ctx, in, info, handler)
}
// Dex_ServiceDesc is the grpc.ServiceDesc for Dex service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Dex_ServiceDesc = grpc.ServiceDesc{
ServiceName: "api.Dex",
HandlerType: (*DexServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateClient",
Handler: _Dex_CreateClient_Handler,
},
{
MethodName: "UpdateClient",
Handler: _Dex_UpdateClient_Handler,
},
{
MethodName: "DeleteClient",
Handler: _Dex_DeleteClient_Handler,
},
{
MethodName: "CreatePassword",
Handler: _Dex_CreatePassword_Handler,
},
{
MethodName: "UpdatePassword",
Handler: _Dex_UpdatePassword_Handler,
},
{
MethodName: "DeletePassword",
Handler: _Dex_DeletePassword_Handler,
},
{
MethodName: "ListPasswords",
Handler: _Dex_ListPasswords_Handler,
},
{
MethodName: "GetVersion",
Handler: _Dex_GetVersion_Handler,
},
{
MethodName: "ListRefresh",
Handler: _Dex_ListRefresh_Handler,
},
{
MethodName: "RevokeRefresh",
Handler: _Dex_RevokeRefresh_Handler,
},
{
MethodName: "VerifyPassword",
Handler: _Dex_VerifyPassword_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v2/api.proto",
}

16
api/v2/go.mod Normal file
View File

@ -0,0 +1,16 @@
module github.com/dexidp/dex/api/v2
go 1.17
require (
google.golang.org/grpc v1.47.0
google.golang.org/protobuf v1.28.0
)
require (
github.com/golang/protobuf v1.5.2 // indirect
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 // indirect
)

141
api/v2/go.sum Normal file
View File

@ -0,0 +1,141 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 h1:qRu95HZ148xXw+XeZ3dvqe85PxH4X8+jIo0iRPKcEnM=
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -5,26 +5,31 @@ import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
"github.com/coreos/dex/server"
"github.com/coreos/dex/storage"
"github.com/coreos/dex/storage/kubernetes"
"github.com/coreos/dex/storage/memory"
"github.com/coreos/dex/storage/sql"
"github.com/dexidp/dex/pkg/log"
"github.com/dexidp/dex/server"
"github.com/dexidp/dex/storage"
"github.com/dexidp/dex/storage/ent"
"github.com/dexidp/dex/storage/etcd"
"github.com/dexidp/dex/storage/kubernetes"
"github.com/dexidp/dex/storage/memory"
"github.com/dexidp/dex/storage/sql"
)
// Config is the config format for the main application.
type Config struct {
Issuer string `json:"issuer"`
Storage Storage `json:"storage"`
Web Web `json:"web"`
OAuth2 OAuth2 `json:"oauth2"`
GRPC GRPC `json:"grpc"`
Expiry Expiry `json:"expiry"`
Logger Logger `json:"logger"`
Issuer string `json:"issuer"`
Storage Storage `json:"storage"`
Web Web `json:"web"`
Telemetry Telemetry `json:"telemetry"`
OAuth2 OAuth2 `json:"oauth2"`
GRPC GRPC `json:"grpc"`
Expiry Expiry `json:"expiry"`
Logger Logger `json:"logger"`
Frontend server.WebConfig `json:"frontend"`
@ -46,14 +51,47 @@ type Config struct {
StaticPasswords []password `json:"staticPasswords"`
}
// Validate the configuration
func (c Config) Validate() error {
// Fast checks. Perform these first for a more responsive CLI.
checks := []struct {
bad bool
errMsg string
}{
{c.Issuer == "", "no issuer specified in config file"},
{!c.EnablePasswordDB && len(c.StaticPasswords) != 0, "cannot specify static passwords without enabling password db"},
{c.Storage.Config == nil, "no storage supplied in config file"},
{c.Web.HTTP == "" && c.Web.HTTPS == "", "must supply a HTTP/HTTPS address to listen on"},
{c.Web.HTTPS != "" && c.Web.TLSCert == "", "no cert specified for HTTPS"},
{c.Web.HTTPS != "" && c.Web.TLSKey == "", "no private key specified for HTTPS"},
{c.GRPC.TLSCert != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{c.GRPC.TLSKey != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{(c.GRPC.TLSCert == "") != (c.GRPC.TLSKey == ""), "must specific both a gRPC TLS cert and key"},
{c.GRPC.TLSCert == "" && c.GRPC.TLSClientCA != "", "cannot specify gRPC TLS client CA without a gRPC TLS cert"},
}
var checkErrors []string
for _, check := range checks {
if check.bad {
checkErrors = append(checkErrors, check.errMsg)
}
}
if len(checkErrors) != 0 {
return fmt.Errorf("invalid Config:\n\t-\t%s", strings.Join(checkErrors, "\n\t-\t"))
}
return nil
}
type password storage.Password
func (p *password) UnmarshalJSON(b []byte) error {
var data struct {
Email string `json:"email"`
Username string `json:"username"`
UserID string `json:"userID"`
Hash string `json:"hash"`
Email string `json:"email"`
Username string `json:"username"`
UserID string `json:"userID"`
Hash string `json:"hash"`
HashFromEnv string `json:"hashFromEnv"`
}
if err := json.Unmarshal(b, &data); err != nil {
return err
@ -63,6 +101,9 @@ func (p *password) UnmarshalJSON(b []byte) error {
Username: data.Username,
UserID: data.UserID,
})
if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 {
data.Hash = os.Getenv(data.HashFromEnv)
}
if len(data.Hash) == 0 {
return fmt.Errorf("no password hash provided")
}
@ -92,6 +133,10 @@ type OAuth2 struct {
// If specified, do not prompt the user to approve client authorization. The
// act of logging in implies authorization.
SkipApprovalScreen bool `json:"skipApprovalScreen"`
// If specified, show the connector selection screen even if there's only one
AlwaysShowLoginScreen bool `json:"alwaysShowLoginScreen"`
// This is the connector that can be used for password grant
PasswordConnector string `json:"passwordConnector"`
}
// Web is the config format for the HTTP server.
@ -103,6 +148,13 @@ type Web struct {
AllowedOrigins []string `json:"allowedOrigins"`
}
// Telemetry is the config format for telemetry including the HTTP server config.
type Telemetry struct {
HTTP string `json:"http"`
// EnableProfiling makes profiling endpoints available via web interface host:port/debug/pprof/
EnableProfiling bool `json:"enableProfiling"`
}
// GRPC is the config for the gRPC API.
type GRPC struct {
// The port to listen on.
@ -110,6 +162,7 @@ type GRPC struct {
TLSCert string `json:"tlsCert"`
TLSKey string `json:"tlsKey"`
TLSClientCA string `json:"tlsClientCA"`
Reflection bool `json:"reflection"`
}
// Storage holds app's storage configuration.
@ -120,14 +173,52 @@ type Storage struct {
// StorageConfig is a configuration that can create a storage.
type StorageConfig interface {
Open(logrus.FieldLogger) (storage.Storage, error)
Open(logger log.Logger) (storage.Storage, error)
}
var (
_ StorageConfig = (*etcd.Etcd)(nil)
_ StorageConfig = (*kubernetes.Config)(nil)
_ StorageConfig = (*memory.Config)(nil)
_ StorageConfig = (*sql.SQLite3)(nil)
_ StorageConfig = (*sql.Postgres)(nil)
_ StorageConfig = (*sql.MySQL)(nil)
_ StorageConfig = (*ent.SQLite3)(nil)
_ StorageConfig = (*ent.Postgres)(nil)
_ StorageConfig = (*ent.MySQL)(nil)
)
func getORMBasedSQLStorage(normal, entBased StorageConfig) func() StorageConfig {
return func() StorageConfig {
switch os.Getenv("DEX_ENT_ENABLED") {
case "true", "yes":
return entBased
default:
return normal
}
}
}
var storages = map[string]func() StorageConfig{
"etcd": func() StorageConfig { return new(etcd.Etcd) },
"kubernetes": func() StorageConfig { return new(kubernetes.Config) },
"memory": func() StorageConfig { return new(memory.Config) },
"sqlite3": func() StorageConfig { return new(sql.SQLite3) },
"postgres": func() StorageConfig { return new(sql.Postgres) },
"sqlite3": getORMBasedSQLStorage(&sql.SQLite3{}, &ent.SQLite3{}),
"postgres": getORMBasedSQLStorage(&sql.Postgres{}, &ent.Postgres{}),
"mysql": getORMBasedSQLStorage(&sql.MySQL{}, &ent.MySQL{}),
}
// isExpandEnvEnabled returns if os.ExpandEnv should be used for each storage and connector config.
// Disabling this feature avoids surprises e.g. if the LDAP bind password contains a dollar character.
// Returns false if the env variable "DEX_EXPAND_ENV" is a falsy string, e.g. "false".
// Returns true if the env variable is unset or a truthy string, e.g. "true", or can't be parsed as bool.
func isExpandEnvEnabled() bool {
enabled, err := strconv.ParseBool(os.Getenv("DEX_EXPAND_ENV"))
if err != nil {
// Unset, empty string or can't be parsed as bool: Default = true.
return true
}
return enabled
}
// UnmarshalJSON allows Storage to implement the unmarshaler interface to
@ -147,7 +238,11 @@ func (s *Storage) UnmarshalJSON(b []byte) error {
storageConfig := f()
if len(store.Config) != 0 {
data := []byte(os.ExpandEnv(string(store.Config)))
data := []byte(store.Config)
if isExpandEnvEnabled() {
// Caution, we're expanding in the raw JSON/YAML source. This may not be what the admin expects.
data = []byte(os.ExpandEnv(string(store.Config)))
}
if err := json.Unmarshal(data, storageConfig); err != nil {
return fmt.Errorf("parse storage config: %v", err)
}
@ -189,7 +284,11 @@ func (c *Connector) UnmarshalJSON(b []byte) error {
connConfig := f()
if len(conn.Config) != 0 {
data := []byte(os.ExpandEnv(string(conn.Config)))
data := []byte(conn.Config)
if isExpandEnvEnabled() {
// Caution, we're expanding in the raw JSON/YAML source. This may not be what the admin expects.
data = []byte(os.ExpandEnv(string(conn.Config)))
}
if err := json.Unmarshal(data, connConfig); err != nil {
return fmt.Errorf("parse connector config: %v", err)
}
@ -225,6 +324,15 @@ type Expiry struct {
// IdTokens defines the duration of time for which the IdTokens will be valid.
IDTokens string `json:"idTokens"`
// AuthRequests defines the duration of time for which the AuthRequests will be valid.
AuthRequests string `json:"authRequests"`
// DeviceRequests defines the duration of time for which the DeviceRequests will be valid.
DeviceRequests string `json:"deviceRequests"`
// RefreshTokens defines refresh tokens expiry policy
RefreshTokens RefreshToken `json:"refreshTokens"`
}
// Logger holds configuration required to customize logging for dex.
@ -235,3 +343,10 @@ type Logger struct {
// Format specifies the format to be used for logging.
Format string `json:"format"`
}
type RefreshToken struct {
DisableRotation bool `json:"disableRotation"`
ReuseInterval string `json:"reuseInterval"`
AbsoluteLifetime string `json:"absoluteLifetime"`
ValidIfNotUsedFor string `json:"validIfNotUsedFor"`
}

View File

@ -1,28 +1,83 @@
package main
import (
"os"
"testing"
"github.com/coreos/dex/connector/mock"
"github.com/coreos/dex/connector/oidc"
"github.com/coreos/dex/storage"
"github.com/coreos/dex/storage/sql"
"github.com/ghodss/yaml"
"github.com/kylelemons/godebug/pretty"
"github.com/dexidp/dex/connector/mock"
"github.com/dexidp/dex/connector/oidc"
"github.com/dexidp/dex/server"
"github.com/dexidp/dex/storage"
"github.com/dexidp/dex/storage/sql"
)
var _ = yaml.YAMLToJSON
func TestValidConfiguration(t *testing.T) {
configuration := Config{
Issuer: "http://127.0.0.1:5556/dex",
Storage: Storage{
Type: "sqlite3",
Config: &sql.SQLite3{
File: "examples/dex.db",
},
},
Web: Web{
HTTP: "127.0.0.1:5556",
},
StaticConnectors: []Connector{
{
Type: "mockCallback",
ID: "mock",
Name: "Example",
Config: &mock.CallbackConfig{},
},
},
}
if err := configuration.Validate(); err != nil {
t.Fatalf("this configuration should have been valid: %v", err)
}
}
func TestInvalidConfiguration(t *testing.T) {
configuration := Config{}
err := configuration.Validate()
if err == nil {
t.Fatal("this configuration should be invalid")
}
got := err.Error()
wanted := `invalid Config:
- no issuer specified in config file
- no storage supplied in config file
- must supply a HTTP/HTTPS address to listen on`
if got != wanted {
t.Fatalf("Expected error message to be %q, got %q", wanted, got)
}
}
func TestUnmarshalConfig(t *testing.T) {
rawConfig := []byte(`
issuer: http://127.0.0.1:5556/dex
storage:
type: sqlite3
type: postgres
config:
file: examples/dex.db
host: 10.0.0.1
port: 65432
maxOpenConns: 5
maxIdleConns: 3
connMaxLifetime: 30
connectionTimeout: 3
web:
http: 127.0.0.1:5556
frontend:
dir: ./web
extra:
foo: bar
staticClients:
- id: example-app
redirectURIs:
@ -30,6 +85,9 @@ staticClients:
name: 'Example App'
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
oauth2:
alwaysShowLoginScreen: true
connectors:
- type: mockCallback
id: mock
@ -50,15 +108,17 @@ staticPasswords:
hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
- email: "foo@example.com"
- email: "foo@example.com"
# base64'd value of the same bcrypt hash above. We want to be able to parse both of these
hash: "JDJhJDEwJDMzRU1UMGNWWVZsUHk2V0FNQ0xzY2VMWWpXaHVIcGJ6NXl1Wnh1L0dBRmowM0o5THl0anV5"
username: "foo"
userID: "41331323-6f44-45e6-b3b9-2c4b60c02be5"
expiry:
signingKeys: "6h"
idTokens: "24h"
signingKeys: "7h"
idTokens: "25h"
authRequests: "25h"
deviceRequests: "10m"
logger:
level: "debug"
@ -68,14 +128,27 @@ logger:
want := Config{
Issuer: "http://127.0.0.1:5556/dex",
Storage: Storage{
Type: "sqlite3",
Config: &sql.SQLite3{
File: "examples/dex.db",
Type: "postgres",
Config: &sql.Postgres{
NetworkDB: sql.NetworkDB{
Host: "10.0.0.1",
Port: 65432,
MaxOpenConns: 5,
MaxIdleConns: 3,
ConnMaxLifetime: 30,
ConnectionTimeout: 3,
},
},
},
Web: Web{
HTTP: "127.0.0.1:5556",
},
Frontend: server.WebConfig{
Dir: "./web",
Extra: map[string]string{
"foo": "bar",
},
},
StaticClients: []storage.Client{
{
ID: "example-app",
@ -86,6 +159,9 @@ logger:
},
},
},
OAuth2: OAuth2{
AlwaysShowLoginScreen: true,
},
StaticConnectors: []Connector{
{
Type: "mockCallback",
@ -121,8 +197,217 @@ logger:
},
},
Expiry: Expiry{
SigningKeys: "6h",
IDTokens: "24h",
SigningKeys: "7h",
IDTokens: "25h",
AuthRequests: "25h",
DeviceRequests: "10m",
},
Logger: Logger{
Level: "debug",
Format: "json",
},
}
var c Config
if err := yaml.Unmarshal(rawConfig, &c); err != nil {
t.Fatalf("failed to decode config: %v", err)
}
if diff := pretty.Compare(c, want); diff != "" {
t.Errorf("got!=want: %s", diff)
}
}
func TestUnmarshalConfigWithEnvNoExpand(t *testing.T) {
// If the env variable DEX_EXPAND_ENV is set and has a "falsy" value, os.ExpandEnv is disabled.
// ParseBool: "It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False."
checkUnmarshalConfigWithEnv(t, "0", false)
checkUnmarshalConfigWithEnv(t, "f", false)
checkUnmarshalConfigWithEnv(t, "F", false)
checkUnmarshalConfigWithEnv(t, "FALSE", false)
checkUnmarshalConfigWithEnv(t, "false", false)
checkUnmarshalConfigWithEnv(t, "False", false)
os.Unsetenv("DEX_EXPAND_ENV")
}
func TestUnmarshalConfigWithEnvExpand(t *testing.T) {
// If the env variable DEX_EXPAND_ENV is unset or has a "truthy" or unknown value, os.ExpandEnv is enabled.
// ParseBool: "It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False."
checkUnmarshalConfigWithEnv(t, "1", true)
checkUnmarshalConfigWithEnv(t, "t", true)
checkUnmarshalConfigWithEnv(t, "T", true)
checkUnmarshalConfigWithEnv(t, "TRUE", true)
checkUnmarshalConfigWithEnv(t, "true", true)
checkUnmarshalConfigWithEnv(t, "True", true)
// Values that can't be parsed as bool:
checkUnmarshalConfigWithEnv(t, "UNSET", true)
checkUnmarshalConfigWithEnv(t, "", true)
checkUnmarshalConfigWithEnv(t, "whatever - true is default", true)
os.Unsetenv("DEX_EXPAND_ENV")
}
func checkUnmarshalConfigWithEnv(t *testing.T, dexExpandEnv string, wantExpandEnv bool) {
// For hashFromEnv:
os.Setenv("DEX_FOO_USER_PASSWORD", "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy")
// For os.ExpandEnv ($VAR -> value_of_VAR):
os.Setenv("DEX_FOO_POSTGRES_HOST", "10.0.0.1")
os.Setenv("DEX_FOO_OIDC_CLIENT_SECRET", "bar")
if dexExpandEnv != "UNSET" {
os.Setenv("DEX_EXPAND_ENV", dexExpandEnv)
} else {
os.Unsetenv("DEX_EXPAND_ENV")
}
rawConfig := []byte(`
issuer: http://127.0.0.1:5556/dex
storage:
type: postgres
config:
# Env variables are expanded in raw YAML source.
# Single quotes work fine, as long as the env variable doesn't contain any.
host: '$DEX_FOO_POSTGRES_HOST'
port: 65432
maxOpenConns: 5
maxIdleConns: 3
connMaxLifetime: 30
connectionTimeout: 3
web:
http: 127.0.0.1:5556
frontend:
dir: ./web
extra:
foo: bar
staticClients:
- id: example-app
redirectURIs:
- 'http://127.0.0.1:5555/callback'
name: 'Example App'
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
oauth2:
alwaysShowLoginScreen: true
connectors:
- type: mockCallback
id: mock
name: Example
- type: oidc
id: google
name: Google
config:
issuer: https://accounts.google.com
clientID: foo
# Env variables are expanded in raw YAML source.
# Single quotes work fine, as long as the env variable doesn't contain any.
clientSecret: '$DEX_FOO_OIDC_CLIENT_SECRET'
redirectURI: http://127.0.0.1:5556/dex/callback/google
enablePasswordDB: true
staticPasswords:
- email: "admin@example.com"
# bcrypt hash of the string "password"
hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
- email: "foo@example.com"
hashFromEnv: "DEX_FOO_USER_PASSWORD"
username: "foo"
userID: "41331323-6f44-45e6-b3b9-2c4b60c02be5"
expiry:
signingKeys: "7h"
idTokens: "25h"
authRequests: "25h"
logger:
level: "debug"
format: "json"
`)
// This is not a valid hostname. It's only used to check whether os.ExpandEnv was applied or not.
wantPostgresHost := "$DEX_FOO_POSTGRES_HOST"
wantOidcClientSecret := "$DEX_FOO_OIDC_CLIENT_SECRET"
if wantExpandEnv {
wantPostgresHost = "10.0.0.1"
wantOidcClientSecret = "bar"
}
want := Config{
Issuer: "http://127.0.0.1:5556/dex",
Storage: Storage{
Type: "postgres",
Config: &sql.Postgres{
NetworkDB: sql.NetworkDB{
Host: wantPostgresHost,
Port: 65432,
MaxOpenConns: 5,
MaxIdleConns: 3,
ConnMaxLifetime: 30,
ConnectionTimeout: 3,
},
},
},
Web: Web{
HTTP: "127.0.0.1:5556",
},
Frontend: server.WebConfig{
Dir: "./web",
Extra: map[string]string{
"foo": "bar",
},
},
StaticClients: []storage.Client{
{
ID: "example-app",
Secret: "ZXhhbXBsZS1hcHAtc2VjcmV0",
Name: "Example App",
RedirectURIs: []string{
"http://127.0.0.1:5555/callback",
},
},
},
OAuth2: OAuth2{
AlwaysShowLoginScreen: true,
},
StaticConnectors: []Connector{
{
Type: "mockCallback",
ID: "mock",
Name: "Example",
Config: &mock.CallbackConfig{},
},
{
Type: "oidc",
ID: "google",
Name: "Google",
Config: &oidc.Config{
Issuer: "https://accounts.google.com",
ClientID: "foo",
ClientSecret: wantOidcClientSecret,
RedirectURI: "http://127.0.0.1:5556/dex/callback/google",
},
},
},
EnablePasswordDB: true,
StaticPasswords: []password{
{
Email: "admin@example.com",
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
Username: "admin",
UserID: "08a8684b-db88-4b73-90a9-3cd1661f5466",
},
{
Email: "foo@example.com",
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
Username: "foo",
UserID: "41331323-6f44-45e6-b3b9-2c4b60c02be5",
},
},
Expiry: Expiry{
SigningKeys: "7h",
IDTokens: "25h",
AuthRequests: "25h",
},
Logger: Logger{
Level: "debug",
@ -137,5 +422,4 @@ logger:
if diff := pretty.Compare(c, want); diff != "" {
t.Errorf("got!=want: %s", diff)
}
}

View File

@ -6,51 +6,78 @@ import (
"crypto/x509"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/pprof"
"os"
"runtime"
"strings"
"syscall"
"time"
gosundheit "github.com/AppsFlyer/go-sundheit"
"github.com/AppsFlyer/go-sundheit/checks"
gosundheithttp "github.com/AppsFlyer/go-sundheit/http"
"github.com/ghodss/yaml"
grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/oklog/run"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/reflection"
"github.com/coreos/dex/api"
"github.com/coreos/dex/server"
"github.com/coreos/dex/storage"
"github.com/dexidp/dex/api/v2"
"github.com/dexidp/dex/pkg/log"
"github.com/dexidp/dex/server"
"github.com/dexidp/dex/storage"
)
func commandServe() *cobra.Command {
return &cobra.Command{
Use: "serve [ config file ]",
Short: "Connect to the storage and begin serving requests.",
Long: ``,
Example: "dex serve config.yaml",
Run: func(cmd *cobra.Command, args []string) {
if err := serve(cmd, args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
},
}
type serveOptions struct {
// Config file path
config string
// Flags
webHTTPAddr string
webHTTPSAddr string
telemetryAddr string
grpcAddr string
}
func serve(cmd *cobra.Command, args []string) error {
switch len(args) {
default:
return errors.New("surplus arguments")
case 0:
// TODO(ericchiang): Consider having a default config file location.
return errors.New("no arguments provided")
case 1:
func commandServe() *cobra.Command {
options := serveOptions{}
cmd := &cobra.Command{
Use: "serve [flags] [config file]",
Short: "Launch Dex",
Example: "dex serve config.yaml",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
cmd.SilenceErrors = true
options.config = args[0]
return runServe(options)
},
}
configFile := args[0]
configData, err := ioutil.ReadFile(configFile)
flags := cmd.Flags()
flags.StringVar(&options.webHTTPAddr, "web-http-addr", "", "Web HTTP address")
flags.StringVar(&options.webHTTPSAddr, "web-https-addr", "", "Web HTTPS address")
flags.StringVar(&options.telemetryAddr, "telemetry-addr", "", "Telemetry address")
flags.StringVar(&options.grpcAddr, "grpc-addr", "", "gRPC API address")
return cmd
}
func runServe(options serveOptions) error {
configFile := options.config
configData, err := os.ReadFile(configFile)
if err != nil {
return fmt.Errorf("failed to read config file %s: %v", configFile, err)
}
@ -60,82 +87,130 @@ func serve(cmd *cobra.Command, args []string) error {
return fmt.Errorf("error parse config file %s: %v", configFile, err)
}
applyConfigOverrides(options, &c)
logger, err := newLogger(c.Logger.Level, c.Logger.Format)
if err != nil {
return fmt.Errorf("invalid config: %v", err)
}
logger.Infof(
"Dex Version: %s, Go Version: %s, Go OS/ARCH: %s %s",
version,
runtime.Version(),
runtime.GOOS,
runtime.GOARCH,
)
if c.Logger.Level != "" {
logger.Infof("config using log level: %s", c.Logger.Level)
}
// Fast checks. Perform these first for a more responsive CLI.
checks := []struct {
bad bool
errMsg string
}{
{c.Issuer == "", "no issuer specified in config file"},
{!c.EnablePasswordDB && len(c.StaticPasswords) != 0, "cannot specify static passwords without enabling password db"},
{c.Storage.Config == nil, "no storage suppied in config file"},
{c.Web.HTTP == "" && c.Web.HTTPS == "", "must supply a HTTP/HTTPS address to listen on"},
{c.Web.HTTPS != "" && c.Web.TLSCert == "", "no cert specified for HTTPS"},
{c.Web.HTTPS != "" && c.Web.TLSKey == "", "no private key specified for HTTPS"},
{c.GRPC.TLSCert != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{c.GRPC.TLSKey != "" && c.GRPC.Addr == "", "no address specified for gRPC"},
{(c.GRPC.TLSCert == "") != (c.GRPC.TLSKey == ""), "must specific both a gRPC TLS cert and key"},
{c.GRPC.TLSCert == "" && c.GRPC.TLSClientCA != "", "cannot specify gRPC TLS client CA without a gRPC TLS cert"},
}
for _, check := range checks {
if check.bad {
return fmt.Errorf("invalid config: %s", check.errMsg)
}
if err := c.Validate(); err != nil {
return err
}
logger.Infof("config issuer: %s", c.Issuer)
var grpcOptions []grpc.ServerOption
if c.GRPC.TLSCert != "" {
if c.GRPC.TLSClientCA != "" {
// Parse certificates from certificate file and key file for server.
cert, err := tls.LoadX509KeyPair(c.GRPC.TLSCert, c.GRPC.TLSKey)
if err != nil {
return fmt.Errorf("invalid config: error parsing gRPC certificate file: %v", err)
}
prometheusRegistry := prometheus.NewRegistry()
err = prometheusRegistry.Register(collectors.NewGoCollector())
if err != nil {
return fmt.Errorf("failed to register Go runtime metrics: %v", err)
}
err = prometheusRegistry.Register(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
if err != nil {
return fmt.Errorf("failed to register process metrics: %v", err)
}
grpcMetrics := grpcprometheus.NewServerMetrics()
err = prometheusRegistry.Register(grpcMetrics)
if err != nil {
return fmt.Errorf("failed to register gRPC server metrics: %v", err)
}
var grpcOptions []grpc.ServerOption
allowedTLSCiphers := []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
}
if c.GRPC.TLSCert != "" {
// Parse certificates from certificate file and key file for server.
cert, err := tls.LoadX509KeyPair(c.GRPC.TLSCert, c.GRPC.TLSKey)
if err != nil {
return fmt.Errorf("invalid config: error parsing gRPC certificate file: %v", err)
}
tlsConfig := tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS12,
CipherSuites: allowedTLSCiphers,
PreferServerCipherSuites: true,
}
if c.GRPC.TLSClientCA != "" {
// Parse certificates from client CA file to a new CertPool.
cPool := x509.NewCertPool()
clientCert, err := ioutil.ReadFile(c.GRPC.TLSClientCA)
clientCert, err := os.ReadFile(c.GRPC.TLSClientCA)
if err != nil {
return fmt.Errorf("invalid config: reading from client CA file: %v", err)
}
if cPool.AppendCertsFromPEM(clientCert) != true {
if !cPool.AppendCertsFromPEM(clientCert) {
return errors.New("invalid config: failed to parse client CA")
}
tlsConfig := tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: cPool,
}
grpcOptions = append(grpcOptions, grpc.Creds(credentials.NewTLS(&tlsConfig)))
} else {
opt, err := credentials.NewServerTLSFromFile(c.GRPC.TLSCert, c.GRPC.TLSKey)
if err != nil {
return fmt.Errorf("invalid config: load grpc certs: %v", err)
}
grpcOptions = append(grpcOptions, grpc.Creds(opt))
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
tlsConfig.ClientCAs = cPool
// Only add metrics if client auth is enabled
grpcOptions = append(grpcOptions,
grpc.StreamInterceptor(grpcMetrics.StreamServerInterceptor()),
grpc.UnaryInterceptor(grpcMetrics.UnaryServerInterceptor()),
)
}
grpcOptions = append(grpcOptions, grpc.Creds(credentials.NewTLS(&tlsConfig)))
}
s, err := c.Storage.Config.Open(logger)
if err != nil {
return fmt.Errorf("failed to initialize storage: %v", err)
}
defer s.Close()
logger.Infof("config storage: %s", c.Storage.Type)
if len(c.StaticClients) > 0 {
for _, client := range c.StaticClients {
logger.Infof("config static client: %s", client.ID)
for i, client := range c.StaticClients {
if client.Name == "" {
return fmt.Errorf("invalid config: Name field is required for a client")
}
if client.ID == "" && client.IDEnv == "" {
return fmt.Errorf("invalid config: ID or IDEnv field is required for a client")
}
if client.IDEnv != "" {
if client.ID != "" {
return fmt.Errorf("invalid config: ID and IDEnv fields are exclusive for client %q", client.ID)
}
c.StaticClients[i].ID = os.Getenv(client.IDEnv)
}
if client.Secret == "" && client.SecretEnv == "" && !client.Public {
return fmt.Errorf("invalid config: Secret or SecretEnv field is required for client %q", client.ID)
}
if client.SecretEnv != "" {
if client.Secret != "" {
return fmt.Errorf("invalid config: Secret and SecretEnv fields are exclusive for client %q", client.ID)
}
c.StaticClients[i].Secret = os.Getenv(client.SecretEnv)
}
logger.Infof("config static client: %s", client.Name)
}
s = storage.WithStaticClients(s, c.StaticClients)
}
@ -144,7 +219,7 @@ func serve(cmd *cobra.Command, args []string) error {
for i, p := range c.StaticPasswords {
passwords[i] = storage.Password(p)
}
s = storage.WithStaticPasswords(s, passwords)
s = storage.WithStaticPasswords(s, passwords, logger)
}
storageConnectors := make([]storage.Connector, len(c.StaticConnectors))
@ -163,7 +238,6 @@ func serve(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to initialize storage connectors: %v", err)
}
storageConnectors[i] = conn
}
if c.EnablePasswordDB {
@ -183,6 +257,9 @@ func serve(cmd *cobra.Command, args []string) error {
if c.OAuth2.SkipApprovalScreen {
logger.Infof("config skipping approval screen")
}
if c.OAuth2.PasswordConnector != "" {
logger.Infof("config using password grant connector: %s", c.OAuth2.PasswordConnector)
}
if len(c.Web.AllowedOrigins) > 0 {
logger.Infof("config allowed origins: %s", c.Web.AllowedOrigins)
}
@ -190,15 +267,21 @@ func serve(cmd *cobra.Command, args []string) error {
// explicitly convert to UTC.
now := func() time.Time { return time.Now().UTC() }
healthChecker := gosundheit.New()
serverConfig := server.Config{
SupportedResponseTypes: c.OAuth2.ResponseTypes,
SkipApprovalScreen: c.OAuth2.SkipApprovalScreen,
AlwaysShowLoginScreen: c.OAuth2.AlwaysShowLoginScreen,
PasswordConnector: c.OAuth2.PasswordConnector,
AllowedOrigins: c.Web.AllowedOrigins,
Issuer: c.Issuer,
Storage: s,
Web: c.Frontend,
Logger: logger,
Now: now,
PrometheusRegistry: prometheusRegistry,
HealthChecker: healthChecker,
}
if c.Expiry.SigningKeys != "" {
signingKeys, err := time.ParseDuration(c.Expiry.SigningKeys)
@ -216,44 +299,195 @@ func serve(cmd *cobra.Command, args []string) error {
logger.Infof("config id tokens valid for: %v", idTokens)
serverConfig.IDTokensValidFor = idTokens
}
if c.Expiry.AuthRequests != "" {
authRequests, err := time.ParseDuration(c.Expiry.AuthRequests)
if err != nil {
return fmt.Errorf("invalid config value %q for auth request expiry: %v", c.Expiry.AuthRequests, err)
}
logger.Infof("config auth requests valid for: %v", authRequests)
serverConfig.AuthRequestsValidFor = authRequests
}
if c.Expiry.DeviceRequests != "" {
deviceRequests, err := time.ParseDuration(c.Expiry.DeviceRequests)
if err != nil {
return fmt.Errorf("invalid config value %q for device request expiry: %v", c.Expiry.AuthRequests, err)
}
logger.Infof("config device requests valid for: %v", deviceRequests)
serverConfig.DeviceRequestsValidFor = deviceRequests
}
refreshTokenPolicy, err := server.NewRefreshTokenPolicy(
logger,
c.Expiry.RefreshTokens.DisableRotation,
c.Expiry.RefreshTokens.ValidIfNotUsedFor,
c.Expiry.RefreshTokens.AbsoluteLifetime,
c.Expiry.RefreshTokens.ReuseInterval,
)
if err != nil {
return fmt.Errorf("invalid refresh token expiration policy config: %v", err)
}
serverConfig.RefreshTokenPolicy = refreshTokenPolicy
serv, err := server.NewServer(context.Background(), serverConfig)
if err != nil {
return fmt.Errorf("failed to initialize server: %v", err)
}
errc := make(chan error, 3)
if c.Web.HTTP != "" {
logger.Infof("listening (http) on %s", c.Web.HTTP)
go func() {
err := http.ListenAndServe(c.Web.HTTP, serv)
errc <- fmt.Errorf("listening on %s failed: %v", c.Web.HTTP, err)
}()
}
if c.Web.HTTPS != "" {
logger.Infof("listening (https) on %s", c.Web.HTTPS)
go func() {
err := http.ListenAndServeTLS(c.Web.HTTPS, c.Web.TLSCert, c.Web.TLSKey, serv)
errc <- fmt.Errorf("listening on %s failed: %v", c.Web.HTTPS, err)
}()
}
if c.GRPC.Addr != "" {
logger.Infof("listening (grpc) on %s", c.GRPC.Addr)
go func() {
errc <- func() error {
list, err := net.Listen("tcp", c.GRPC.Addr)
if err != nil {
return fmt.Errorf("listening on %s failed: %v", c.GRPC.Addr, err)
}
s := grpc.NewServer(grpcOptions...)
api.RegisterDexServer(s, server.NewAPI(serverConfig.Storage, logger))
err = s.Serve(list)
return fmt.Errorf("listening on %s failed: %v", c.GRPC.Addr, err)
}()
}()
telemetryRouter := http.NewServeMux()
telemetryRouter.Handle("/metrics", promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{}))
// Configure health checker
{
handler := gosundheithttp.HandleHealthJSON(healthChecker)
telemetryRouter.Handle("/healthz", handler)
// Kubernetes style health checks
telemetryRouter.HandleFunc("/healthz/live", func(w http.ResponseWriter, _ *http.Request) {
_, _ = w.Write([]byte("ok"))
})
telemetryRouter.Handle("/healthz/ready", handler)
}
return <-errc
healthChecker.RegisterCheck(
&checks.CustomCheck{
CheckName: "storage",
CheckFunc: storage.NewCustomHealthCheckFunc(serverConfig.Storage, serverConfig.Now),
},
gosundheit.ExecutionPeriod(15*time.Second),
gosundheit.InitiallyPassing(true),
)
var group run.Group
// Set up telemetry server
if c.Telemetry.HTTP != "" {
const name = "telemetry"
logger.Infof("listening (%s) on %s", name, c.Telemetry.HTTP)
l, err := net.Listen("tcp", c.Telemetry.HTTP)
if err != nil {
return fmt.Errorf("listening (%s) on %s: %v", name, c.Telemetry.HTTP, err)
}
if c.Telemetry.EnableProfiling {
pprofHandler(telemetryRouter)
}
server := &http.Server{
Handler: telemetryRouter,
}
defer server.Close()
group.Add(func() error {
return server.Serve(l)
}, func(err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
logger.Debugf("starting graceful shutdown (%s)", name)
if err := server.Shutdown(ctx); err != nil {
logger.Errorf("graceful shutdown (%s): %v", name, err)
}
})
}
// Set up http server
if c.Web.HTTP != "" {
const name = "http"
logger.Infof("listening (%s) on %s", name, c.Web.HTTP)
l, err := net.Listen("tcp", c.Web.HTTP)
if err != nil {
return fmt.Errorf("listening (%s) on %s: %v", name, c.Web.HTTP, err)
}
server := &http.Server{
Handler: serv,
}
defer server.Close()
group.Add(func() error {
return server.Serve(l)
}, func(err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
logger.Debugf("starting graceful shutdown (%s)", name)
if err := server.Shutdown(ctx); err != nil {
logger.Errorf("graceful shutdown (%s): %v", name, err)
}
})
}
// Set up https server
if c.Web.HTTPS != "" {
const name = "https"
logger.Infof("listening (%s) on %s", name, c.Web.HTTPS)
l, err := net.Listen("tcp", c.Web.HTTPS)
if err != nil {
return fmt.Errorf("listening (%s) on %s: %v", name, c.Web.HTTPS, err)
}
server := &http.Server{
Handler: serv,
TLSConfig: &tls.Config{
CipherSuites: allowedTLSCiphers,
PreferServerCipherSuites: true,
MinVersion: tls.VersionTLS12,
},
}
defer server.Close()
group.Add(func() error {
return server.ServeTLS(l, c.Web.TLSCert, c.Web.TLSKey)
}, func(err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
logger.Debugf("starting graceful shutdown (%s)", name)
if err := server.Shutdown(ctx); err != nil {
logger.Errorf("graceful shutdown (%s): %v", name, err)
}
})
}
// Set up grpc server
if c.GRPC.Addr != "" {
logger.Infof("listening (grpc) on %s", c.GRPC.Addr)
grpcListener, err := net.Listen("tcp", c.GRPC.Addr)
if err != nil {
return fmt.Errorf("listening (grcp) on %s: %w", c.GRPC.Addr, err)
}
grpcSrv := grpc.NewServer(grpcOptions...)
api.RegisterDexServer(grpcSrv, server.NewAPI(serverConfig.Storage, logger, version))
grpcMetrics.InitializeMetrics(grpcSrv)
if c.GRPC.Reflection {
logger.Info("enabling reflection in grpc service")
reflection.Register(grpcSrv)
}
group.Add(func() error {
return grpcSrv.Serve(grpcListener)
}, func(err error) {
logger.Debugf("starting graceful shutdown (grpc)")
grpcSrv.GracefulStop()
})
}
group.Add(run.SignalHandler(context.Background(), os.Interrupt, syscall.SIGTERM))
if err := group.Run(); err != nil {
if _, ok := err.(run.SignalError); !ok {
return fmt.Errorf("run groups: %w", err)
}
logger.Infof("%v, shutdown now", err)
}
return nil
}
var (
@ -270,7 +504,7 @@ func (f *utcFormatter) Format(e *logrus.Entry) ([]byte, error) {
return f.f.Format(e)
}
func newLogger(level string, format string) (logrus.FieldLogger, error) {
func newLogger(level string, format string) (log.Logger, error) {
var logLevel logrus.Level
switch strings.ToLower(level) {
case "debug":
@ -299,3 +533,33 @@ func newLogger(level string, format string) (logrus.FieldLogger, error) {
Level: logLevel,
}, nil
}
func applyConfigOverrides(options serveOptions, config *Config) {
if options.webHTTPAddr != "" {
config.Web.HTTP = options.webHTTPAddr
}
if options.webHTTPSAddr != "" {
config.Web.HTTPS = options.webHTTPSAddr
}
if options.telemetryAddr != "" {
config.Telemetry.HTTP = options.telemetryAddr
}
if options.grpcAddr != "" {
config.GRPC.Addr = options.grpcAddr
}
if config.Frontend.Dir == "" {
config.Frontend.Dir = os.Getenv("DEX_FRONTEND_DIR")
}
}
func pprofHandler(router *http.ServeMux) {
router.HandleFunc("/debug/pprof/", pprof.Index)
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
router.HandleFunc("/debug/pprof/trace", pprof.Trace)
}

View File

@ -4,19 +4,23 @@ import (
"fmt"
"runtime"
"github.com/coreos/dex/version"
"github.com/spf13/cobra"
)
var version = "DEV"
func commandVersion() *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Print the version and exit",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf(`dex Version: %s
Go Version: %s
Go OS/ARCH: %s %s
`, version.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
Run: func(_ *cobra.Command, _ []string) {
fmt.Printf(
"Dex Version: %s\nGo Version: %s\nGo OS/ARCH: %s %s\n",
version,
runtime.Version(),
runtime.GOOS,
runtime.GOARCH,
)
},
}
}

View File

@ -0,0 +1,92 @@
// Package main provides a utility program to launch the Dex container process with an optional
// templating step (provided by gomplate).
//
// This was originally written as a shell script, but we rewrote it as a Go program so that it could
// run as a raw binary in a distroless container.
package main
import (
"fmt"
"os"
"os/exec"
"strings"
"syscall"
)
func main() {
// Note that this docker-entrypoint program is args[0], and it is provided with the true process
// args.
args := os.Args[1:]
if err := run(args, realExec, realWhich); err != nil {
fmt.Println("error:", err.Error())
os.Exit(1)
}
}
func realExec(fork bool, args ...string) error {
if fork {
if output, err := exec.Command(args[0], args[1:]...).CombinedOutput(); err != nil {
return fmt.Errorf("cannot fork/exec command %s: %w (output: %q)", args, err, string(output))
}
return nil
}
argv0, err := exec.LookPath(args[0])
if err != nil {
return fmt.Errorf("cannot lookup path for command %s: %w", args[0], err)
}
if err := syscall.Exec(argv0, args, os.Environ()); err != nil {
return fmt.Errorf("cannot exec command %s (%q): %w", args, argv0, err)
}
return nil
}
func realWhich(path string) string {
fullPath, err := exec.LookPath(path)
if err != nil {
return ""
}
return fullPath
}
func run(args []string, execFunc func(bool, ...string) error, whichFunc func(string) string) error {
if args[0] != "dex" && args[0] != whichFunc("dex") {
return execFunc(false, args...)
}
if args[1] != "serve" {
return execFunc(false, args...)
}
newArgs := []string{}
for _, tplCandidate := range args {
if hasSuffixes(tplCandidate, ".tpl", ".tmpl", ".yaml") {
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
if err != nil {
return fmt.Errorf("cannot create temp file: %w", err)
}
if err := execFunc(true, "gomplate", "-f", tplCandidate, "-o", tmpFile.Name()); err != nil {
return err
}
newArgs = append(newArgs, tmpFile.Name())
} else {
newArgs = append(newArgs, tplCandidate)
}
}
return execFunc(false, newArgs...)
}
func hasSuffixes(s string, suffixes ...string) bool {
for _, suffix := range suffixes {
if strings.HasSuffix(s, suffix) {
return true
}
}
return false
}

View File

@ -0,0 +1,113 @@
package main
import (
"strings"
"testing"
)
type execArgs struct {
fork bool
argPrefixes []string
}
func TestRun(t *testing.T) {
tests := []struct {
name string
args []string
execReturns error
whichReturns string
wantExecArgs []execArgs
wantErr error
}{
{
name: "executable not dex",
args: []string{"tuna", "fish"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"tuna", "fish"}}},
},
{
name: "executable is full path to dex",
args: []string{"/usr/local/bin/dex", "marshmallow", "zelda"},
whichReturns: "/usr/local/bin/dex",
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}}},
},
{
name: "command is not serve",
args: []string{"dex", "marshmallow", "zelda"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}}},
},
{
name: "no templates",
args: []string{"dex", "serve", "config.yaml.not-a-template"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
},
{
name: "no templates",
args: []string{"dex", "serve", "config.yaml.not-a-template"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
},
{
name: ".tpl template",
args: []string{"dex", "serve", "config.tpl"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tpl", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
},
{
name: ".tmpl template",
args: []string{"dex", "serve", "config.tmpl"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tmpl", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
},
{
name: ".yaml template",
args: []string{"dex", "serve", "some/path/config.yaml"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "some/path/config.yaml", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var gotExecForks []bool
var gotExecArgs [][]string
fakeExec := func(fork bool, args ...string) error {
gotExecForks = append(gotExecForks, fork)
gotExecArgs = append(gotExecArgs, args)
return test.execReturns
}
fakeWhich := func(_ string) string { return test.whichReturns }
gotErr := run(test.args, fakeExec, fakeWhich)
if (test.wantErr == nil) != (gotErr == nil) {
t.Errorf("wanted error %s, got %s", test.wantErr, gotErr)
}
if !execArgsMatch(test.wantExecArgs, gotExecForks, gotExecArgs) {
t.Errorf("wanted exec args %+v, got %+v %+v", test.wantExecArgs, gotExecForks, gotExecArgs)
}
})
}
}
func execArgsMatch(wantExecArgs []execArgs, gotForks []bool, gotExecArgs [][]string) bool {
if len(wantExecArgs) != len(gotForks) {
return false
}
for i := range wantExecArgs {
if wantExecArgs[i].fork != gotForks[i] {
return false
}
for j := range wantExecArgs[i].argPrefixes {
if !strings.HasPrefix(gotExecArgs[i][j], wantExecArgs[i].argPrefixes[j]) {
return false
}
}
}
return true
}

35
config.dev.yaml Normal file
View File

@ -0,0 +1,35 @@
issuer: http://127.0.0.1:5556/dex
storage:
type: sqlite3
config:
file: var/sqlite/dex.db
web:
http: 127.0.0.1:5556
telemetry:
http: 127.0.0.1:5558
grpc:
addr: 127.0.0.1:5557
staticClients:
- id: example-app
redirectURIs:
- 'http://127.0.0.1:5555/callback'
name: 'Example App'
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
connectors:
- type: mockCallback
id: mock
name: Example
enablePasswordDB: true
staticPasswords:
- email: "admin@example.com"
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"

48
config.docker.yaml Normal file
View File

@ -0,0 +1,48 @@
{{- /* NOTE: This configuration file is an example and exists only for development purposes. */ -}}
{{- /* To find more about gomplate formatting, please visit its documentation site - https://docs.gomplate.ca/ */ -}}
issuer: {{ getenv "DEX_ISSUER" "http://127.0.0.1:5556/dex" }}
storage:
type: sqlite3
config:
file: {{ getenv "DEX_STORAGE_SQLITE3_CONFIG_FILE" "/var/dex/dex.db" }}
web:
{{- if getenv "DEX_WEB_HTTPS" "" }}
https: {{ .Env.DEX_WEB_HTTPS }}
tlsKey: {{ getenv "DEX_WEB_TLS_KEY" | required "$DEX_WEB_TLS_KEY in case of web.https is enabled" }}
tlsCert: {{ getenv "DEX_WEB_TLS_CERT" | required "$DEX_WEB_TLS_CERT in case of web.https is enabled" }}
{{- end }}
http: {{ getenv "DEX_WEB_HTTP" "0.0.0.0:5556" }}
{{- if getenv "DEX_TELEMETRY_HTTP" }}
telemetry:
http: {{ .Env.DEX_TELEMETRY_HTTP }}
{{- end }}
expiry:
deviceRequests: {{ getenv "DEX_EXPIRY_DEVICE_REQUESTS" "5m" }}
signingKeys: {{ getenv "DEX_EXPIRY_SIGNING_KEYS" "6h" }}
idTokens: {{ getenv "DEX_EXPIRY_ID_TOKENS" "24h" }}
authRequests: {{ getenv "DEX_EXPIRY_AUTH_REQUESTS" "24h" }}
logger:
level: {{ getenv "DEX_LOG_LEVEL" "info" }}
format: {{ getenv "DEX_LOG_FORMAT" "text" }}
oauth2:
responseTypes: {{ getenv "DEX_OAUTH2_RESPONSE_TYPES" "[code]" }}
skipApprovalScreen: {{ getenv "DEX_OAUTH2_SKIP_APPROVAL_SCREEN" "false" }}
alwaysShowLoginScreen: {{ getenv "DEX_OAUTH2_ALWAYS_SHOW_LOGIN_SCREEN" "false" }}
{{- if getenv "DEX_OAUTH2_PASSWORD_CONNECTOR" "" }}
passwordConnector: {{ .Env.DEX_OAUTH2_PASSWORD_CONNECTOR }}
{{- end }}
enablePasswordDB: {{ getenv "DEX_ENABLE_PASSWORD_DB" "true" }}
connectors:
{{- if getenv "DEX_CONNECTORS_ENABLE_MOCK" }}
- type: mockCallback
id: mock
name: Example
{{- end }}

136
config.yaml.dist Normal file
View File

@ -0,0 +1,136 @@
# The base path of Dex and the external name of the OpenID Connect service.
# This is the canonical URL that all clients MUST use to refer to Dex. If a
# path is provided, Dex's HTTP service will listen at a non-root URL.
issuer: http://127.0.0.1:5556/dex
# The storage configuration determines where Dex stores its state.
# Supported options include:
# - SQL flavors
# - key-value stores (eg. etcd)
# - Kubernetes Custom Resources
#
# See the documentation (https://dexidp.io/docs/storage/) for further information.
storage:
type: memory
# type: sqlite3
# config:
# file: /var/dex/dex.db
# type: mysql
# config:
# host: 127.0.0.1
# port: 3306
# database: dex
# user: mysql
# password: mysql
# ssl:
# mode: "false"
# type: postgres
# config:
# host: 127.0.0.1
# port: 5432
# database: dex
# user: postgres
# password: postgres
# ssl:
# mode: disable
# type: etcd
# config:
# endpoints:
# - http://127.0.0.1:2379
# namespace: dex/
# type: kubernetes
# config:
# kubeConfigFile: $HOME/.kube/config
# HTTP service configuration
web:
http: 127.0.0.1:5556
# Uncomment to enable HTTPS endpoint.
# https: 127.0.0.1:5554
# tlsCert: /etc/dex/tls.crt
# tlsKey: /etc/dex/tls.key
# Dex UI configuration
# frontend:
# issuer: dex
# logoURL: theme/logo.png
# dir: ""
# theme: light
# Telemetry configuration
# telemetry:
# http: 127.0.0.1:5558
# logger:
# level: "debug"
# format: "text" # can also be "json"
# gRPC API configuration
# Uncomment this block to enable the gRPC API.
# See the documentation (https://dexidp.io/docs/api/) for further information.
# grpc:
# addr: 127.0.0.1:5557
# tlsCert: examples/grpc-client/server.crt
# tlsKey: examples/grpc-client/server.key
# tlsClientCA: examples/grpc-client/ca.crt
# Expiration configuration for tokens, signing keys, etc.
# expiry:
# deviceRequests: "5m"
# signingKeys: "6h"
# idTokens: "24h"
# refreshTokens:
# disableRotation: false
# reuseInterval: "3s"
# validIfNotUsedFor: "2160h" # 90 days
# absoluteLifetime: "3960h" # 165 days
# OAuth2 configuration
# oauth2:
# # use ["code", "token", "id_token"] to enable implicit flow for web-only clients
# responseTypes: [ "code" ] # also allowed are "token" and "id_token"
#
# # By default, Dex will ask for approval to share data with application
# # (approval for sharing data from connected IdP to Dex is separate process on IdP)
# skipApprovalScreen: false
#
# # If only one authentication method is enabled, the default behavior is to
# # go directly to it. For connected IdPs, this redirects the browser away
# # from application to upstream provider such as the Google login page
# alwaysShowLoginScreen: false
#
# # Uncomment to use a specific connector for password grants
# passwordConnector: local
# Static clients registered in Dex by default.
#
# Alternatively, clients may be added through the gRPC API.
# staticClients:
# - id: example-app
# redirectURIs:
# - 'http://127.0.0.1:5555/callback'
# name: 'Example App'
# secret: ZXhhbXBsZS1hcHAtc2VjcmV0
# Connectors are used to authenticate users agains upstream identity providers.
#
# See the documentation (https://dexidp.io/docs/connectors/) for further information.
# connectors: []
# Enable the password database.
#
# It's a "virtual" connector (identity provider) that stores
# login credentials in Dex's store.
enablePasswordDB: true
# If this option isn't chosen users may be added through the gRPC API.
# A static list of passwords for the password connector.
#
# Alternatively, passwords my be added/updated through the gRPC API.
# staticPasswords: []

View File

@ -0,0 +1,449 @@
// Package atlassiancrowd provides authentication strategies using Atlassian Crowd.
package atlassiancrowd
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
)
// Config holds configuration options for Atlassian Crowd connector.
// Crowd connectors require executing two queries, the first to find
// the user based on the username and password given to the connector.
// The second to use the user entry to search for groups.
//
// An example config:
//
// type: atlassian-crowd
// config:
// baseURL: https://crowd.example.com/context
// clientID: applogin
// clientSecret: appP4$$w0rd
// # users can be restricted by a list of groups
// groups:
// - admin
// # Prompt for username field
// usernamePrompt: Login
// preferredUsernameField: name
//
type Config struct {
BaseURL string `json:"baseURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
Groups []string `json:"groups"`
// PreferredUsernameField allows users to set the field to any of the
// following values: "key", "name" or "email".
// If unset, the preferred_username field will remain empty.
PreferredUsernameField string `json:"preferredUsernameField"`
// UsernamePrompt allows users to override the username attribute (displayed
// in the username/password prompt). If unset, the handler will use.
// "Username".
UsernamePrompt string `json:"usernamePrompt"`
}
type crowdUser struct {
Key string
Name string
Active bool
Email string
}
type crowdGroups struct {
Groups []struct {
Name string
} `json:"groups"`
}
type crowdAuthentication struct {
Token string
User struct {
Name string
} `json:"user"`
CreatedDate uint64 `json:"created-date"`
ExpiryDate uint64 `json:"expiry-date"`
}
type crowdAuthenticationError struct {
Reason string
Message string
}
// Open returns a strategy for logging in through Atlassian Crowd
func (c *Config) Open(_ string, logger log.Logger) (connector.Connector, error) {
if c.BaseURL == "" {
return nil, fmt.Errorf("crowd: no baseURL provided for crowd connector")
}
return &crowdConnector{Config: *c, logger: logger}, nil
}
type crowdConnector struct {
Config
logger log.Logger
}
var (
_ connector.PasswordConnector = (*crowdConnector)(nil)
_ connector.RefreshConnector = (*crowdConnector)(nil)
)
type refreshData struct {
Username string `json:"username"`
}
func (c *crowdConnector) Login(ctx context.Context, s connector.Scopes, username, password string) (ident connector.Identity, validPass bool, err error) {
// make this check to avoid empty passwords.
if password == "" {
return connector.Identity{}, false, nil
}
// We want to return a different error if the user's password is incorrect vs
// if there was an error.
var incorrectPass bool
var user crowdUser
client := c.crowdAPIClient()
if incorrectPass, err = c.authenticateWithPassword(ctx, client, username, password); err != nil {
return connector.Identity{}, false, err
}
if incorrectPass {
return connector.Identity{}, false, nil
}
if user, err = c.user(ctx, client, username); err != nil {
return connector.Identity{}, false, err
}
ident = c.identityFromCrowdUser(user)
if s.Groups {
userGroups, err := c.getGroups(ctx, client, s.Groups, ident.Username)
if err != nil {
return connector.Identity{}, false, fmt.Errorf("crowd: failed to query groups: %v", err)
}
ident.Groups = userGroups
}
if s.OfflineAccess {
refresh := refreshData{Username: username}
// Encode entry for following up requests such as the groups query and refresh attempts.
if ident.ConnectorData, err = json.Marshal(refresh); err != nil {
return connector.Identity{}, false, fmt.Errorf("crowd: marshal refresh data: %v", err)
}
}
return ident, true, nil
}
func (c *crowdConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
var data refreshData
if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
return ident, fmt.Errorf("crowd: failed to unmarshal internal data: %v", err)
}
var user crowdUser
client := c.crowdAPIClient()
user, err := c.user(ctx, client, data.Username)
if err != nil {
return ident, fmt.Errorf("crowd: get user %q: %v", data.Username, err)
}
newIdent := c.identityFromCrowdUser(user)
newIdent.ConnectorData = ident.ConnectorData
// If user exists, authenticate it to prolong sso session.
err = c.authenticateUser(ctx, client, data.Username)
if err != nil {
return ident, fmt.Errorf("crowd: authenticate user: %v", err)
}
if s.Groups {
userGroups, err := c.getGroups(ctx, client, s.Groups, newIdent.Username)
if err != nil {
return connector.Identity{}, fmt.Errorf("crowd: failed to query groups: %v", err)
}
newIdent.Groups = userGroups
}
return newIdent, nil
}
func (c *crowdConnector) Prompt() string {
return c.UsernamePrompt
}
func (c *crowdConnector) crowdAPIClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
}
// authenticateWithPassword creates a new session for user and validates a password with Crowd API
func (c *crowdConnector) authenticateWithPassword(ctx context.Context, client *http.Client, username string, password string) (invalidPass bool, err error) {
req, err := c.crowdUserManagementRequest(ctx,
"POST",
"/session",
struct {
Username string `json:"username"`
Password string `json:"password"`
}{Username: username, Password: password},
)
if err != nil {
return false, fmt.Errorf("crowd: new auth pass api request %v", err)
}
resp, err := client.Do(req)
if err != nil {
return false, fmt.Errorf("crowd: api request %v", err)
}
defer resp.Body.Close()
body, err := c.validateCrowdResponse(resp)
if err != nil {
return false, err
}
if resp.StatusCode != http.StatusCreated {
var authError crowdAuthenticationError
if err := json.Unmarshal(body, &authError); err != nil {
return false, fmt.Errorf("unmarshal auth pass response: %d %v %q", resp.StatusCode, err, string(body))
}
if authError.Reason == "INVALID_USER_AUTHENTICATION" {
return true, nil
}
return false, fmt.Errorf("%s: %s", resp.Status, authError.Message)
}
var authResponse crowdAuthentication
if err := json.Unmarshal(body, &authResponse); err != nil {
return false, fmt.Errorf("decode auth response: %v", err)
}
return false, nil
}
// authenticateUser creates a new session for user without password validations with Crowd API
func (c *crowdConnector) authenticateUser(ctx context.Context, client *http.Client, username string) error {
req, err := c.crowdUserManagementRequest(ctx,
"POST",
"/session?validate-password=false",
struct {
Username string `json:"username"`
}{Username: username},
)
if err != nil {
return fmt.Errorf("crowd: new auth api request %v", err)
}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("crowd: api request %v", err)
}
defer resp.Body.Close()
body, err := c.validateCrowdResponse(resp)
if err != nil {
return err
}
if resp.StatusCode != http.StatusCreated {
return fmt.Errorf("%s: %s", resp.Status, body)
}
var authResponse crowdAuthentication
if err := json.Unmarshal(body, &authResponse); err != nil {
return fmt.Errorf("decode auth response: %v", err)
}
return nil
}
// user retrieves user info from Crowd API
func (c *crowdConnector) user(ctx context.Context, client *http.Client, username string) (crowdUser, error) {
var user crowdUser
req, err := c.crowdUserManagementRequest(ctx,
"GET",
fmt.Sprintf("/user?username=%s", username),
nil,
)
if err != nil {
return user, fmt.Errorf("crowd: new user api request %v", err)
}
resp, err := client.Do(req)
if err != nil {
return user, fmt.Errorf("crowd: api request %v", err)
}
defer resp.Body.Close()
body, err := c.validateCrowdResponse(resp)
if err != nil {
return user, err
}
if resp.StatusCode != http.StatusOK {
return user, fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.Unmarshal(body, &user); err != nil {
return user, fmt.Errorf("failed to decode response: %v", err)
}
return user, nil
}
// groups retrieves groups from Crowd API
func (c *crowdConnector) groups(ctx context.Context, client *http.Client, username string) (userGroups []string, err error) {
var crowdGroups crowdGroups
req, err := c.crowdUserManagementRequest(ctx,
"GET",
fmt.Sprintf("/user/group/nested?username=%s", username),
nil,
)
if err != nil {
return nil, fmt.Errorf("crowd: new groups api request %v", err)
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("crowd: api request %v", err)
}
defer resp.Body.Close()
body, err := c.validateCrowdResponse(resp)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.Unmarshal(body, &crowdGroups); err != nil {
return nil, fmt.Errorf("failed to decode response: %v", err)
}
for _, group := range crowdGroups.Groups {
userGroups = append(userGroups, group.Name)
}
return userGroups, nil
}
// identityFromCrowdUser converts crowdUser to Identity
func (c *crowdConnector) identityFromCrowdUser(user crowdUser) connector.Identity {
identity := connector.Identity{
Username: user.Name,
UserID: user.Key,
Email: user.Email,
EmailVerified: true,
}
switch c.PreferredUsernameField {
case "key":
identity.PreferredUsername = user.Key
case "name":
identity.PreferredUsername = user.Name
case "email":
identity.PreferredUsername = user.Email
default:
if c.PreferredUsernameField != "" {
c.logger.Warnf("preferred_username left empty. Invalid crowd field mapped to preferred_username: %s", c.PreferredUsernameField)
}
}
return identity
}
// getGroups retrieves a list of user's groups and filters it
func (c *crowdConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) ([]string, error) {
crowdGroups, err := c.groups(ctx, client, userLogin)
if err != nil {
return nil, err
}
if len(c.Groups) > 0 {
filteredGroups := groups.Filter(crowdGroups, c.Groups)
if len(filteredGroups) == 0 {
return nil, fmt.Errorf("crowd: user %q is not in any of the required groups", userLogin)
}
return filteredGroups, nil
} else if groupScope {
return crowdGroups, nil
}
return nil, nil
}
// crowdUserManagementRequest create a http.Request with basic auth, json payload and Accept header
func (c *crowdConnector) crowdUserManagementRequest(ctx context.Context, method string, apiURL string, jsonPayload interface{}) (*http.Request, error) {
var body io.Reader
if jsonPayload != nil {
jsonData, err := json.Marshal(jsonPayload)
if err != nil {
return nil, fmt.Errorf("crowd: marshal API json payload: %v", err)
}
body = bytes.NewReader(jsonData)
}
req, err := http.NewRequest(method, fmt.Sprintf("%s/rest/usermanagement/1%s", c.BaseURL, apiURL), body)
if err != nil {
return nil, fmt.Errorf("new API req: %v", err)
}
req = req.WithContext(ctx)
// Crowd API requires a basic auth
req.SetBasicAuth(c.ClientID, c.ClientSecret)
req.Header.Set("Accept", "application/json")
if jsonPayload != nil {
req.Header.Set("Content-type", "application/json")
}
return req, nil
}
// validateCrowdResponse validates unique not JSON responses from API
func (c *crowdConnector) validateCrowdResponse(resp *http.Response) ([]byte, error) {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("crowd: read user body: %v", err)
}
if resp.StatusCode == http.StatusForbidden && strings.Contains(string(body), "The server understood the request but refuses to authorize it.") {
c.logger.Debugf("crowd response validation failed: %s", string(body))
return nil, fmt.Errorf("dex is forbidden from making requests to the Atlassian Crowd application by URL %q", c.BaseURL)
}
if resp.StatusCode == http.StatusUnauthorized && string(body) == "Application failed to authenticate" {
c.logger.Debugf("crowd response validation failed: %s", string(body))
return nil, fmt.Errorf("dex failed to authenticate Crowd Application with ID %q", c.ClientID)
}
return body, nil
}

View File

@ -0,0 +1,189 @@
// Package atlassiancrowd provides authentication strategies using Atlassian Crowd.
package atlassiancrowd
import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"github.com/sirupsen/logrus"
)
func TestUserGroups(t *testing.T) {
s := newTestServer(map[string]TestServerResponse{
"/rest/usermanagement/1/user/group/nested?username=testuser": {
Body: crowdGroups{Groups: []struct{ Name string }{{Name: "group1"}, {Name: "group2"}}},
Code: 200,
},
})
defer s.Close()
c := newTestCrowdConnector(s.URL)
groups, err := c.getGroups(context.Background(), newClient(), true, "testuser")
expectNil(t, err)
expectEquals(t, groups, []string{"group1", "group2"})
}
func TestUserGroupsWithFiltering(t *testing.T) {
s := newTestServer(map[string]TestServerResponse{
"/rest/usermanagement/1/user/group/nested?username=testuser": {
Body: crowdGroups{Groups: []struct{ Name string }{{Name: "group1"}, {Name: "group2"}}},
Code: 200,
},
})
defer s.Close()
c := newTestCrowdConnector(s.URL)
c.Groups = []string{"group1"}
groups, err := c.getGroups(context.Background(), newClient(), true, "testuser")
expectNil(t, err)
expectEquals(t, groups, []string{"group1"})
}
func TestUserLoginFlow(t *testing.T) {
s := newTestServer(map[string]TestServerResponse{
"/rest/usermanagement/1/session?validate-password=false": {
Body: crowdAuthentication{},
Code: 201,
},
"/rest/usermanagement/1/user?username=testuser": {
Body: crowdUser{Active: true, Name: "testuser", Email: "testuser@example.com"},
Code: 200,
},
"/rest/usermanagement/1/user?username=testuser2": {
Body: `<html>The server understood the request but refuses to authorize it.</html>`,
Code: 403,
},
})
defer s.Close()
c := newTestCrowdConnector(s.URL)
user, err := c.user(context.Background(), newClient(), "testuser")
expectNil(t, err)
expectEquals(t, user.Name, "testuser")
expectEquals(t, user.Email, "testuser@example.com")
err = c.authenticateUser(context.Background(), newClient(), "testuser")
expectNil(t, err)
_, err = c.user(context.Background(), newClient(), "testuser2")
expectEquals(t, err, fmt.Errorf("dex is forbidden from making requests to the Atlassian Crowd application by URL %q", s.URL))
}
func TestUserPassword(t *testing.T) {
s := newTestServer(map[string]TestServerResponse{
"/rest/usermanagement/1/session": {
Body: crowdAuthenticationError{Reason: "INVALID_USER_AUTHENTICATION", Message: "test"},
Code: 401,
},
"/rest/usermanagement/1/session?validate-password=false": {
Body: crowdAuthentication{},
Code: 201,
},
})
defer s.Close()
c := newTestCrowdConnector(s.URL)
invalidPassword, err := c.authenticateWithPassword(context.Background(), newClient(), "testuser", "testpassword")
expectNil(t, err)
expectEquals(t, invalidPassword, true)
err = c.authenticateUser(context.Background(), newClient(), "testuser")
expectNil(t, err)
}
func TestIdentityFromCrowdUser(t *testing.T) {
user := crowdUser{
Key: "12345",
Name: "testuser",
Active: true,
Email: "testuser@example.com",
}
c := newTestCrowdConnector("/")
// Sanity checks
expectEquals(t, user.Name, "testuser")
expectEquals(t, user.Email, "testuser@example.com")
// Test unconfigured behaviour
i := c.identityFromCrowdUser(user)
expectEquals(t, i.UserID, "12345")
expectEquals(t, i.Username, "testuser")
expectEquals(t, i.Email, "testuser@example.com")
expectEquals(t, i.EmailVerified, true)
// Test for various PreferredUsernameField settings
// unset
expectEquals(t, i.PreferredUsername, "")
c.Config.PreferredUsernameField = "key"
i = c.identityFromCrowdUser(user)
expectEquals(t, i.PreferredUsername, "12345")
c.Config.PreferredUsernameField = "name"
i = c.identityFromCrowdUser(user)
expectEquals(t, i.PreferredUsername, "testuser")
c.Config.PreferredUsernameField = "email"
i = c.identityFromCrowdUser(user)
expectEquals(t, i.PreferredUsername, "testuser@example.com")
c.Config.PreferredUsernameField = "invalidstring"
i = c.identityFromCrowdUser(user)
expectEquals(t, i.PreferredUsername, "")
}
type TestServerResponse struct {
Body interface{}
Code int
}
func newTestCrowdConnector(baseURL string) crowdConnector {
connector := crowdConnector{}
connector.BaseURL = baseURL
connector.logger = &logrus.Logger{
Out: io.Discard,
Level: logrus.DebugLevel,
Formatter: &logrus.TextFormatter{DisableColors: true},
}
return connector
}
func newTestServer(responses map[string]TestServerResponse) *httptest.Server {
s := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := responses[r.RequestURI]
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(response.Code)
json.NewEncoder(w).Encode(response.Body)
}))
return s
}
func newClient() *http.Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return &http.Client{Transport: tr}
}
func expectNil(t *testing.T, a interface{}) {
if a != nil {
t.Errorf("Expected %+v to equal nil", a)
}
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("Expected %+v to equal %+v", a, b)
}
}

View File

@ -0,0 +1,80 @@
// Package authproxy implements a connector which relies on external
// authentication (e.g. mod_auth in Apache2) and returns an identity with the
// HTTP header X-Remote-User as verified email.
package authproxy
import (
"fmt"
"net/http"
"net/url"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
// Config holds the configuration parameters for a connector which returns an
// identity with the HTTP header X-Remote-User as verified email,
// X-Remote-Group and configured staticGroups as user's group.
// Headers retrieved to fetch user's email and group can be configured
// with userHeader and groupHeader.
type Config struct {
UserHeader string `json:"userHeader"`
GroupHeader string `json:"groupHeader"`
Groups []string `json:"staticGroups"`
}
// Open returns an authentication strategy which requires no user interaction.
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
userHeader := c.UserHeader
if userHeader == "" {
userHeader = "X-Remote-User"
}
groupHeader := c.GroupHeader
if groupHeader == "" {
groupHeader = "X-Remote-Group"
}
return &callback{userHeader: userHeader, groupHeader: groupHeader, logger: logger, pathSuffix: "/" + id, groups: c.Groups}, nil
}
// Callback is a connector which returns an identity with the HTTP header
// X-Remote-User as verified email.
type callback struct {
userHeader string
groupHeader string
groups []string
logger log.Logger
pathSuffix string
}
// LoginURL returns the URL to redirect the user to login with.
func (m *callback) LoginURL(s connector.Scopes, callbackURL, state string) (string, error) {
u, err := url.Parse(callbackURL)
if err != nil {
return "", fmt.Errorf("failed to parse callbackURL %q: %v", callbackURL, err)
}
u.Path += m.pathSuffix
v := u.Query()
v.Set("state", state)
u.RawQuery = v.Encode()
return u.String(), nil
}
// HandleCallback parses the request and returns the user's identity
func (m *callback) HandleCallback(s connector.Scopes, r *http.Request) (connector.Identity, error) {
remoteUser := r.Header.Get(m.userHeader)
if remoteUser == "" {
return connector.Identity{}, fmt.Errorf("required HTTP header %s is not set", m.userHeader)
}
groups := m.groups
headerGroup := r.Header.Get(m.groupHeader)
if headerGroup != "" {
groups = append(groups, headerGroup)
}
return connector.Identity{
UserID: remoteUser, // TODO: figure out if this is a bad ID value.
Email: remoteUser,
EmailVerified: true,
Groups: groups,
}, nil
}

View File

@ -0,0 +1,468 @@
// Package bitbucketcloud provides authentication strategies using Bitbucket Cloud.
package bitbucketcloud
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"sync"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/bitbucket"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
)
const (
apiURL = "https://api.bitbucket.org/2.0"
// Switch to API v2.0 when the Atlassian platform services are fully available in Bitbucket
legacyAPIURL = "https://api.bitbucket.org/1.0"
// Bitbucket requires this scope to access '/user' API endpoints.
scopeAccount = "account"
// Bitbucket requires this scope to access '/user/emails' API endpoints.
scopeEmail = "email"
// Bitbucket requires this scope to access '/teams' API endpoints
// which are used when a client includes the 'groups' scope.
scopeTeams = "team"
)
// Config holds configuration options for Bitbucket logins.
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Teams []string `json:"teams"`
IncludeTeamGroups bool `json:"includeTeamGroups,omitempty"`
}
// Open returns a strategy for logging in through Bitbucket.
func (c *Config) Open(_ string, logger log.Logger) (connector.Connector, error) {
b := bitbucketConnector{
redirectURI: c.RedirectURI,
teams: c.Teams,
clientID: c.ClientID,
clientSecret: c.ClientSecret,
includeTeamGroups: c.IncludeTeamGroups,
apiURL: apiURL,
legacyAPIURL: legacyAPIURL,
logger: logger,
}
return &b, nil
}
type connectorData struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
Expiry time.Time `json:"expiry"`
}
var (
_ connector.CallbackConnector = (*bitbucketConnector)(nil)
_ connector.RefreshConnector = (*bitbucketConnector)(nil)
)
type bitbucketConnector struct {
redirectURI string
teams []string
clientID string
clientSecret string
logger log.Logger
apiURL string
legacyAPIURL string
// the following are used only for tests
hostName string
httpClient *http.Client
includeTeamGroups bool
}
// groupsRequired returns whether dex requires Bitbucket's 'team' scope.
func (b *bitbucketConnector) groupsRequired(groupScope bool) bool {
return len(b.teams) > 0 || groupScope
}
func (b *bitbucketConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
bitbucketScopes := []string{scopeAccount, scopeEmail}
if b.groupsRequired(scopes.Groups) {
bitbucketScopes = append(bitbucketScopes, scopeTeams)
}
endpoint := bitbucket.Endpoint
if b.hostName != "" {
endpoint = oauth2.Endpoint{
AuthURL: "https://" + b.hostName + "/site/oauth2/authorize",
TokenURL: "https://" + b.hostName + "/site/oauth2/access_token",
}
}
return &oauth2.Config{
ClientID: b.clientID,
ClientSecret: b.clientSecret,
Endpoint: endpoint,
Scopes: bitbucketScopes,
}
}
func (b *bitbucketConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
if b.redirectURI != callbackURL {
return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", callbackURL, b.redirectURI)
}
return b.oauth2Config(scopes).AuthCodeURL(state), nil
}
type oauth2Error struct {
error string
errorDescription string
}
func (e *oauth2Error) Error() string {
if e.errorDescription == "" {
return e.error
}
return e.error + ": " + e.errorDescription
}
func (b *bitbucketConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
q := r.URL.Query()
if errType := q.Get("error"); errType != "" {
return identity, &oauth2Error{errType, q.Get("error_description")}
}
oauth2Config := b.oauth2Config(s)
ctx := r.Context()
if b.httpClient != nil {
ctx = context.WithValue(r.Context(), oauth2.HTTPClient, b.httpClient)
}
token, err := oauth2Config.Exchange(ctx, q.Get("code"))
if err != nil {
return identity, fmt.Errorf("bitbucket: failed to get token: %v", err)
}
client := oauth2Config.Client(ctx, token)
user, err := b.user(ctx, client)
if err != nil {
return identity, fmt.Errorf("bitbucket: get user: %v", err)
}
identity = connector.Identity{
UserID: user.UUID,
Username: user.Username,
Email: user.Email,
EmailVerified: true,
}
if b.groupsRequired(s.Groups) {
groups, err := b.getGroups(ctx, client, s.Groups, user.Username)
if err != nil {
return identity, err
}
identity.Groups = groups
}
if s.OfflineAccess {
data := connectorData{
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
Expiry: token.Expiry,
}
connData, err := json.Marshal(data)
if err != nil {
return identity, fmt.Errorf("bitbucket: marshal connector data: %v", err)
}
identity.ConnectorData = connData
}
return identity, nil
}
// Refreshing tokens
// https://github.com/golang/oauth2/issues/84#issuecomment-332860871
type tokenNotifyFunc func(*oauth2.Token) error
// notifyRefreshTokenSource is essentially `oauth2.ReuseTokenSource` with `TokenNotifyFunc` added.
type notifyRefreshTokenSource struct {
new oauth2.TokenSource
mu sync.Mutex // guards t
t *oauth2.Token
f tokenNotifyFunc // called when token refreshed so new refresh token can be persisted
}
// Token returns the current token if it's still valid, else will
// refresh the current token (using r.Context for HTTP client
// information) and return the new one.
func (s *notifyRefreshTokenSource) Token() (*oauth2.Token, error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.t.Valid() {
return s.t, nil
}
t, err := s.new.Token()
if err != nil {
return nil, err
}
s.t = t
return t, s.f(t)
}
func (b *bitbucketConnector) Refresh(ctx context.Context, s connector.Scopes, identity connector.Identity) (connector.Identity, error) {
if len(identity.ConnectorData) == 0 {
return identity, errors.New("bitbucket: no upstream access token found")
}
var data connectorData
if err := json.Unmarshal(identity.ConnectorData, &data); err != nil {
return identity, fmt.Errorf("bitbucket: unmarshal access token: %v", err)
}
tok := &oauth2.Token{
AccessToken: data.AccessToken,
RefreshToken: data.RefreshToken,
Expiry: data.Expiry,
}
client := oauth2.NewClient(ctx, &notifyRefreshTokenSource{
new: b.oauth2Config(s).TokenSource(ctx, tok),
t: tok,
f: func(tok *oauth2.Token) error {
data := connectorData{
AccessToken: tok.AccessToken,
RefreshToken: tok.RefreshToken,
Expiry: tok.Expiry,
}
connData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("bitbucket: marshal connector data: %v", err)
}
identity.ConnectorData = connData
return nil
},
})
user, err := b.user(ctx, client)
if err != nil {
return identity, fmt.Errorf("bitbucket: get user: %v", err)
}
identity.Username = user.Username
identity.Email = user.Email
if b.groupsRequired(s.Groups) {
groups, err := b.getGroups(ctx, client, s.Groups, user.Username)
if err != nil {
return identity, err
}
identity.Groups = groups
}
return identity, nil
}
// Bitbucket pagination wrapper
type pagedResponse struct {
Size int `json:"size"`
Page int `json:"page"`
PageLen int `json:"pagelen"`
Next *string `json:"next"`
Previous *string `json:"previous"`
}
// user holds Bitbucket user information (relevant to dex) as defined by
// https://developer.atlassian.com/bitbucket/api/2/reference/resource/user
type user struct {
Username string `json:"username"`
UUID string `json:"uuid"`
Email string `json:"email"`
}
// user queries the Bitbucket API for profile information using the provided client.
//
// The HTTP client is expected to be constructed by the golang.org/x/oauth2 package,
// which inserts a bearer token as part of the request.
func (b *bitbucketConnector) user(ctx context.Context, client *http.Client) (user, error) {
// https://developer.atlassian.com/bitbucket/api/2/reference/resource/user
var (
u user
err error
)
if err = get(ctx, client, b.apiURL+"/user", &u); err != nil {
return user{}, err
}
if u.Email, err = b.userEmail(ctx, client); err != nil {
return user{}, err
}
return u, nil
}
// userEmail holds Bitbucket user email information as defined by
// https://developer.atlassian.com/bitbucket/api/2/reference/resource/user/emails
type userEmail struct {
IsPrimary bool `json:"is_primary"`
IsConfirmed bool `json:"is_confirmed"`
Email string `json:"email"`
}
type userEmailResponse struct {
pagedResponse
Values []userEmail
}
// userEmail returns the users primary, confirmed email
//
// The HTTP client is expected to be constructed by the golang.org/x/oauth2 package,
// which inserts a bearer token as part of the request.
func (b *bitbucketConnector) userEmail(ctx context.Context, client *http.Client) (string, error) {
apiURL := b.apiURL + "/user/emails"
for {
// https://developer.atlassian.com/bitbucket/api/2/reference/resource/user/emails
var response userEmailResponse
if err := get(ctx, client, apiURL, &response); err != nil {
return "", err
}
for _, email := range response.Values {
if email.IsConfirmed && email.IsPrimary {
return email.Email, nil
}
}
if response.Next == nil {
break
}
}
return "", errors.New("bitbucket: user has no confirmed, primary email")
}
// getGroups retrieves Bitbucket teams a user is in, if any.
func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) ([]string, error) {
bitbucketTeams, err := b.userWorkspaces(ctx, client)
if err != nil {
return nil, err
}
if len(b.teams) > 0 {
filteredTeams := groups.Filter(bitbucketTeams, b.teams)
if len(filteredTeams) == 0 {
return nil, fmt.Errorf("bitbucket: user %q is not in any of the required teams", userLogin)
}
return filteredTeams, nil
} else if groupScope {
return bitbucketTeams, nil
}
return nil, nil
}
type workspaceSlug struct {
Slug string `json:"slug"`
}
type workspace struct {
Workspace workspaceSlug `json:"workspace"`
}
type userWorkspacesResponse struct {
pagedResponse
Values []workspace `json:"values"`
}
func (b *bitbucketConnector) userWorkspaces(ctx context.Context, client *http.Client) ([]string, error) {
var teams []string
apiURL := b.apiURL + "/user/permissions/workspaces"
for {
// https://developer.atlassian.com/cloud/bitbucket/rest/api-group-workspaces/#api-workspaces-get
var response userWorkspacesResponse
if err := get(ctx, client, apiURL, &response); err != nil {
return nil, fmt.Errorf("bitbucket: get user teams: %v", err)
}
for _, value := range response.Values {
teams = append(teams, value.Workspace.Slug)
}
if response.Next == nil {
break
}
}
if b.includeTeamGroups {
for _, team := range teams {
teamGroups, err := b.userTeamGroups(ctx, client, team)
if err != nil {
return nil, fmt.Errorf("bitbucket: %v", err)
}
teams = append(teams, teamGroups...)
}
}
return teams, nil
}
type group struct {
Slug string `json:"slug"`
}
func (b *bitbucketConnector) userTeamGroups(ctx context.Context, client *http.Client, teamName string) ([]string, error) {
apiURL := b.legacyAPIURL + "/groups/" + teamName
var response []group
if err := get(ctx, client, apiURL, &response); err != nil {
return nil, fmt.Errorf("get user team %q groups: %v", teamName, err)
}
teamGroups := make([]string, 0, len(response))
for _, group := range response {
teamGroups = append(teamGroups, teamName+"/"+group.Slug)
}
return teamGroups, nil
}
// get creates a "GET `apiURL`" request with context, sends the request using
// the client, and decodes the resulting response body into v.
// Any errors encountered when building requests, sending requests, and
// reading and decoding response data are returned.
func get(ctx context.Context, client *http.Client, apiURL string, v interface{}) error {
req, err := http.NewRequest("GET", apiURL, nil)
if err != nil {
return fmt.Errorf("bitbucket: new req: %v", err)
}
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("bitbucket: get URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("bitbucket: read body: %s: %v", resp.Status, err)
}
return fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
return fmt.Errorf("bitbucket: failed to decode response: %v", err)
}
return nil
}

View File

@ -0,0 +1,137 @@
package bitbucketcloud
import (
"context"
"crypto/tls"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"
"github.com/dexidp/dex/connector"
)
func TestUserGroups(t *testing.T) {
teamsResponse := userWorkspacesResponse{
pagedResponse: pagedResponse{
Size: 3,
Page: 1,
PageLen: 10,
},
Values: []workspace{
{Workspace: workspaceSlug{Slug: "team-1"}},
{Workspace: workspaceSlug{Slug: "team-2"}},
{Workspace: workspaceSlug{Slug: "team-3"}},
},
}
s := newTestServer(map[string]interface{}{
"/user/permissions/workspaces": teamsResponse,
"/groups/team-1": []group{{Slug: "administrators"}, {Slug: "members"}},
"/groups/team-2": []group{{Slug: "everyone"}},
"/groups/team-3": []group{},
})
connector := bitbucketConnector{apiURL: s.URL, legacyAPIURL: s.URL}
groups, err := connector.userWorkspaces(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, groups, []string{
"team-1",
"team-2",
"team-3",
})
connector.includeTeamGroups = true
groups, err = connector.userWorkspaces(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, groups, []string{
"team-1",
"team-2",
"team-3",
"team-1/administrators",
"team-1/members",
"team-2/everyone",
})
s.Close()
}
func TestUserWithoutTeams(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/user/permissions/workspaces": userWorkspacesResponse{},
})
connector := bitbucketConnector{apiURL: s.URL}
groups, err := connector.userWorkspaces(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, len(groups), 0)
s.Close()
}
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/user": user{Username: "some-login"},
"/user/emails": userEmailResponse{
pagedResponse: pagedResponse{
Size: 1,
Page: 1,
PageLen: 10,
},
Values: []userEmail{{
Email: "some@email.com",
IsConfirmed: true,
IsPrimary: true,
}},
},
"/site/oauth2/access_token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
},
})
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
bitbucketConnector := bitbucketConnector{apiURL: s.URL, hostName: hostURL.Host, httpClient: newClient()}
identity, err := bitbucketConnector.HandleCallback(connector.Scopes{}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some-login")
s.Close()
}
func newTestServer(responses map[string]interface{}) *httptest.Server {
return httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(responses[r.URL.String()])
}))
}
func newClient() *http.Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return &http.Client{Transport: tr}
}
func expectNil(t *testing.T, a interface{}) {
if a != nil {
t.Fatalf("Expected %+v to equal nil", a)
}
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Fatalf("Expected %+v to equal %+v", a, b)
}
}

View File

@ -23,10 +23,11 @@ type Scopes struct {
// Identity represents the ID Token claims supported by the server.
type Identity struct {
UserID string
Username string
Email string
EmailVerified bool
UserID string
Username string
PreferredUsername string
Email string
EmailVerified bool
Groups []string
@ -39,7 +40,10 @@ type Identity struct {
// PasswordConnector is an interface implemented by connectors which take a
// username and password.
// Prompt() is used to inform the handler what to display in the password
// template. If this returns an empty string, it'll default to "Username".
type PasswordConnector interface {
Prompt() string
Login(ctx context.Context, s Scopes, username, password string) (identity Identity, validPassword bool, err error)
}
@ -76,7 +80,7 @@ type SAMLConnector interface {
//
// POSTData should encode the provided request ID in the returned serialized
// SAML request.
POSTData(s Scopes, requestID string) (sooURL, samlRequest string, err error)
POSTData(s Scopes, requestID string) (ssoURL, samlRequest string, err error)
// HandlePOST decodes, verifies, and maps attributes from the SAML response.
// It passes the expected value of the "InResponseTo" response field, which

424
connector/gitea/gitea.go Normal file
View File

@ -0,0 +1,424 @@
// Package gitea provides authentication strategies using Gitea.
package gitea
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"sync"
"time"
"golang.org/x/oauth2"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
// Config holds configuration options for gitea logins.
type Config struct {
BaseURL string `json:"baseURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Orgs []Org `json:"orgs"`
LoadAllGroups bool `json:"loadAllGroups"`
UseLoginAsID bool `json:"useLoginAsID"`
}
// Org holds org-team filters, in which teams are optional.
type Org struct {
// Organization name in gitea (not slug, full name). Only users in this gitea
// organization can authenticate.
Name string `json:"name"`
// Names of teams in a gitea organization. A user will be able to
// authenticate if they are members of at least one of these teams. Users
// in the organization can authenticate if this field is omitted from the
// config file.
Teams []string `json:"teams,omitempty"`
}
type giteaUser struct {
ID int `json:"id"`
Name string `json:"full_name"`
Username string `json:"login"`
Email string `json:"email"`
IsAdmin bool `json:"is_admin"`
}
// Open returns a strategy for logging in through Gitea
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
if c.BaseURL == "" {
c.BaseURL = "https://gitea.com"
}
return &giteaConnector{
baseURL: c.BaseURL,
redirectURI: c.RedirectURI,
orgs: c.Orgs,
clientID: c.ClientID,
clientSecret: c.ClientSecret,
logger: logger,
loadAllGroups: c.LoadAllGroups,
useLoginAsID: c.UseLoginAsID,
}, nil
}
type connectorData struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
Expiry time.Time `json:"expiry"`
}
var (
_ connector.CallbackConnector = (*giteaConnector)(nil)
_ connector.RefreshConnector = (*giteaConnector)(nil)
)
type giteaConnector struct {
baseURL string
redirectURI string
orgs []Org
clientID string
clientSecret string
logger log.Logger
httpClient *http.Client
// if set to true and no orgs are configured then connector loads all user claims (all orgs and team)
loadAllGroups bool
// if set to true will use the user's handle rather than their numeric id as the ID
useLoginAsID bool
}
func (c *giteaConnector) oauth2Config(_ connector.Scopes) *oauth2.Config {
giteaEndpoint := oauth2.Endpoint{AuthURL: c.baseURL + "/login/oauth/authorize", TokenURL: c.baseURL + "/login/oauth/access_token"}
return &oauth2.Config{
ClientID: c.clientID,
ClientSecret: c.clientSecret,
Endpoint: giteaEndpoint,
RedirectURL: c.redirectURI,
}
}
func (c *giteaConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
if c.redirectURI != callbackURL {
return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", c.redirectURI, callbackURL)
}
return c.oauth2Config(scopes).AuthCodeURL(state), nil
}
type oauth2Error struct {
error string
errorDescription string
}
func (e *oauth2Error) Error() string {
if e.errorDescription == "" {
return e.error
}
return e.error + ": " + e.errorDescription
}
func (c *giteaConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
q := r.URL.Query()
if errType := q.Get("error"); errType != "" {
return identity, &oauth2Error{errType, q.Get("error_description")}
}
oauth2Config := c.oauth2Config(s)
ctx := r.Context()
if c.httpClient != nil {
ctx = context.WithValue(r.Context(), oauth2.HTTPClient, c.httpClient)
}
token, err := oauth2Config.Exchange(ctx, q.Get("code"))
if err != nil {
return identity, fmt.Errorf("gitea: failed to get token: %v", err)
}
client := oauth2Config.Client(ctx, token)
user, err := c.user(ctx, client)
if err != nil {
return identity, fmt.Errorf("gitea: get user: %v", err)
}
username := user.Name
if username == "" {
username = user.Email
}
identity = connector.Identity{
UserID: strconv.Itoa(user.ID),
Username: username,
PreferredUsername: user.Username,
Email: user.Email,
EmailVerified: true,
}
if c.useLoginAsID {
identity.UserID = user.Username
}
// Only set identity.Groups if 'orgs', 'org', or 'groups' scope are specified.
if c.groupsRequired() {
groups, err := c.getGroups(ctx, client)
if err != nil {
return identity, err
}
identity.Groups = groups
}
if s.OfflineAccess {
data := connectorData{
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
Expiry: token.Expiry,
}
connData, err := json.Marshal(data)
if err != nil {
return identity, fmt.Errorf("gitea: marshal connector data: %v", err)
}
identity.ConnectorData = connData
}
return identity, nil
}
// Refreshing tokens
// https://github.com/golang/oauth2/issues/84#issuecomment-332860871
type tokenNotifyFunc func(*oauth2.Token) error
// notifyRefreshTokenSource is essentially `oauth2.ReuseTokenSource` with `TokenNotifyFunc` added.
type notifyRefreshTokenSource struct {
new oauth2.TokenSource
mu sync.Mutex // guards t
t *oauth2.Token
f tokenNotifyFunc // called when token refreshed so new refresh token can be persisted
}
// Token returns the current token if it's still valid, else will
// refresh the current token (using r.Context for HTTP client
// information) and return the new one.
func (s *notifyRefreshTokenSource) Token() (*oauth2.Token, error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.t.Valid() {
return s.t, nil
}
t, err := s.new.Token()
if err != nil {
return nil, err
}
s.t = t
return t, s.f(t)
}
func (c *giteaConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
if len(ident.ConnectorData) == 0 {
return ident, errors.New("gitea: no upstream access token found")
}
var data connectorData
if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
return ident, fmt.Errorf("gitea: unmarshal access token: %v", err)
}
tok := &oauth2.Token{
AccessToken: data.AccessToken,
RefreshToken: data.RefreshToken,
Expiry: data.Expiry,
}
client := oauth2.NewClient(ctx, &notifyRefreshTokenSource{
new: c.oauth2Config(s).TokenSource(ctx, tok),
t: tok,
f: func(tok *oauth2.Token) error {
data := connectorData{
AccessToken: tok.AccessToken,
RefreshToken: tok.RefreshToken,
Expiry: tok.Expiry,
}
connData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("gitea: marshal connector data: %v", err)
}
ident.ConnectorData = connData
return nil
},
})
user, err := c.user(ctx, client)
if err != nil {
return ident, fmt.Errorf("gitea: get user: %v", err)
}
username := user.Name
if username == "" {
username = user.Email
}
ident.Username = username
ident.PreferredUsername = user.Username
ident.Email = user.Email
// Only set identity.Groups if 'orgs', 'org', or 'groups' scope are specified.
if c.groupsRequired() {
groups, err := c.getGroups(ctx, client)
if err != nil {
return ident, err
}
ident.Groups = groups
}
return ident, nil
}
// getGroups retrieves Gitea orgs and teams a user is in, if any.
func (c *giteaConnector) getGroups(ctx context.Context, client *http.Client) ([]string, error) {
if len(c.orgs) > 0 {
return c.groupsForOrgs(ctx, client)
} else if c.loadAllGroups {
return c.userGroups(ctx, client)
}
return nil, nil
}
// formatTeamName returns unique team name.
// Orgs might have the same team names. To make team name unique it should be prefixed with the org name.
func formatTeamName(org string, team string) string {
return fmt.Sprintf("%s:%s", org, team)
}
// groupsForOrgs returns list of groups that user belongs to in approved list
func (c *giteaConnector) groupsForOrgs(ctx context.Context, client *http.Client) ([]string, error) {
groups, err := c.userGroups(ctx, client)
if err != nil {
return groups, err
}
keys := make(map[string]bool)
for _, o := range c.orgs {
keys[o.Name] = true
if o.Teams != nil {
for _, t := range o.Teams {
keys[formatTeamName(o.Name, t)] = true
}
}
}
atLeastOne := false
filteredGroups := make([]string, 0)
for _, g := range groups {
if _, value := keys[g]; value {
filteredGroups = append(filteredGroups, g)
atLeastOne = true
}
}
if !atLeastOne {
return []string{}, fmt.Errorf("gitea: User does not belong to any of the approved groups")
}
return filteredGroups, nil
}
type organization struct {
ID int64 `json:"id"`
Name string `json:"username"`
}
type team struct {
ID int64 `json:"id"`
Name string `json:"name"`
Organization *organization `json:"organization"`
}
func (c *giteaConnector) userGroups(ctx context.Context, client *http.Client) ([]string, error) {
apiURL := c.baseURL + "/api/v1/user/teams"
groups := make([]string, 0)
page := 1
limit := 20
for {
var teams []team
req, err := http.NewRequest("GET", fmt.Sprintf("%s?page=%d&limit=%d", apiURL, page, limit), nil)
if err != nil {
return groups, fmt.Errorf("gitea: new req: %v", err)
}
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
return groups, fmt.Errorf("gitea: get URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return groups, fmt.Errorf("gitea: read body: %v", err)
}
return groups, fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.NewDecoder(resp.Body).Decode(&teams); err != nil {
return groups, fmt.Errorf("failed to decode response: %v", err)
}
if len(teams) == 0 {
break
}
for _, t := range teams {
groups = append(groups, t.Organization.Name)
groups = append(groups, formatTeamName(t.Organization.Name, t.Name))
}
page++
}
// remove duplicate slice variables
keys := make(map[string]struct{})
list := []string{}
for _, group := range groups {
if _, exists := keys[group]; !exists {
keys[group] = struct{}{}
list = append(list, group)
}
}
groups = list
return groups, nil
}
// user queries the Gitea API for profile information using the provided client. The HTTP
// client is expected to be constructed by the golang.org/x/oauth2 package, which inserts
// a bearer token as part of the request.
func (c *giteaConnector) user(ctx context.Context, client *http.Client) (giteaUser, error) {
var u giteaUser
req, err := http.NewRequest("GET", c.baseURL+"/api/v1/user", nil)
if err != nil {
return u, fmt.Errorf("gitea: new req: %v", err)
}
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
return u, fmt.Errorf("gitea: get URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return u, fmt.Errorf("gitea: read body: %v", err)
}
return u, fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {
return u, fmt.Errorf("failed to decode response: %v", err)
}
return u, nil
}
// groupsRequired returns whether dex needs to request groups from Gitea.
func (c *giteaConnector) groupsRequired() bool {
return len(c.orgs) > 0 || c.loadAllGroups
}

View File

@ -0,0 +1,72 @@
package gitea
import (
"crypto/tls"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"
"github.com/dexidp/dex/connector"
)
// tests that the email is used as their username when they have no username set
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v1/user": giteaUser{Email: "some@email.com", ID: 12345678},
"/login/oauth/access_token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := giteaConnector{baseURL: s.URL, httpClient: newClient()}
identity, err := c.HandleCallback(connector.Scopes{}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some@email.com")
expectEquals(t, identity.UserID, "12345678")
c = giteaConnector{baseURL: s.URL, httpClient: newClient()}
identity, err = c.HandleCallback(connector.Scopes{}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some@email.com")
expectEquals(t, identity.UserID, "12345678")
}
func newTestServer(responses map[string]interface{}) *httptest.Server {
return httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := responses[r.RequestURI]
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}))
}
func newClient() *http.Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return &http.Client{Transport: tr}
}
func expectNil(t *testing.T, a interface{}) {
if a != nil {
t.Errorf("Expected %+v to equal nil", a)
}
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("Expected %+v to equal %+v", a, b)
}
}

View File

@ -8,9 +8,10 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
"os"
"regexp"
"strconv"
"strings"
@ -19,35 +20,43 @@ import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/github"
"github.com/coreos/dex/connector"
"github.com/sirupsen/logrus"
"github.com/dexidp/dex/connector"
groups_pkg "github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
)
const (
apiURL = "https://api.github.com"
apiURL = "https://api.github.com"
// GitHub requires this scope to access '/user' and '/user/emails' API endpoints.
scopeEmail = "user:email"
scopeOrgs = "read:org"
// GitHub requires this scope to access '/user/teams' and '/orgs' API endpoints
// which are used when a client includes the 'groups' scope.
scopeOrgs = "read:org"
)
// Pagination URL patterns
// https://developer.github.com/v3/#pagination
var reNext = regexp.MustCompile("<([^>]+)>; rel=\"next\"")
var reLast = regexp.MustCompile("<([^>]+)>; rel=\"last\"")
var (
reNext = regexp.MustCompile("<([^>]+)>; rel=\"next\"")
reLast = regexp.MustCompile("<([^>]+)>; rel=\"last\"")
)
// Config holds configuration options for github logins.
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Org string `json:"org"`
Orgs []Org `json:"orgs"`
HostName string `json:"hostName"`
RootCA string `json:"rootCA"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Org string `json:"org"`
Orgs []Org `json:"orgs"`
HostName string `json:"hostName"`
RootCA string `json:"rootCA"`
TeamNameField string `json:"teamNameField"`
LoadAllGroups bool `json:"loadAllGroups"`
UseLoginAsID bool `json:"useLoginAsID"`
}
// Org holds org-team filters, in which teams are optional.
type Org struct {
// Organization name in github (not slug, full name). Only users in this github
// organization can authenticate.
Name string `json:"name"`
@ -60,14 +69,13 @@ type Org struct {
}
// Open returns a strategy for logging in through GitHub.
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
if c.Org != "" {
// Return error if both 'org' and 'orgs' fields are used.
if len(c.Orgs) > 0 {
return nil, errors.New("github: cannot use both 'org' and 'orgs' fields simultaneously")
}
logger.Warnln("github: legacy field 'org' being used. Switch to the newer 'orgs' field structure")
logger.Warn("github: legacy field 'org' being used. Switch to the newer 'orgs' field structure")
}
g := githubConnector{
@ -78,6 +86,7 @@ func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
clientSecret: c.ClientSecret,
apiURL: apiURL,
logger: logger,
useLoginAsID: c.UseLoginAsID,
}
if c.HostName != "" {
@ -100,7 +109,14 @@ func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
if g.httpClient, err = newHTTPClient(g.rootCA); err != nil {
return nil, fmt.Errorf("failed to create HTTP client: %v", err)
}
}
g.loadAllGroups = c.LoadAllGroups
switch c.TeamNameField {
case "name", "slug", "both", "":
g.teamNameField = c.TeamNameField
default:
return nil, fmt.Errorf("invalid connector config: unsupported team name field value `%s`", c.TeamNameField)
}
return &g, nil
@ -122,27 +138,39 @@ type githubConnector struct {
orgs []Org
clientID string
clientSecret string
logger logrus.FieldLogger
logger log.Logger
// apiURL defaults to "https://api.github.com"
apiURL string
// hostName of the GitHub enterprise account.
hostName string
// Used to support untrusted/self-signed CA certs.
rootCA string
// HTTP Client that trusts the custom delcared rootCA cert.
// HTTP Client that trusts the custom declared rootCA cert.
httpClient *http.Client
// optional choice between 'name' (default) or 'slug'
teamNameField string
// if set to true and no orgs are configured then connector loads all user claims (all orgs and team)
loadAllGroups bool
// if set to true will use the user's handle rather than their numeric id as the ID
useLoginAsID bool
}
// groupsRequired returns whether dex requires GitHub's 'read:org' scope. Dex
// needs 'read:org' if 'orgs' or 'org' fields are populated in a config file.
// Clients can require 'groups' scope without setting 'orgs'/'org'.
func (c *githubConnector) groupsRequired(groupScope bool) bool {
return len(c.orgs) > 0 || c.org != "" || groupScope
}
func (c *githubConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
var githubScopes []string
if scopes.Groups {
githubScopes = []string{scopeEmail, scopeOrgs}
} else {
githubScopes = []string{scopeEmail}
// 'read:org' scope is required by the GitHub API, and thus for dex to ensure
// a user is a member of orgs and teams provided in configs.
githubScopes := []string{scopeEmail}
if c.groupsRequired(scopes.Groups) {
githubScopes = append(githubScopes, scopeOrgs)
}
endpoint := github.Endpoint
// case when it is a GitHub Enterprise account.
if c.hostName != "" {
endpoint = oauth2.Endpoint{
@ -156,6 +184,7 @@ func (c *githubConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
ClientSecret: c.clientSecret,
Endpoint: endpoint,
Scopes: githubScopes,
RedirectURL: c.redirectURI,
}
}
@ -179,10 +208,10 @@ func (e *oauth2Error) Error() string {
return e.error + ": " + e.errorDescription
}
// newHTTPClient returns a new HTTP client that trusts the custom delcared rootCA cert.
// newHTTPClient returns a new HTTP client that trusts the custom declared rootCA cert.
func newHTTPClient(rootCA string) (*http.Client, error) {
tlsConfig := tls.Config{RootCAs: x509.NewCertPool()}
rootCABytes, err := ioutil.ReadFile(rootCA)
rootCABytes, err := os.ReadFile(rootCA)
if err != nil {
return nil, fmt.Errorf("failed to read root-ca: %v", err)
}
@ -237,30 +266,23 @@ func (c *githubConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
if username == "" {
username = user.Login
}
identity = connector.Identity{
UserID: strconv.Itoa(user.ID),
Username: username,
Email: user.Email,
EmailVerified: true,
UserID: strconv.Itoa(user.ID),
Username: username,
PreferredUsername: user.Login,
Email: user.Email,
EmailVerified: true,
}
if c.useLoginAsID {
identity.UserID = user.Login
}
if s.Groups {
var groups []string
if len(c.orgs) > 0 {
if groups, err = c.listGroups(ctx, client, username); err != nil {
return identity, err
}
} else if c.org != "" {
inOrg, err := c.userInOrg(ctx, client, username, c.org)
if err != nil {
return identity, err
}
if !inOrg {
return identity, fmt.Errorf("github: user %q not a member of org %q", username, c.org)
}
if groups, err = c.teams(ctx, client, c.org); err != nil {
return identity, fmt.Errorf("github: get teams: %v", err)
}
// Only set identity.Groups if 'orgs', 'org', or 'groups' scope are specified.
if c.groupsRequired(s.Groups) {
groups, err := c.getGroups(ctx, client, s.Groups, user.Login)
if err != nil {
return identity, err
}
identity.Groups = groups
}
@ -298,25 +320,14 @@ func (c *githubConnector) Refresh(ctx context.Context, s connector.Scopes, ident
username = user.Login
}
identity.Username = username
identity.PreferredUsername = user.Login
identity.Email = user.Email
if s.Groups {
var groups []string
if len(c.orgs) > 0 {
if groups, err = c.listGroups(ctx, client, username); err != nil {
return identity, err
}
} else if c.org != "" {
inOrg, err := c.userInOrg(ctx, client, username, c.org)
if err != nil {
return identity, err
}
if !inOrg {
return identity, fmt.Errorf("github: user %q not a member of org %q", username, c.org)
}
if groups, err = c.teams(ctx, client, c.org); err != nil {
return identity, fmt.Errorf("github: get teams: %v", err)
}
// Only set identity.Groups if 'orgs', 'org', or 'groups' scope are specified.
if c.groupsRequired(s.Groups) {
groups, err := c.getGroups(ctx, client, s.Groups, user.Login)
if err != nil {
return identity, err
}
identity.Groups = groups
}
@ -324,65 +335,141 @@ func (c *githubConnector) Refresh(ctx context.Context, s connector.Scopes, ident
return identity, nil
}
// listGroups enforces org and team constraints on user authorization
// getGroups retrieves GitHub orgs and teams a user is in, if any.
func (c *githubConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) ([]string, error) {
switch {
case len(c.orgs) > 0:
return c.groupsForOrgs(ctx, client, userLogin)
case c.org != "":
return c.teamsForOrg(ctx, client, c.org)
case groupScope && c.loadAllGroups:
return c.userGroups(ctx, client)
}
return nil, nil
}
// formatTeamName returns unique team name.
// Orgs might have the same team names. To make team name unique it should be prefixed with the org name.
func formatTeamName(org string, team string) string {
return fmt.Sprintf("%s:%s", org, team)
}
// groupsForOrgs enforces org and team constraints on user authorization
// Cases in which user is authorized:
// N orgs, no teams: user is member of at least 1 org
// N orgs, M teams per org: user is member of any team from at least 1 org
// N-1 orgs, M teams per org, 1 org with no teams: user is member of any team
// from at least 1 org, or member of org with no teams
func (c *githubConnector) listGroups(ctx context.Context, client *http.Client, userName string) (groups []string, err error) {
func (c *githubConnector) groupsForOrgs(ctx context.Context, client *http.Client, userName string) ([]string, error) {
groups := make([]string, 0)
var inOrgNoTeams bool
for _, org := range c.orgs {
inOrg, err := c.userInOrg(ctx, client, userName, org.Name)
if err != nil {
return groups, err
return nil, err
}
if !inOrg {
continue
}
teams, err := c.teams(ctx, client, org.Name)
teams, err := c.teamsForOrg(ctx, client, org.Name)
if err != nil {
return groups, err
return nil, err
}
// User is in at least one org. User is authorized if no teams are specified
// in config; include all teams in claim. Otherwise filter out teams not in
// 'teams' list in config.
if len(org.Teams) == 0 {
inOrgNoTeams = true
c.logger.Debugf("github: user %q in org %q", userName, org.Name)
} else if teams = filterTeams(teams, org.Teams); len(teams) == 0 {
c.logger.Debugf("github: user %q in org %q but no teams", userName, org.Name)
} else if teams = groups_pkg.Filter(teams, org.Teams); len(teams) == 0 {
c.logger.Infof("github: user %q in org %q but no teams", userName, org.Name)
}
// Orgs might have the same team names. We append orgPrefix to team name,
// i.e. "org:team", to make team names unique across orgs.
orgPrefix := org.Name + ":"
for _, teamName := range teams {
groups = append(groups, orgPrefix+teamName)
c.logger.Debugf("github: user %q in org %q team %q", userName, org.Name, teamName)
groups = append(groups, formatTeamName(org.Name, teamName))
}
}
if inOrgNoTeams || len(groups) > 0 {
return
return groups, nil
}
return groups, fmt.Errorf("github: user %q not in required orgs or teams", userName)
}
// Filter the users' team memberships by 'teams' from config.
func filterTeams(userTeams, configTeams []string) (teams []string) {
teamFilter := make(map[string]struct{})
for _, team := range configTeams {
if _, ok := teamFilter[team]; !ok {
teamFilter[team] = struct{}{}
func (c *githubConnector) userGroups(ctx context.Context, client *http.Client) ([]string, error) {
orgs, err := c.userOrgs(ctx, client)
if err != nil {
return nil, err
}
orgTeams, err := c.userOrgTeams(ctx, client)
if err != nil {
return nil, err
}
groups := make([]string, 0)
for _, o := range orgs {
groups = append(groups, o)
if teams, ok := orgTeams[o]; ok {
for _, t := range teams {
groups = append(groups, formatTeamName(o, t))
}
}
}
for _, team := range userTeams {
if _, ok := teamFilter[team]; ok {
teams = append(teams, team)
return groups, nil
}
// userOrgs retrieves list of current user orgs
func (c *githubConnector) userOrgs(ctx context.Context, client *http.Client) ([]string, error) {
groups := make([]string, 0)
apiURL := c.apiURL + "/user/orgs"
for {
// https://developer.github.com/v3/orgs/#list-your-organizations
var (
orgs []org
err error
)
if apiURL, err = get(ctx, client, apiURL, &orgs); err != nil {
return nil, fmt.Errorf("github: get orgs: %v", err)
}
for _, o := range orgs {
groups = append(groups, o.Login)
}
if apiURL == "" {
break
}
}
return
return groups, nil
}
// userOrgTeams retrieves teams which current user belongs to.
// Method returns a map where key is an org name and value list of teams under the org.
func (c *githubConnector) userOrgTeams(ctx context.Context, client *http.Client) (map[string][]string, error) {
groups := make(map[string][]string)
apiURL := c.apiURL + "/user/teams"
for {
// https://developer.github.com/v3/orgs/teams/#list-user-teams
var (
teams []team
err error
)
if apiURL, err = get(ctx, client, apiURL, &teams); err != nil {
return nil, fmt.Errorf("github: get teams: %v", err)
}
for _, t := range teams {
groups[t.Org.Login] = append(groups[t.Org.Login], c.teamGroupClaims(t)...)
}
if apiURL == "" {
break
}
}
return groups, nil
}
// get creates a "GET `apiURL`" request with context, sends the request using
@ -402,7 +489,7 @@ func get(ctx context.Context, client *http.Client, apiURL string, v interface{})
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("github: read body: %v", err)
}
@ -416,10 +503,10 @@ func get(ctx context.Context, client *http.Client, apiURL string, v interface{})
return getPagination(apiURL, resp), nil
}
// getPagination checks the "Link" header field for "next" or "last" pagination
// URLs, and returns true only if a "next" URL is found. The next pages' URL is
// returned if a "next" URL is found. apiURL is returned if apiURL equals the
// "last" URL or no "next" or "last" URL are found.
// getPagination checks the "Link" header field for "next" or "last" pagination URLs,
// and returns "next" page URL or empty string to indicate that there are no more pages.
// Non empty next pages' URL is returned if both "last" and "next" URLs are found and next page
// URL is not equal to last.
//
// https://developer.github.com/v3/#pagination
func getPagination(apiURL string, resp *http.Response) string {
@ -464,7 +551,7 @@ func (c *githubConnector) user(ctx context.Context, client *http.Client) (user,
return u, err
}
// Only pulic user emails are returned by 'GET /user'. u.Email will be empty
// Only public user emails are returned by 'GET /user'. u.Email will be empty
// if a users' email is private. We must retrieve private emails explicitly.
if u.Email == "" {
var err error
@ -503,6 +590,20 @@ func (c *githubConnector) userEmail(ctx context.Context, client *http.Client) (s
}
for _, email := range emails {
/*
if GitHub Enterprise, set email.Verified to true
This change being made because GitHub Enterprise does not
support email verification. CircleCI indicated that GitHub
advised them not to check for verified emails
(https://circleci.com/enterprise/changelog/#1-47-1).
In addition, GitHub Enterprise support replied to a support
ticket with "There is no way to verify an email address in
GitHub Enterprise."
*/
if c.hostName != "" {
email.Verified = true
}
if email.Verified && email.Primary {
return email.Email, nil
}
@ -528,7 +629,6 @@ func (c *githubConnector) userInOrg(ctx context.Context, client *http.Client, us
apiURL := fmt.Sprintf("%s/orgs/%s/members/%s", c.apiURL, orgName, userName)
req, err := http.NewRequest("GET", apiURL, nil)
if err != nil {
return false, fmt.Errorf("github: new req: %v", err)
}
@ -542,7 +642,7 @@ func (c *githubConnector) userInOrg(ctx context.Context, client *http.Client, us
switch resp.StatusCode {
case http.StatusNoContent:
case http.StatusFound, http.StatusNotFound:
c.logger.Debugf("github: user %q not in org %q", userName, orgName)
c.logger.Infof("github: user %q not in org %q or application not authorized to read org data", userName, orgName)
default:
err = fmt.Errorf("github: unexpected return status: %q", resp.Status)
}
@ -555,16 +655,19 @@ func (c *githubConnector) userInOrg(ctx context.Context, client *http.Client, us
// https://developer.github.com/v3/orgs/teams/#response-12
type team struct {
Name string `json:"name"`
Org struct {
Login string `json:"login"`
} `json:"organization"`
Org org `json:"organization"`
Slug string `json:"slug"`
}
// teams queries the GitHub API for team membership within a specific organization.
type org struct {
Login string `json:"login"`
}
// teamsForOrg queries the GitHub API for team membership within a specific organization.
//
// The HTTP passed client is expected to be constructed by the golang.org/x/oauth2 package,
// which inserts a bearer token as part of the request.
func (c *githubConnector) teams(ctx context.Context, client *http.Client, orgName string) ([]string, error) {
func (c *githubConnector) teamsForOrg(ctx context.Context, client *http.Client, orgName string) ([]string, error) {
apiURL, groups := c.apiURL+"/user/teams", []string{}
for {
// https://developer.github.com/v3/orgs/teams/#list-user-teams
@ -573,12 +676,12 @@ func (c *githubConnector) teams(ctx context.Context, client *http.Client, orgNam
err error
)
if apiURL, err = get(ctx, client, apiURL, &teams); err != nil {
return nil, err
return nil, fmt.Errorf("github: get teams: %v", err)
}
for _, team := range teams {
if team.Org.Login == orgName {
groups = append(groups, team.Name)
for _, t := range teams {
if t.Org.Login == orgName {
groups = append(groups, c.teamGroupClaims(t)...)
}
}
@ -589,3 +692,17 @@ func (c *githubConnector) teams(ctx context.Context, client *http.Client, orgNam
return groups, nil
}
// teamGroupClaims returns team slug if 'teamNameField' option is set to
// 'slug', returns the slug *and* name if set to 'both', otherwise returns team
// name.
func (c *githubConnector) teamGroupClaims(t team) []string {
switch c.teamNameField {
case "both":
return []string{t.Name, t.Slug}
case "slug":
return []string{t.Slug}
default:
return []string{t.Name}
}
}

View File

@ -0,0 +1,238 @@
package github
import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"testing"
"github.com/dexidp/dex/connector"
)
type testResponse struct {
data interface{}
nextLink string
lastLink string
}
func TestUserGroups(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user/orgs": {
data: []org{{Login: "org-1"}, {Login: "org-2"}},
nextLink: "/user/orgs?since=2",
lastLink: "/user/orgs?since=2",
},
"/user/orgs?since=2": {data: []org{{Login: "org-3"}}},
"/user/teams": {
data: []team{
{Name: "team-1", Org: org{Login: "org-1"}},
{Name: "team-2", Org: org{Login: "org-1"}},
},
nextLink: "/user/teams?since=2",
lastLink: "/user/teams?since=2",
},
"/user/teams?since=2": {
data: []team{
{Name: "team-3", Org: org{Login: "org-1"}},
{Name: "team-4", Org: org{Login: "org-2"}},
},
nextLink: "/user/teams?since=2",
lastLink: "/user/teams?since=2",
},
})
defer s.Close()
c := githubConnector{apiURL: s.URL}
groups, err := c.userGroups(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, groups, []string{
"org-1",
"org-1:team-1",
"org-1:team-2",
"org-1:team-3",
"org-2",
"org-2:team-4",
"org-3",
})
}
func TestUserGroupsWithoutOrgs(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user/orgs": {data: []org{}},
"/user/teams": {data: []team{}},
})
defer s.Close()
c := githubConnector{apiURL: s.URL}
groups, err := c.userGroups(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, len(groups), 0)
}
func TestUserGroupsWithTeamNameFieldConfig(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user/orgs": {
data: []org{{Login: "org-1"}},
},
"/user/teams": {
data: []team{
{Name: "Team 1", Slug: "team-1", Org: org{Login: "org-1"}},
},
},
})
defer s.Close()
c := githubConnector{apiURL: s.URL, teamNameField: "slug"}
groups, err := c.userGroups(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, groups, []string{
"org-1",
"org-1:team-1",
})
}
func TestUserGroupsWithTeamNameAndSlugFieldConfig(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user/orgs": {
data: []org{{Login: "org-1"}},
},
"/user/teams": {
data: []team{
{Name: "Team 1", Slug: "team-1", Org: org{Login: "org-1"}},
},
},
})
defer s.Close()
c := githubConnector{apiURL: s.URL, teamNameField: "both"}
groups, err := c.userGroups(context.Background(), newClient())
expectNil(t, err)
expectEquals(t, groups, []string{
"org-1",
"org-1:Team 1",
"org-1:team-1",
})
}
// tests that the users login is used as their username when they have no username set
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user": {data: user{Login: "some-login", ID: 12345678}},
"/user/emails": {data: []userEmail{{
Email: "some@email.com",
Verified: true,
Primary: true,
}}},
"/login/oauth/access_token": {data: map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
}},
"/user/orgs": {
data: []org{{Login: "org-1"}},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := githubConnector{apiURL: s.URL, hostName: hostURL.Host, httpClient: newClient()}
identity, err := c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some-login")
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, 0, len(identity.Groups))
c = githubConnector{apiURL: s.URL, hostName: hostURL.Host, httpClient: newClient(), loadAllGroups: true}
identity, err = c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some-login")
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, identity.Groups, []string{"org-1"})
}
func TestLoginUsedAsIDWhenConfigured(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user": {data: user{Login: "some-login", ID: 12345678, Name: "Joe Bloggs"}},
"/user/emails": {data: []userEmail{{
Email: "some@email.com",
Verified: true,
Primary: true,
}}},
"/login/oauth/access_token": {data: map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
}},
"/user/orgs": {
data: []org{{Login: "org-1"}},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := githubConnector{apiURL: s.URL, hostName: hostURL.Host, httpClient: newClient(), useLoginAsID: true}
identity, err := c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.UserID, "some-login")
expectEquals(t, identity.Username, "Joe Bloggs")
}
func newTestServer(responses map[string]testResponse) *httptest.Server {
var s *httptest.Server
s = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := responses[r.RequestURI]
linkParts := make([]string, 0)
if response.nextLink != "" {
linkParts = append(linkParts, fmt.Sprintf("<%s%s>; rel=\"next\"", s.URL, response.nextLink))
}
if response.lastLink != "" {
linkParts = append(linkParts, fmt.Sprintf("<%s%s>; rel=\"last\"", s.URL, response.lastLink))
}
if len(linkParts) > 0 {
w.Header().Add("Link", strings.Join(linkParts, ", "))
}
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(response.data)
}))
return s
}
func newClient() *http.Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return &http.Client{Transport: tr}
}
func expectNil(t *testing.T, a interface{}) {
if a != nil {
t.Errorf("Expected %+v to equal nil", a)
}
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("Expected %+v to equal %+v", a, b)
}
}

View File

@ -6,27 +6,34 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"regexp"
"strconv"
"time"
"github.com/coreos/dex/connector"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
)
const (
scopeEmail = "user:email"
scopeOrgs = "read:org"
// read operations of the /api/v4/user endpoint
scopeUser = "read_user"
// used to retrieve groups from /oauth/userinfo
// https://docs.gitlab.com/ee/integration/openid_connect_provider.html
scopeOpenID = "openid"
)
// Config holds configuration options for gilab logins.
// Config holds configuration options for gitlab logins.
type Config struct {
BaseURL string `json:"baseURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
BaseURL string `json:"baseURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Groups []string `json:"groups"`
UseLoginAsID bool `json:"useLoginAsID"`
}
type gitlabUser struct {
@ -38,16 +45,10 @@ type gitlabUser struct {
IsAdmin bool
}
type gitlabGroup struct {
ID int
Name string
Path string
}
// Open returns a strategy for logging in through GitLab.
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
if c.BaseURL == "" {
c.BaseURL = "https://www.gitlab.com"
c.BaseURL = "https://gitlab.com"
}
return &gitlabConnector{
baseURL: c.BaseURL,
@ -55,12 +56,15 @@ func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
clientID: c.ClientID,
clientSecret: c.ClientSecret,
logger: logger,
groups: c.Groups,
useLoginAsID: c.UseLoginAsID,
}, nil
}
type connectorData struct {
// GitLab's OAuth2 tokens never expire. We don't need a refresh token.
AccessToken string `json:"accessToken"`
// Support GitLab's Access Tokens and Refresh tokens.
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
}
var (
@ -71,14 +75,21 @@ var (
type gitlabConnector struct {
baseURL string
redirectURI string
org string
groups []string
clientID string
clientSecret string
logger logrus.FieldLogger
logger log.Logger
httpClient *http.Client
// if set to true will use the user's handle rather than their numeric id as the ID
useLoginAsID bool
}
func (c *gitlabConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
gitlabScopes := []string{"api"}
gitlabScopes := []string{scopeUser}
if c.groupsRequired(scopes.Groups) {
gitlabScopes = []string{scopeUser, scopeOpenID}
}
gitlabEndpoint := oauth2.Endpoint{AuthURL: c.baseURL + "/oauth/authorize", TokenURL: c.baseURL + "/oauth/token"}
return &oauth2.Config{
ClientID: c.clientID,
@ -115,13 +126,22 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
}
oauth2Config := c.oauth2Config(s)
ctx := r.Context()
if c.httpClient != nil {
ctx = context.WithValue(r.Context(), oauth2.HTTPClient, c.httpClient)
}
token, err := oauth2Config.Exchange(ctx, q.Get("code"))
if err != nil {
return identity, fmt.Errorf("gitlab: failed to get token: %v", err)
}
return c.identity(ctx, s, token)
}
func (c *gitlabConnector) identity(ctx context.Context, s connector.Scopes, token *oauth2.Token) (identity connector.Identity, err error) {
oauth2Config := c.oauth2Config(s)
client := oauth2Config.Client(ctx, token)
user, err := c.user(ctx, client)
@ -133,15 +153,20 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
if username == "" {
username = user.Email
}
identity = connector.Identity{
UserID: strconv.Itoa(user.ID),
Username: username,
Email: user.Email,
EmailVerified: true,
UserID: strconv.Itoa(user.ID),
Username: username,
PreferredUsername: user.Username,
Email: user.Email,
EmailVerified: true,
}
if c.useLoginAsID {
identity.UserID = user.Username
}
if s.Groups {
groups, err := c.groups(ctx, client)
if c.groupsRequired(s.Groups) {
groups, err := c.getGroups(ctx, client, s.Groups, user.Username)
if err != nil {
return identity, fmt.Errorf("gitlab: get groups: %v", err)
}
@ -149,10 +174,10 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
}
if s.OfflineAccess {
data := connectorData{AccessToken: token.AccessToken}
data := connectorData{RefreshToken: token.RefreshToken, AccessToken: token.AccessToken}
connData, err := json.Marshal(data)
if err != nil {
return identity, fmt.Errorf("marshal connector data: %v", err)
return identity, fmt.Errorf("gitlab: marshal connector data: %v", err)
}
identity.ConnectorData = connData
}
@ -161,36 +186,43 @@ func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
}
func (c *gitlabConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
if len(ident.ConnectorData) == 0 {
return ident, errors.New("no upstream access token found")
}
var data connectorData
if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
return ident, fmt.Errorf("gitlab: unmarshal access token: %v", err)
return ident, fmt.Errorf("gitlab: unmarshal connector data: %v", err)
}
oauth2Config := c.oauth2Config(s)
if c.httpClient != nil {
ctx = context.WithValue(ctx, oauth2.HTTPClient, c.httpClient)
}
client := c.oauth2Config(s).Client(ctx, &oauth2.Token{AccessToken: data.AccessToken})
user, err := c.user(ctx, client)
if err != nil {
return ident, fmt.Errorf("gitlab: get user: %v", err)
}
username := user.Name
if username == "" {
username = user.Email
}
ident.Username = username
ident.Email = user.Email
if s.Groups {
groups, err := c.groups(ctx, client)
if err != nil {
return ident, fmt.Errorf("gitlab: get groups: %v", err)
switch {
case data.RefreshToken != "":
{
t := &oauth2.Token{
RefreshToken: data.RefreshToken,
Expiry: time.Now().Add(-time.Hour),
}
token, err := oauth2Config.TokenSource(ctx, t).Token()
if err != nil {
return ident, fmt.Errorf("gitlab: failed to get refresh token: %v", err)
}
return c.identity(ctx, s, token)
}
ident.Groups = groups
case data.AccessToken != "":
{
token := &oauth2.Token{
AccessToken: data.AccessToken,
}
return c.identity(ctx, s, token)
}
default:
return ident, errors.New("no refresh or access token found")
}
return ident, nil
}
func (c *gitlabConnector) groupsRequired(groupScope bool) bool {
return len(c.groups) > 0 || groupScope
}
// user queries the GitLab API for profile information using the provided client. The HTTP
@ -198,7 +230,7 @@ func (c *gitlabConnector) Refresh(ctx context.Context, s connector.Scopes, ident
// a bearer token as part of the request.
func (c *gitlabConnector) user(ctx context.Context, client *http.Client) (gitlabUser, error) {
var u gitlabUser
req, err := http.NewRequest("GET", c.baseURL+"/api/v3/user", nil)
req, err := http.NewRequest("GET", c.baseURL+"/api/v4/user", nil)
if err != nil {
return u, fmt.Errorf("gitlab: new req: %v", err)
}
@ -210,7 +242,7 @@ func (c *gitlabConnector) user(ctx context.Context, client *http.Client) (gitlab
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return u, fmt.Errorf("gitlab: read body: %v", err)
}
@ -223,66 +255,56 @@ func (c *gitlabConnector) user(ctx context.Context, client *http.Client) (gitlab
return u, nil
}
// groups queries the GitLab API for group membership.
type userInfo struct {
Groups []string
}
// userGroups queries the GitLab API for group membership.
//
// The HTTP passed client is expected to be constructed by the golang.org/x/oauth2 package,
// which inserts a bearer token as part of the request.
func (c *gitlabConnector) groups(ctx context.Context, client *http.Client) ([]string, error) {
apiURL := c.baseURL + "/api/v3/groups"
reNext := regexp.MustCompile("<(.*)>; rel=\"next\"")
reLast := regexp.MustCompile("<(.*)>; rel=\"last\"")
groups := []string{}
var gitlabGroups []gitlabGroup
for {
// 100 is the maximum number for per_page that allowed by gitlab
req, err := http.NewRequest("GET", apiURL, nil)
if err != nil {
return nil, fmt.Errorf("gitlab: new req: %v", err)
}
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("gitlab: get groups: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("gitlab: read body: %v", err)
}
return nil, fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.NewDecoder(resp.Body).Decode(&gitlabGroups); err != nil {
return nil, fmt.Errorf("gitlab: unmarshal groups: %v", err)
}
for _, group := range gitlabGroups {
groups = append(groups, group.Name)
}
link := resp.Header.Get("Link")
if len(reLast.FindStringSubmatch(link)) > 1 {
lastPageURL := reLast.FindStringSubmatch(link)[1]
if apiURL == lastPageURL {
break
}
} else {
break
}
if len(reNext.FindStringSubmatch(link)) > 1 {
apiURL = reNext.FindStringSubmatch(link)[1]
} else {
break
}
func (c *gitlabConnector) userGroups(ctx context.Context, client *http.Client) ([]string, error) {
req, err := http.NewRequest("GET", c.baseURL+"/oauth/userinfo", nil)
if err != nil {
return nil, fmt.Errorf("gitlab: new req: %v", err)
}
return groups, nil
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("gitlab: get URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("gitlab: read body: %v", err)
}
return nil, fmt.Errorf("%s: %s", resp.Status, body)
}
var u userInfo
if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {
return nil, fmt.Errorf("failed to decode response: %v", err)
}
return u.Groups, nil
}
func (c *gitlabConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) ([]string, error) {
gitlabGroups, err := c.userGroups(ctx, client)
if err != nil {
return nil, err
}
if len(c.groups) > 0 {
filteredGroups := groups.Filter(gitlabGroups, c.groups)
if len(filteredGroups) == 0 {
return nil, fmt.Errorf("gitlab: user %q is not in any of the required groups", userLogin)
}
return filteredGroups, nil
} else if groupScope {
return gitlabGroups, nil
}
return nil, nil
}

View File

@ -0,0 +1,283 @@
package gitlab
import (
"context"
"crypto/tls"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"
"github.com/dexidp/dex/connector"
)
func TestUserGroups(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/oauth/userinfo": userInfo{
Groups: []string{"team-1", "team-2"},
},
})
defer s.Close()
c := gitlabConnector{baseURL: s.URL}
groups, err := c.getGroups(context.Background(), newClient(), true, "joebloggs")
expectNil(t, err)
expectEquals(t, groups, []string{
"team-1",
"team-2",
})
}
func TestUserGroupsWithFiltering(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/oauth/userinfo": userInfo{
Groups: []string{"team-1", "team-2"},
},
})
defer s.Close()
c := gitlabConnector{baseURL: s.URL, groups: []string{"team-1"}}
groups, err := c.getGroups(context.Background(), newClient(), true, "joebloggs")
expectNil(t, err)
expectEquals(t, groups, []string{
"team-1",
})
}
func TestUserGroupsWithoutOrgs(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/oauth/userinfo": userInfo{
Groups: []string{},
},
})
defer s.Close()
c := gitlabConnector{baseURL: s.URL}
groups, err := c.getGroups(context.Background(), newClient(), true, "joebloggs")
expectNil(t, err)
expectEquals(t, len(groups), 0)
}
// tests that the email is used as their username when they have no username set
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678},
"/oauth/token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
},
"/oauth/userinfo": userInfo{
Groups: []string{"team-1"},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := gitlabConnector{baseURL: s.URL, httpClient: newClient()}
identity, err := c.HandleCallback(connector.Scopes{Groups: false}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some@email.com")
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, 0, len(identity.Groups))
c = gitlabConnector{baseURL: s.URL, httpClient: newClient()}
identity, err = c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some@email.com")
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, identity.Groups, []string{"team-1"})
}
func TestLoginUsedAsIDWhenConfigured(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678, Name: "Joe Bloggs", Username: "joebloggs"},
"/oauth/token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
},
"/oauth/userinfo": userInfo{
Groups: []string{"team-1"},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := gitlabConnector{baseURL: s.URL, httpClient: newClient(), useLoginAsID: true}
identity, err := c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.UserID, "joebloggs")
expectEquals(t, identity.Username, "Joe Bloggs")
}
func TestLoginWithTeamWhitelisted(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678, Name: "Joe Bloggs"},
"/oauth/token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
},
"/oauth/userinfo": userInfo{
Groups: []string{"team-1"},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := gitlabConnector{baseURL: s.URL, httpClient: newClient(), groups: []string{"team-1"}}
identity, err := c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, identity.Username, "Joe Bloggs")
}
func TestLoginWithTeamNonWhitelisted(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678, Name: "Joe Bloggs", Username: "joebloggs"},
"/oauth/token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
},
"/oauth/userinfo": userInfo{
Groups: []string{"team-1"},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := gitlabConnector{baseURL: s.URL, httpClient: newClient(), groups: []string{"team-2"}}
_, err = c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNotNil(t, err, "HandleCallback error")
expectEquals(t, err.Error(), "gitlab: get groups: gitlab: user \"joebloggs\" is not in any of the required groups")
}
func TestRefresh(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678},
"/oauth/token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"refresh_token": "oRzxVjCnohYRHEYEhZshkmakKmoyVoTjfUGC",
"expires_in": "30",
},
"/oauth/userinfo": userInfo{
Groups: []string{"team-1"},
},
})
defer s.Close()
hostURL, err := url.Parse(s.URL)
expectNil(t, err)
req, err := http.NewRequest("GET", hostURL.String(), nil)
expectNil(t, err)
c := gitlabConnector{baseURL: s.URL, httpClient: newClient()}
expectedConnectorData, err := json.Marshal(connectorData{
RefreshToken: "oRzxVjCnohYRHEYEhZshkmakKmoyVoTjfUGC",
AccessToken: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
})
expectNil(t, err)
identity, err := c.HandleCallback(connector.Scopes{OfflineAccess: true}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "some@email.com")
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, identity.ConnectorData, expectedConnectorData)
identity, err = c.Refresh(context.Background(), connector.Scopes{OfflineAccess: true}, identity)
expectNil(t, err)
expectEquals(t, identity.Username, "some@email.com")
expectEquals(t, identity.UserID, "12345678")
expectEquals(t, identity.ConnectorData, expectedConnectorData)
}
func TestRefreshWithEmptyConnectorData(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678},
"/oauth/token": map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"refresh_token": "oRzxVjCnohYRHEYEhZshkmakKmoyVoTjfUGC",
"expires_in": "30",
},
"/oauth/userinfo": userInfo{
Groups: []string{"team-1"},
},
})
defer s.Close()
emptyConnectorData, err := json.Marshal(connectorData{
RefreshToken: "",
AccessToken: "",
})
expectNil(t, err)
c := gitlabConnector{baseURL: s.URL, httpClient: newClient()}
emptyIdentity := connector.Identity{ConnectorData: emptyConnectorData}
identity, err := c.Refresh(context.Background(), connector.Scopes{OfflineAccess: true}, emptyIdentity)
expectNotNil(t, err, "Refresh error")
expectEquals(t, emptyIdentity, identity)
}
func newTestServer(responses map[string]interface{}) *httptest.Server {
return httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := responses[r.RequestURI]
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}))
}
func newClient() *http.Client {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
return &http.Client{Transport: tr}
}
func expectNil(t *testing.T, a interface{}) {
if a != nil {
t.Errorf("Expected %+v to equal nil", a)
}
}
func expectNotNil(t *testing.T, a interface{}, msg string) {
if a == nil {
t.Errorf("Expected %+v to not to be nil", msg)
}
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("Expected %+v to equal %+v", a, b)
}
}

326
connector/google/google.go Normal file
View File

@ -0,0 +1,326 @@
// Package google implements logging in through Google's OpenID Connect provider.
package google
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
admin "google.golang.org/api/admin/directory/v1"
"google.golang.org/api/option"
"github.com/dexidp/dex/connector"
pkg_groups "github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
)
const (
issuerURL = "https://accounts.google.com"
)
// Config holds configuration options for Google logins.
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Scopes []string `json:"scopes"` // defaults to "profile" and "email"
// Optional list of whitelisted domains
// If this field is nonempty, only users from a listed domain will be allowed to log in
HostedDomains []string `json:"hostedDomains"`
// Optional list of whitelisted groups
// If this field is nonempty, only users from a listed group will be allowed to log in
Groups []string `json:"groups"`
// Optional path to service account json
// If nonempty, and groups claim is made, will use authentication from file to
// check groups with the admin directory api
ServiceAccountFilePath string `json:"serviceAccountFilePath"`
// Required if ServiceAccountFilePath
// The email of a GSuite super user which the service account will impersonate
// when listing groups
AdminEmail string
// If this field is true, fetch direct group membership and transitive group membership
FetchTransitiveGroupMembership bool `json:"fetchTransitiveGroupMembership"`
}
// Open returns a connector which can be used to login users through Google.
func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, err error) {
ctx, cancel := context.WithCancel(context.Background())
provider, err := oidc.NewProvider(ctx, issuerURL)
if err != nil {
cancel()
return nil, fmt.Errorf("failed to get provider: %v", err)
}
scopes := []string{oidc.ScopeOpenID}
if len(c.Scopes) > 0 {
scopes = append(scopes, c.Scopes...)
} else {
scopes = append(scopes, "profile", "email")
}
srv, err := createDirectoryService(c.ServiceAccountFilePath, c.AdminEmail)
if err != nil {
cancel()
return nil, fmt.Errorf("could not create directory service: %v", err)
}
clientID := c.ClientID
return &googleConnector{
redirectURI: c.RedirectURI,
oauth2Config: &oauth2.Config{
ClientID: clientID,
ClientSecret: c.ClientSecret,
Endpoint: provider.Endpoint(),
Scopes: scopes,
RedirectURL: c.RedirectURI,
},
verifier: provider.Verifier(
&oidc.Config{ClientID: clientID},
),
logger: logger,
cancel: cancel,
hostedDomains: c.HostedDomains,
groups: c.Groups,
serviceAccountFilePath: c.ServiceAccountFilePath,
adminEmail: c.AdminEmail,
fetchTransitiveGroupMembership: c.FetchTransitiveGroupMembership,
adminSrv: srv,
}, nil
}
var (
_ connector.CallbackConnector = (*googleConnector)(nil)
_ connector.RefreshConnector = (*googleConnector)(nil)
)
type googleConnector struct {
redirectURI string
oauth2Config *oauth2.Config
verifier *oidc.IDTokenVerifier
cancel context.CancelFunc
logger log.Logger
hostedDomains []string
groups []string
serviceAccountFilePath string
adminEmail string
fetchTransitiveGroupMembership bool
adminSrv *admin.Service
}
func (c *googleConnector) Close() error {
c.cancel()
return nil
}
func (c *googleConnector) LoginURL(s connector.Scopes, callbackURL, state string) (string, error) {
if c.redirectURI != callbackURL {
return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", callbackURL, c.redirectURI)
}
var opts []oauth2.AuthCodeOption
if len(c.hostedDomains) > 0 {
preferredDomain := c.hostedDomains[0]
if len(c.hostedDomains) > 1 {
preferredDomain = "*"
}
opts = append(opts, oauth2.SetAuthURLParam("hd", preferredDomain))
}
if s.OfflineAccess {
opts = append(opts, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("prompt", "consent"))
}
return c.oauth2Config.AuthCodeURL(state, opts...), nil
}
type oauth2Error struct {
error string
errorDescription string
}
func (e *oauth2Error) Error() string {
if e.errorDescription == "" {
return e.error
}
return e.error + ": " + e.errorDescription
}
func (c *googleConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
q := r.URL.Query()
if errType := q.Get("error"); errType != "" {
return identity, &oauth2Error{errType, q.Get("error_description")}
}
token, err := c.oauth2Config.Exchange(r.Context(), q.Get("code"))
if err != nil {
return identity, fmt.Errorf("google: failed to get token: %v", err)
}
return c.createIdentity(r.Context(), identity, s, token)
}
func (c *googleConnector) Refresh(ctx context.Context, s connector.Scopes, identity connector.Identity) (connector.Identity, error) {
t := &oauth2.Token{
RefreshToken: string(identity.ConnectorData),
Expiry: time.Now().Add(-time.Hour),
}
token, err := c.oauth2Config.TokenSource(ctx, t).Token()
if err != nil {
return identity, fmt.Errorf("google: failed to get token: %v", err)
}
return c.createIdentity(ctx, identity, s, token)
}
func (c *googleConnector) createIdentity(ctx context.Context, identity connector.Identity, s connector.Scopes, token *oauth2.Token) (connector.Identity, error) {
rawIDToken, ok := token.Extra("id_token").(string)
if !ok {
return identity, errors.New("google: no id_token in token response")
}
idToken, err := c.verifier.Verify(ctx, rawIDToken)
if err != nil {
return identity, fmt.Errorf("google: failed to verify ID Token: %v", err)
}
var claims struct {
Username string `json:"name"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
HostedDomain string `json:"hd"`
}
if err := idToken.Claims(&claims); err != nil {
return identity, fmt.Errorf("oidc: failed to decode claims: %v", err)
}
if len(c.hostedDomains) > 0 {
found := false
for _, domain := range c.hostedDomains {
if claims.HostedDomain == domain {
found = true
break
}
}
if !found {
return identity, fmt.Errorf("oidc: unexpected hd claim %v", claims.HostedDomain)
}
}
var groups []string
if s.Groups && c.adminSrv != nil {
groups, err = c.getGroups(claims.Email, c.fetchTransitiveGroupMembership)
if err != nil {
return identity, fmt.Errorf("google: could not retrieve groups: %v", err)
}
if len(c.groups) > 0 {
groups = pkg_groups.Filter(groups, c.groups)
if len(groups) == 0 {
return identity, fmt.Errorf("google: user %q is not in any of the required groups", claims.Username)
}
}
}
identity = connector.Identity{
UserID: idToken.Subject,
Username: claims.Username,
Email: claims.Email,
EmailVerified: claims.EmailVerified,
ConnectorData: []byte(token.RefreshToken),
Groups: groups,
}
return identity, nil
}
// getGroups creates a connection to the admin directory service and lists
// all groups the user is a member of
func (c *googleConnector) getGroups(email string, fetchTransitiveGroupMembership bool) ([]string, error) {
var userGroups []string
var err error
groupsList := &admin.Groups{}
for {
groupsList, err = c.adminSrv.Groups.List().
UserKey(email).PageToken(groupsList.NextPageToken).Do()
if err != nil {
return nil, fmt.Errorf("could not list groups: %v", err)
}
for _, group := range groupsList.Groups {
// TODO (joelspeed): Make desired group key configurable
userGroups = append(userGroups, group.Email)
// getGroups takes a user's email/alias as well as a group's email/alias
if fetchTransitiveGroupMembership {
transitiveGroups, err := c.getGroups(group.Email, fetchTransitiveGroupMembership)
if err != nil {
return nil, fmt.Errorf("could not list transitive groups: %v", err)
}
userGroups = append(userGroups, transitiveGroups...)
}
}
if groupsList.NextPageToken == "" {
break
}
}
return uniqueGroups(userGroups), nil
}
// createDirectoryService loads a google service account credentials file,
// sets up super user impersonation and creates an admin client for calling
// the google admin api
func createDirectoryService(serviceAccountFilePath string, email string) (*admin.Service, error) {
if serviceAccountFilePath == "" && email == "" {
return nil, nil
}
if serviceAccountFilePath == "" || email == "" {
return nil, fmt.Errorf("directory service requires both serviceAccountFilePath and adminEmail")
}
jsonCredentials, err := os.ReadFile(serviceAccountFilePath)
if err != nil {
return nil, fmt.Errorf("error reading credentials from file: %v", err)
}
config, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryGroupReadonlyScope)
if err != nil {
return nil, fmt.Errorf("unable to parse client secret file to config: %v", err)
}
// Impersonate an admin. This is mandatory for the admin APIs.
config.Subject = email
ctx := context.Background()
client := config.Client(ctx)
srv, err := admin.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return nil, fmt.Errorf("unable to create directory service %v", err)
}
return srv, nil
}
// uniqueGroups returns the unique groups of a slice
func uniqueGroups(groups []string) []string {
keys := make(map[string]struct{})
unique := []string{}
for _, group := range groups {
if _, exists := keys[group]; !exists {
keys[group] = struct{}{}
unique = append(unique, group)
}
}
return unique
}

View File

@ -0,0 +1,312 @@
// Package keystone provides authentication strategy using Keystone.
package keystone
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
type conn struct {
Domain string
Host string
AdminUsername string
AdminPassword string
Logger log.Logger
}
type userKeystone struct {
Domain domainKeystone `json:"domain"`
ID string `json:"id"`
Name string `json:"name"`
}
type domainKeystone struct {
ID string `json:"id"`
Name string `json:"name"`
}
// Config holds the configuration parameters for Keystone connector.
// Keystone should expose API v3
// An example config:
// connectors:
// type: keystone
// id: keystone
// name: Keystone
// config:
// keystoneHost: http://example:5000
// domain: default
// keystoneUsername: demo
// keystonePassword: DEMO_PASS
type Config struct {
Domain string `json:"domain"`
Host string `json:"keystoneHost"`
AdminUsername string `json:"keystoneUsername"`
AdminPassword string `json:"keystonePassword"`
}
type loginRequestData struct {
auth `json:"auth"`
}
type auth struct {
Identity identity `json:"identity"`
}
type identity struct {
Methods []string `json:"methods"`
Password password `json:"password"`
}
type password struct {
User user `json:"user"`
}
type user struct {
Name string `json:"name"`
Domain domain `json:"domain"`
Password string `json:"password"`
}
type domain struct {
ID string `json:"id"`
}
type token struct {
User userKeystone `json:"user"`
}
type tokenResponse struct {
Token token `json:"token"`
}
type group struct {
ID string `json:"id"`
Name string `json:"name"`
}
type groupsResponse struct {
Groups []group `json:"groups"`
}
type userResponse struct {
User struct {
Name string `json:"name"`
Email string `json:"email"`
ID string `json:"id"`
} `json:"user"`
}
var (
_ connector.PasswordConnector = &conn{}
_ connector.RefreshConnector = &conn{}
)
// Open returns an authentication strategy using Keystone.
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
return &conn{
c.Domain,
c.Host,
c.AdminUsername,
c.AdminPassword,
logger,
}, nil
}
func (p *conn) Close() error { return nil }
func (p *conn) Login(ctx context.Context, scopes connector.Scopes, username, password string) (identity connector.Identity, validPassword bool, err error) {
resp, err := p.getTokenResponse(ctx, username, password)
if err != nil {
return identity, false, fmt.Errorf("keystone: error %v", err)
}
if resp.StatusCode/100 != 2 {
return identity, false, fmt.Errorf("keystone login: error %v", resp.StatusCode)
}
if resp.StatusCode != 201 {
return identity, false, nil
}
token := resp.Header.Get("X-Subject-Token")
data, err := io.ReadAll(resp.Body)
if err != nil {
return identity, false, err
}
defer resp.Body.Close()
tokenResp := new(tokenResponse)
err = json.Unmarshal(data, &tokenResp)
if err != nil {
return identity, false, fmt.Errorf("keystone: invalid token response: %v", err)
}
if scopes.Groups {
groups, err := p.getUserGroups(ctx, tokenResp.Token.User.ID, token)
if err != nil {
return identity, false, err
}
identity.Groups = groups
}
identity.Username = username
identity.UserID = tokenResp.Token.User.ID
user, err := p.getUser(ctx, tokenResp.Token.User.ID, token)
if err != nil {
return identity, false, err
}
if user.User.Email != "" {
identity.Email = user.User.Email
identity.EmailVerified = true
}
return identity, true, nil
}
func (p *conn) Prompt() string { return "username" }
func (p *conn) Refresh(
ctx context.Context, scopes connector.Scopes, identity connector.Identity,
) (connector.Identity, error) {
token, err := p.getAdminToken(ctx)
if err != nil {
return identity, fmt.Errorf("keystone: failed to obtain admin token: %v", err)
}
ok, err := p.checkIfUserExists(ctx, identity.UserID, token)
if err != nil {
return identity, err
}
if !ok {
return identity, fmt.Errorf("keystone: user %q does not exist", identity.UserID)
}
if scopes.Groups {
groups, err := p.getUserGroups(ctx, identity.UserID, token)
if err != nil {
return identity, err
}
identity.Groups = groups
}
return identity, nil
}
func (p *conn) getTokenResponse(ctx context.Context, username, pass string) (response *http.Response, err error) {
client := &http.Client{}
jsonData := loginRequestData{
auth: auth{
Identity: identity{
Methods: []string{"password"},
Password: password{
User: user{
Name: username,
Domain: domain{ID: p.Domain},
Password: pass,
},
},
},
},
}
jsonValue, err := json.Marshal(jsonData)
if err != nil {
return nil, err
}
// https://developer.openstack.org/api-ref/identity/v3/#password-authentication-with-unscoped-authorization
authTokenURL := p.Host + "/v3/auth/tokens/"
req, err := http.NewRequest("POST", authTokenURL, bytes.NewBuffer(jsonValue))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req = req.WithContext(ctx)
return client.Do(req)
}
func (p *conn) getAdminToken(ctx context.Context) (string, error) {
resp, err := p.getTokenResponse(ctx, p.AdminUsername, p.AdminPassword)
if err != nil {
return "", err
}
defer resp.Body.Close()
token := resp.Header.Get("X-Subject-Token")
return token, nil
}
func (p *conn) checkIfUserExists(ctx context.Context, userID string, token string) (bool, error) {
user, err := p.getUser(ctx, userID, token)
return user != nil, err
}
func (p *conn) getUser(ctx context.Context, userID string, token string) (*userResponse, error) {
// https://developer.openstack.org/api-ref/identity/v3/#show-user-details
userURL := p.Host + "/v3/users/" + userID
client := &http.Client{}
req, err := http.NewRequest("GET", userURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("X-Auth-Token", token)
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, err
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
user := userResponse{}
err = json.Unmarshal(data, &user)
if err != nil {
return nil, err
}
return &user, nil
}
func (p *conn) getUserGroups(ctx context.Context, userID string, token string) ([]string, error) {
client := &http.Client{}
// https://developer.openstack.org/api-ref/identity/v3/#list-groups-to-which-a-user-belongs
groupsURL := p.Host + "/v3/users/" + userID + "/groups"
req, err := http.NewRequest("GET", groupsURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("X-Auth-Token", token)
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
p.Logger.Errorf("keystone: error while fetching user %q groups\n", userID)
return nil, err
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
defer resp.Body.Close()
groupsResp := new(groupsResponse)
err = json.Unmarshal(data, &groupsResp)
if err != nil {
return nil, err
}
groups := make([]string, len(groupsResp.Groups))
for i, group := range groupsResp.Groups {
groups[i] = group.Name
}
return groups, nil
}

View File

@ -0,0 +1,483 @@
package keystone
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"os"
"reflect"
"strings"
"testing"
"github.com/dexidp/dex/connector"
)
const (
invalidPass = "WRONG_PASS"
testUser = "test_user"
testPass = "test_pass"
testEmail = "test@example.com"
testGroup = "test_group"
testDomain = "default"
)
var (
keystoneURL = ""
keystoneAdminURL = ""
adminUser = ""
adminPass = ""
authTokenURL = ""
usersURL = ""
groupsURL = ""
)
type groupResponse struct {
Group struct {
ID string `json:"id"`
} `json:"group"`
}
func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string) {
t.Helper()
client := &http.Client{}
jsonData := loginRequestData{
auth: auth{
Identity: identity{
Methods: []string{"password"},
Password: password{
User: user{
Name: adminName,
Domain: domain{ID: testDomain},
Password: adminPass,
},
},
},
},
}
body, err := json.Marshal(jsonData)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", authTokenURL, bytes.NewBuffer(body))
if err != nil {
t.Fatalf("keystone: failed to obtain admin token: %v\n", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
token = resp.Header.Get("X-Subject-Token")
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
tokenResp := new(tokenResponse)
err = json.Unmarshal(data, &tokenResp)
if err != nil {
t.Fatal(err)
}
return token, tokenResp.Token.User.ID
}
func createUser(t *testing.T, token, userName, userEmail, userPass string) string {
t.Helper()
client := &http.Client{}
createUserData := map[string]interface{}{
"user": map[string]interface{}{
"name": userName,
"email": userEmail,
"enabled": true,
"password": userPass,
"roles": []string{"admin"},
},
}
body, err := json.Marshal(createUserData)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", usersURL, bytes.NewBuffer(body))
if err != nil {
t.Fatal(err)
}
req.Header.Set("X-Auth-Token", token)
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
userResp := new(userResponse)
err = json.Unmarshal(data, &userResp)
if err != nil {
t.Fatal(err)
}
return userResp.User.ID
}
// delete group or user
func deleteResource(t *testing.T, token, id, uri string) {
t.Helper()
client := &http.Client{}
deleteURI := uri + id
req, err := http.NewRequest("DELETE", deleteURI, nil)
if err != nil {
t.Fatalf("error: %v", err)
}
req.Header.Set("X-Auth-Token", token)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("error: %v", err)
}
defer resp.Body.Close()
}
func createGroup(t *testing.T, token, description, name string) string {
t.Helper()
client := &http.Client{}
createGroupData := map[string]interface{}{
"group": map[string]interface{}{
"name": name,
"description": description,
},
}
body, err := json.Marshal(createGroupData)
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", groupsURL, bytes.NewBuffer(body))
if err != nil {
t.Fatal(err)
}
req.Header.Set("X-Auth-Token", token)
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
groupResp := new(groupResponse)
err = json.Unmarshal(data, &groupResp)
if err != nil {
t.Fatal(err)
}
return groupResp.Group.ID
}
func addUserToGroup(t *testing.T, token, groupID, userID string) error {
t.Helper()
uri := groupsURL + groupID + "/users/" + userID
client := &http.Client{}
req, err := http.NewRequest("PUT", uri, nil)
if err != nil {
return err
}
req.Header.Set("X-Auth-Token", token)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("error: %v", err)
}
defer resp.Body.Close()
return nil
}
func TestIncorrectCredentialsLogin(t *testing.T) {
setupVariables(t)
c := conn{
Host: keystoneURL, Domain: testDomain,
AdminUsername: adminUser, AdminPassword: adminPass,
}
s := connector.Scopes{OfflineAccess: true, Groups: true}
_, validPW, err := c.Login(context.Background(), s, adminUser, invalidPass)
if validPW {
t.Fatal("Incorrect password check")
}
if err == nil {
t.Fatal("Error should be returned when invalid password is provided")
}
if !strings.Contains(err.Error(), "401") {
t.Fatal("Unrecognized error, expecting 401")
}
}
func TestValidUserLogin(t *testing.T) {
setupVariables(t)
token, _ := getAdminToken(t, adminUser, adminPass)
type tUser struct {
username string
domain string
email string
password string
}
type expect struct {
username string
email string
verifiedEmail bool
}
tests := []struct {
name string
input tUser
expected expect
}{
{
name: "test with email address",
input: tUser{
username: testUser,
domain: testDomain,
email: testEmail,
password: testPass,
},
expected: expect{
username: testUser,
email: testEmail,
verifiedEmail: true,
},
},
{
name: "test without email address",
input: tUser{
username: testUser,
domain: testDomain,
email: "",
password: testPass,
},
expected: expect{
username: testUser,
email: "",
verifiedEmail: false,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
userID := createUser(t, token, tt.input.username, tt.input.email, tt.input.password)
defer deleteResource(t, token, userID, usersURL)
c := conn{
Host: keystoneURL, Domain: tt.input.domain,
AdminUsername: adminUser, AdminPassword: adminPass,
}
s := connector.Scopes{OfflineAccess: true, Groups: true}
identity, validPW, err := c.Login(context.Background(), s, tt.input.username, tt.input.password)
if err != nil {
t.Fatal(err.Error())
}
t.Log(identity)
if identity.Username != tt.expected.username {
t.Fatalf("Invalid user. Got: %v. Wanted: %v", identity.Username, tt.expected.username)
}
if identity.UserID == "" {
t.Fatalf("Didn't get any UserID back")
}
if identity.Email != tt.expected.email {
t.Fatalf("Invalid email. Got: %v. Wanted: %v", identity.Email, tt.expected.email)
}
if identity.EmailVerified != tt.expected.verifiedEmail {
t.Fatalf("Invalid verifiedEmail. Got: %v. Wanted: %v", identity.EmailVerified, tt.expected.verifiedEmail)
}
if !validPW {
t.Fatal("Valid password was not accepted")
}
})
}
}
func TestUseRefreshToken(t *testing.T) {
setupVariables(t)
token, adminID := getAdminToken(t, adminUser, adminPass)
groupID := createGroup(t, token, "Test group description", testGroup)
addUserToGroup(t, token, groupID, adminID)
defer deleteResource(t, token, groupID, groupsURL)
c := conn{
Host: keystoneURL, Domain: testDomain,
AdminUsername: adminUser, AdminPassword: adminPass,
}
s := connector.Scopes{OfflineAccess: true, Groups: true}
identityLogin, _, err := c.Login(context.Background(), s, adminUser, adminPass)
if err != nil {
t.Fatal(err.Error())
}
identityRefresh, err := c.Refresh(context.Background(), s, identityLogin)
if err != nil {
t.Fatal(err.Error())
}
expectEquals(t, 1, len(identityRefresh.Groups))
expectEquals(t, testGroup, identityRefresh.Groups[0])
}
func TestUseRefreshTokenUserDeleted(t *testing.T) {
setupVariables(t)
token, _ := getAdminToken(t, adminUser, adminPass)
userID := createUser(t, token, testUser, testEmail, testPass)
c := conn{
Host: keystoneURL, Domain: testDomain,
AdminUsername: adminUser, AdminPassword: adminPass,
}
s := connector.Scopes{OfflineAccess: true, Groups: true}
identityLogin, _, err := c.Login(context.Background(), s, testUser, testPass)
if err != nil {
t.Fatal(err.Error())
}
_, err = c.Refresh(context.Background(), s, identityLogin)
if err != nil {
t.Fatal(err.Error())
}
deleteResource(t, token, userID, usersURL)
_, err = c.Refresh(context.Background(), s, identityLogin)
if !strings.Contains(err.Error(), "does not exist") {
t.Errorf("unexpected error: %s", err.Error())
}
}
func TestUseRefreshTokenGroupsChanged(t *testing.T) {
setupVariables(t)
token, _ := getAdminToken(t, adminUser, adminPass)
userID := createUser(t, token, testUser, testEmail, testPass)
defer deleteResource(t, token, userID, usersURL)
c := conn{
Host: keystoneURL, Domain: testDomain,
AdminUsername: adminUser, AdminPassword: adminPass,
}
s := connector.Scopes{OfflineAccess: true, Groups: true}
identityLogin, _, err := c.Login(context.Background(), s, testUser, testPass)
if err != nil {
t.Fatal(err.Error())
}
identityRefresh, err := c.Refresh(context.Background(), s, identityLogin)
if err != nil {
t.Fatal(err.Error())
}
expectEquals(t, 0, len(identityRefresh.Groups))
groupID := createGroup(t, token, "Test group", testGroup)
addUserToGroup(t, token, groupID, userID)
defer deleteResource(t, token, groupID, groupsURL)
identityRefresh, err = c.Refresh(context.Background(), s, identityLogin)
if err != nil {
t.Fatal(err.Error())
}
expectEquals(t, 1, len(identityRefresh.Groups))
}
func TestNoGroupsInScope(t *testing.T) {
setupVariables(t)
token, _ := getAdminToken(t, adminUser, adminPass)
userID := createUser(t, token, testUser, testEmail, testPass)
defer deleteResource(t, token, userID, usersURL)
c := conn{
Host: keystoneURL, Domain: testDomain,
AdminUsername: adminUser, AdminPassword: adminPass,
}
s := connector.Scopes{OfflineAccess: true, Groups: false}
groupID := createGroup(t, token, "Test group", testGroup)
addUserToGroup(t, token, groupID, userID)
defer deleteResource(t, token, groupID, groupsURL)
identityLogin, _, err := c.Login(context.Background(), s, testUser, testPass)
if err != nil {
t.Fatal(err.Error())
}
expectEquals(t, 0, len(identityLogin.Groups))
identityRefresh, err := c.Refresh(context.Background(), s, identityLogin)
if err != nil {
t.Fatal(err.Error())
}
expectEquals(t, 0, len(identityRefresh.Groups))
}
func setupVariables(t *testing.T) {
keystoneURLEnv := "DEX_KEYSTONE_URL"
keystoneAdminURLEnv := "DEX_KEYSTONE_ADMIN_URL"
keystoneAdminUserEnv := "DEX_KEYSTONE_ADMIN_USER"
keystoneAdminPassEnv := "DEX_KEYSTONE_ADMIN_PASS"
keystoneURL = os.Getenv(keystoneURLEnv)
if keystoneURL == "" {
t.Skipf("variable %q not set, skipping keystone connector tests\n", keystoneURLEnv)
return
}
keystoneAdminURL = os.Getenv(keystoneAdminURLEnv)
if keystoneAdminURL == "" {
t.Skipf("variable %q not set, skipping keystone connector tests\n", keystoneAdminURLEnv)
return
}
adminUser = os.Getenv(keystoneAdminUserEnv)
if adminUser == "" {
t.Skipf("variable %q not set, skipping keystone connector tests\n", keystoneAdminUserEnv)
return
}
adminPass = os.Getenv(keystoneAdminPassEnv)
if adminPass == "" {
t.Skipf("variable %q not set, skipping keystone connector tests\n", keystoneAdminPassEnv)
return
}
authTokenURL = keystoneURL + "/v3/auth/tokens/"
usersURL = keystoneAdminURL + "/v3/users/"
groupsURL = keystoneAdminURL + "/v3/groups/"
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("Expected %v to be equal %v", a, b)
}
}

View File

@ -7,13 +7,13 @@ import (
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"gopkg.in/ldap.v2"
"github.com/go-ldap/ldap/v3"
"github.com/coreos/dex/connector"
"github.com/sirupsen/logrus"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
// Config holds the configuration parameters for the LDAP connector. The LDAP
@ -29,7 +29,7 @@ import (
// # The following field is required if using port 389.
// # insecureNoSSL: true
// rootCA: /etc/dex/ldap.ca
// bindDN: uid=seviceaccount,cn=users,dc=example,dc=com
// bindDN: uid=serviceaccount,cn=users,dc=example,dc=com
// bindPW: password
// userSearch:
// # Would translate to the query "(&(objectClass=person)(uid=<username>))"
@ -39,17 +39,30 @@ import (
// idAttr: uid
// emailAttr: mail
// nameAttr: name
// preferredUsernameAttr: uid
// groupSearch:
// # Would translate to the query "(&(objectClass=group)(member=<user uid>))"
// # Would translate to the separate query per user matcher pair and aggregate results into a single group list:
// # "(&(|(objectClass=posixGroup)(objectClass=groupOfNames))(memberUid=<user uid>))"
// # "(&(|(objectClass=posixGroup)(objectClass=groupOfNames))(member=<user DN>))"
// baseDN: cn=groups,dc=example,dc=com
// filter: "(objectClass=group)"
// userAttr: uid
// # Use if full DN is needed and not available as any other attribute
// # Will only work if "DN" attribute does not exist in the record
// # userAttr: DN
// groupAttr: member
// filter: "(|(objectClass=posixGroup)(objectClass=groupOfNames))"
// userMatchers:
// - userAttr: uid
// groupAttr: memberUid
// # Use if full DN is needed and not available as any other attribute
// # Will only work if "DN" attribute does not exist in the record:
// - userAttr: DN
// groupAttr: member
// nameAttr: name
//
// UserMatcher holds information about user and group matching.
type UserMatcher struct {
UserAttr string `json:"userAttr"`
GroupAttr string `json:"groupAttr"`
}
// Config holds configuration options for LDAP logins.
type Config struct {
// The host and optional port of the LDAP server. If port isn't supplied, it will be
// guessed based on the TLS configuration. 389 or 636.
@ -68,7 +81,10 @@ type Config struct {
// Path to a trusted root certificate file.
RootCA string `json:"rootCA"`
// Path to a client cert file generated by rootCA.
ClientCert string `json:"clientCert"`
// Path to a client private key file generated by rootCA.
ClientKey string `json:"clientKey"`
// Base64 encoded PEM data containing root CAs.
RootCAData []byte `json:"rootCAData"`
@ -77,9 +93,14 @@ type Config struct {
BindDN string `json:"bindDN"`
BindPW string `json:"bindPW"`
// UsernamePrompt allows users to override the username attribute (displayed
// in the username/password prompt). If unset, the handler will use
// "Username".
UsernamePrompt string `json:"usernamePrompt"`
// User entry search configuration.
UserSearch struct {
// BsaeDN to start the search from. For example "cn=users,dc=example,dc=com"
// BaseDN to start the search from. For example "cn=users,dc=example,dc=com"
BaseDN string `json:"baseDN"`
// Optional filter to apply when searching the directory. For example "(objectClass=person)"
@ -95,15 +116,19 @@ type Config struct {
Scope string `json:"scope"`
// A mapping of attributes on the user entry to claims.
IDAttr string `json:"idAttr"` // Defaults to "uid"
EmailAttr string `json:"emailAttr"` // Defaults to "mail"
NameAttr string `json:"nameAttr"` // No default.
IDAttr string `json:"idAttr"` // Defaults to "uid"
EmailAttr string `json:"emailAttr"` // Defaults to "mail"
NameAttr string `json:"nameAttr"` // No default.
PreferredUsernameAttrAttr string `json:"preferredUsernameAttr"` // No default.
// If this is set, the email claim of the id token will be constructed from the idAttr and
// value of emailSuffix. This should not include the @ character.
EmailSuffix string `json:"emailSuffix"` // No default.
} `json:"userSearch"`
// Group search configuration.
GroupSearch struct {
// BsaeDN to start the search from. For example "cn=groups,dc=example,dc=com"
// BaseDN to start the search from. For example "cn=groups,dc=example,dc=com"
BaseDN string `json:"baseDN"`
// Optional filter to apply when searching the directory. For example "(objectClass=posixGroup)"
@ -111,16 +136,22 @@ type Config struct {
Scope string `json:"scope"` // Defaults to "sub"
// These two fields are use to match a user to a group.
// DEPRECATED config options. Those are left for backward compatibility.
// See "UserMatchers" below for the current group to user matching implementation
// TODO: should be eventually removed from the code
UserAttr string `json:"userAttr"`
GroupAttr string `json:"groupAttr"`
// Array of the field pairs used to match a user to a group.
// See the "UserMatcher" struct for the exact field names
//
// It adds an additional requirement to the filter that an attribute in the group
// Each pair adds an additional requirement to the filter that an attribute in the group
// match the user's attribute value. For example that the "members" attribute of
// a group matches the "uid" of the user. The exact filter being added is:
//
// (<groupAttr>=<userAttr value>)
// (userMatchers[n].<groupAttr>=userMatchers[n].<userAttr value>)
//
UserAttr string `json:"userAttr"`
GroupAttr string `json:"groupAttr"`
UserMatchers []UserMatcher `json:"userMatchers"`
// The attribute of the group that represents its name.
NameAttr string `json:"nameAttr"`
@ -152,8 +183,26 @@ func parseScope(s string) (int, bool) {
return 0, false
}
// Build a list of group attr name to user attr value matchers.
// Function exists here to allow backward compatibility between old and new
// group to user matching implementations.
// See "Config.GroupSearch.UserMatchers" comments for the details
func userMatchers(c *Config, logger log.Logger) []UserMatcher {
if len(c.GroupSearch.UserMatchers) > 0 && c.GroupSearch.UserMatchers[0].UserAttr != "" {
return c.GroupSearch.UserMatchers
}
log.Deprecated(logger, `LDAP: use groupSearch.userMatchers option instead of "userAttr/groupAttr" fields.`)
return []UserMatcher{
{
UserAttr: c.GroupSearch.UserAttr,
GroupAttr: c.GroupSearch.GroupAttr,
},
}
}
// Open returns an authentication strategy using LDAP.
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
conn, err := c.OpenConnector(logger)
if err != nil {
return nil, err
@ -167,16 +216,16 @@ type refreshData struct {
}
// OpenConnector is the same as Open but returns a type with all implemented connector interfaces.
func (c *Config) OpenConnector(logger logrus.FieldLogger) (interface {
func (c *Config) OpenConnector(logger log.Logger) (interface {
connector.Connector
connector.PasswordConnector
connector.RefreshConnector
}, error) {
}, error,
) {
return c.openConnector(logger)
}
func (c *Config) openConnector(logger logrus.FieldLogger) (*ldapConnector, error) {
func (c *Config) openConnector(logger log.Logger) (*ldapConnector, error) {
requiredFields := []struct {
name string
val string
@ -199,9 +248,9 @@ func (c *Config) openConnector(logger logrus.FieldLogger) (*ldapConnector, error
if host, _, err = net.SplitHostPort(c.Host); err != nil {
host = c.Host
if c.InsecureNoSSL {
c.Host = c.Host + ":389"
c.Host += ":389"
} else {
c.Host = c.Host + ":636"
c.Host += ":636"
}
}
@ -210,7 +259,7 @@ func (c *Config) openConnector(logger logrus.FieldLogger) (*ldapConnector, error
data := c.RootCAData
if len(data) == 0 {
var err error
if data, err = ioutil.ReadFile(c.RootCA); err != nil {
if data, err = os.ReadFile(c.RootCA); err != nil {
return nil, fmt.Errorf("ldap: read ca file: %v", err)
}
}
@ -220,6 +269,14 @@ func (c *Config) openConnector(logger logrus.FieldLogger) (*ldapConnector, error
}
tlsConfig.RootCAs = rootCAs
}
if c.ClientKey != "" && c.ClientCert != "" {
cert, err := tls.LoadX509KeyPair(c.ClientCert, c.ClientKey)
if err != nil {
return nil, fmt.Errorf("ldap: load client cert failed: %v", err)
}
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
}
userSearchScope, ok := parseScope(c.UserSearch.Scope)
if !ok {
return nil, fmt.Errorf("userSearch.Scope unknown value %q", c.UserSearch.Scope)
@ -228,6 +285,9 @@ func (c *Config) openConnector(logger logrus.FieldLogger) (*ldapConnector, error
if !ok {
return nil, fmt.Errorf("groupSearch.Scope unknown value %q", c.GroupSearch.Scope)
}
// TODO(nabokihms): remove it after deleting deprecated groupSearch options
c.GroupSearch.UserMatchers = userMatchers(c, logger)
return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig, logger}, nil
}
@ -239,7 +299,7 @@ type ldapConnector struct {
tlsConfig *tls.Config
logger logrus.FieldLogger
logger log.Logger
}
var (
@ -250,7 +310,7 @@ var (
// do initializes a connection to the LDAP directory and passes it to the
// provided function. It then performs appropriate teardown or reuse before
// returning.
func (c *ldapConnector) do(ctx context.Context, f func(c *ldap.Conn) error) error {
func (c *ldapConnector) do(_ context.Context, f func(c *ldap.Conn) error) error {
// TODO(ericchiang): support context here
var (
conn *ldap.Conn
@ -276,7 +336,11 @@ func (c *ldapConnector) do(ctx context.Context, f func(c *ldap.Conn) error) erro
defer conn.Close()
// If bindDN and bindPW are empty this will default to an anonymous bind.
if err := conn.Bind(c.BindDN, c.BindPW); err != nil {
if c.BindDN == "" && c.BindPW == "" {
if err := conn.UnauthenticatedBind(""); err != nil {
return fmt.Errorf("ldap: initial anonymous bind failed: %v", err)
}
} else if err := conn.Bind(c.BindDN, c.BindPW); err != nil {
return fmt.Errorf("ldap: initial bind for user %q failed: %v", c.BindDN, err)
}
@ -312,11 +376,6 @@ func (c *ldapConnector) identityFromEntry(user ldap.Entry) (ident connector.Iden
if ident.UserID = getAttr(user, c.UserSearch.IDAttr); ident.UserID == "" {
missing = append(missing, c.UserSearch.IDAttr)
}
if ident.Email = getAttr(user, c.UserSearch.EmailAttr); ident.Email == "" {
missing = append(missing, c.UserSearch.EmailAttr)
}
// TODO(ericchiang): Let this value be set from an attribute.
ident.EmailVerified = true
if c.UserSearch.NameAttr != "" {
if ident.Username = getAttr(user, c.UserSearch.NameAttr); ident.Username == "" {
@ -324,6 +383,20 @@ func (c *ldapConnector) identityFromEntry(user ldap.Entry) (ident connector.Iden
}
}
if c.UserSearch.PreferredUsernameAttrAttr != "" {
if ident.PreferredUsername = getAttr(user, c.UserSearch.PreferredUsernameAttrAttr); ident.PreferredUsername == "" {
missing = append(missing, c.UserSearch.PreferredUsernameAttrAttr)
}
}
if c.UserSearch.EmailSuffix != "" {
ident.Email = ident.Username + "@" + c.UserSearch.EmailSuffix
} else if ident.Email = getAttr(user, c.UserSearch.EmailAttr); ident.Email == "" {
missing = append(missing, c.UserSearch.EmailAttr)
}
// TODO(ericchiang): Let this value be set from an attribute.
ident.EmailVerified = true
if len(missing) != 0 {
err := fmt.Errorf("ldap: entry %q missing following required attribute(s): %q", user.DN, missing)
return connector.Identity{}, err
@ -332,7 +405,6 @@ func (c *ldapConnector) identityFromEntry(user ldap.Entry) (ident connector.Iden
}
func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.Entry, found bool, err error) {
filter := fmt.Sprintf("(%s=%s)", c.UserSearch.Username, ldap.EscapeFilter(username))
if c.UserSearch.Filter != "" {
filter = fmt.Sprintf("(&%s%s)", c.UserSearch.Filter, filter)
@ -347,15 +419,22 @@ func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.E
Attributes: []string{
c.UserSearch.IDAttr,
c.UserSearch.EmailAttr,
c.GroupSearch.UserAttr,
// TODO(ericchiang): what if this contains duplicate values?
},
}
for _, matcher := range c.GroupSearch.UserMatchers {
req.Attributes = append(req.Attributes, matcher.UserAttr)
}
if c.UserSearch.NameAttr != "" {
req.Attributes = append(req.Attributes, c.UserSearch.NameAttr)
}
if c.UserSearch.PreferredUsernameAttrAttr != "" {
req.Attributes = append(req.Attributes, c.UserSearch.PreferredUsernameAttrAttr)
}
c.logger.Infof("performing ldap search %s %s %s",
req.BaseDN, scopeString(req.Scope), req.Filter)
resp, err := conn.Search(req)
@ -404,12 +483,17 @@ func (c *ldapConnector) Login(ctx context.Context, s connector.Scopes, username,
if err := conn.Bind(user.DN, password); err != nil {
// Detect a bad password through the LDAP error code.
if ldapErr, ok := err.(*ldap.Error); ok {
if ldapErr.ResultCode == ldap.LDAPResultInvalidCredentials {
switch ldapErr.ResultCode {
case ldap.LDAPResultInvalidCredentials:
c.logger.Errorf("ldap: invalid password for user %q", user.DN)
incorrectPass = true
return nil
case ldap.LDAPResultConstraintViolation:
c.logger.Errorf("ldap: constraint violation for user %q: %s", user.DN, ldapErr.Error())
incorrectPass = true
return nil
}
}
} // will also catch all ldap.Error without a case statement above
return fmt.Errorf("ldap: failed to bind as dn %q: %v", user.DN, err)
}
return nil
@ -451,7 +535,7 @@ func (c *ldapConnector) Login(ctx context.Context, s connector.Scopes, username,
func (c *ldapConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
var data refreshData
if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
return ident, fmt.Errorf("ldap: failed to unamrshal internal data: %v", err)
return ident, fmt.Errorf("ldap: failed to unmarshal internal data: %v", err)
}
var user ldap.Entry
@ -496,40 +580,42 @@ func (c *ldapConnector) groups(ctx context.Context, user ldap.Entry) ([]string,
}
var groups []*ldap.Entry
for _, attr := range getAttrs(user, c.GroupSearch.UserAttr) {
filter := fmt.Sprintf("(%s=%s)", c.GroupSearch.GroupAttr, ldap.EscapeFilter(attr))
if c.GroupSearch.Filter != "" {
filter = fmt.Sprintf("(&%s%s)", c.GroupSearch.Filter, filter)
}
req := &ldap.SearchRequest{
BaseDN: c.GroupSearch.BaseDN,
Filter: filter,
Scope: c.groupSearchScope,
Attributes: []string{c.GroupSearch.NameAttr},
}
gotGroups := false
if err := c.do(ctx, func(conn *ldap.Conn) error {
c.logger.Infof("performing ldap search %s %s %s",
req.BaseDN, scopeString(req.Scope), req.Filter)
resp, err := conn.Search(req)
if err != nil {
return fmt.Errorf("ldap: search failed: %v", err)
for _, matcher := range c.GroupSearch.UserMatchers {
for _, attr := range getAttrs(user, matcher.UserAttr) {
filter := fmt.Sprintf("(%s=%s)", matcher.GroupAttr, ldap.EscapeFilter(attr))
if c.GroupSearch.Filter != "" {
filter = fmt.Sprintf("(&%s%s)", c.GroupSearch.Filter, filter)
}
req := &ldap.SearchRequest{
BaseDN: c.GroupSearch.BaseDN,
Filter: filter,
Scope: c.groupSearchScope,
Attributes: []string{c.GroupSearch.NameAttr},
}
gotGroups := false
if err := c.do(ctx, func(conn *ldap.Conn) error {
c.logger.Infof("performing ldap search %s %s %s",
req.BaseDN, scopeString(req.Scope), req.Filter)
resp, err := conn.Search(req)
if err != nil {
return fmt.Errorf("ldap: search failed: %v", err)
}
gotGroups = len(resp.Entries) != 0
groups = append(groups, resp.Entries...)
return nil
}); err != nil {
return nil, err
}
if !gotGroups {
// TODO(ericchiang): Is this going to spam the logs?
c.logger.Errorf("ldap: groups search with filter %q returned no groups", filter)
}
gotGroups = len(resp.Entries) != 0
groups = append(groups, resp.Entries...)
return nil
}); err != nil {
return nil, err
}
if !gotGroups {
// TODO(ericchiang): Is this going to spam the logs?
c.logger.Errorf("ldap: groups search with filter %q returned no groups", filter)
}
}
var groupNames []string
groupNames := make([]string, 0, len(groups))
for _, group := range groups {
name := getAttr(*group, c.GroupSearch.NameAttr)
if name == "" {
@ -545,3 +631,7 @@ func (c *ldapConnector) groups(ctx context.Context, user ldap.Entry) ([]string,
}
return groupNames, nil
}
func (c *ldapConnector) Prompt() string {
return c.UsernamePrompt
}

View File

@ -1,26 +1,18 @@
package ldap
import (
"bytes"
"context"
"io/ioutil"
"net/url"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"sync"
"testing"
"text/template"
"time"
"github.com/kylelemons/godebug/pretty"
"github.com/sirupsen/logrus"
"github.com/coreos/dex/connector"
"github.com/dexidp/dex/connector"
)
const envVar = "DEX_LDAP_TESTS"
// connectionMethod indicates how the test should connect to the LDAP server.
type connectionMethod int32
@ -28,6 +20,7 @@ const (
connectStartTLS connectionMethod = iota
connectLDAPS
connectLDAP
connectInsecureSkipVerify
)
// subtest is a login test against a given schema.
@ -48,35 +41,8 @@ type subtest struct {
}
func TestQuery(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.BaseDN = "ou=People,ou=TestQuery,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
@ -88,7 +54,7 @@ userpassword: bar
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
UserID: "cn=jane,ou=People,ou=TestQuery,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
@ -99,7 +65,7 @@ userpassword: bar
username: "john",
password: "bar",
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
UserID: "cn=john,ou=People,ou=TestQuery,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
@ -119,63 +85,108 @@ userpassword: bar
},
}
runTests(t, schema, connectLDAP, c, tests)
runTests(t, connectLDAP, c, tests)
}
func TestGroupQuery(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Groups,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,dc=example,dc=org
member: cn=jane,ou=People,dc=example,dc=org
dn: cn=developers,ou=Groups,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,dc=example,dc=org
`
func TestQueryWithEmailSuffix(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.BaseDN = "ou=People,ou=TestQueryWithEmailSuffix,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailSuffix = "test.example.com"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "ignoremailattr",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=TestQueryWithEmailSuffix,dc=example,dc=org",
Username: "jane",
Email: "jane@test.example.com",
EmailVerified: true,
},
},
{
name: "nomailattr",
username: "john",
password: "bar",
want: connector.Identity{
UserID: "cn=john,ou=People,ou=TestQueryWithEmailSuffix,dc=example,dc=org",
Username: "john",
Email: "john@test.example.com",
EmailVerified: true,
},
},
}
runTests(t, connectLDAP, c, tests)
}
func TestUserFilter(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=TestUserFilter,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=Groups,dc=example,dc=org"
c.GroupSearch.UserAttr = "DN"
c.GroupSearch.GroupAttr = "member"
c.UserSearch.Filter = "(ou:dn:=Seattle)"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=Seattle,ou=TestUserFilter,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
want: connector.Identity{
UserID: "cn=john,ou=People,ou=Seattle,ou=TestUserFilter,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
},
},
{
name: "invalidpassword",
username: "jane",
password: "badpassword",
wantBadPW: true,
},
{
name: "invaliduser",
username: "idontexist",
password: "foo",
wantBadPW: true, // Want invalid password, not a query error.
},
}
runTests(t, connectLDAP, c, tests)
}
func TestGroupQuery(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=People,ou=TestGroupQuery,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=Groups,ou=TestGroupQuery,dc=example,dc=org"
c.GroupSearch.UserMatchers = []UserMatcher{
{
UserAttr: "DN",
GroupAttr: "member",
},
}
c.GroupSearch.NameAttr = "cn"
tests := []subtest{
@ -185,7 +196,7 @@ member: cn=jane,ou=People,dc=example,dc=org
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
UserID: "cn=jane,ou=People,ou=TestGroupQuery,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
@ -198,7 +209,7 @@ member: cn=jane,ou=People,dc=example,dc=org
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
UserID: "cn=john,ou=People,ou=TestGroupQuery,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
@ -207,74 +218,23 @@ member: cn=jane,ou=People,dc=example,dc=org
},
}
runTests(t, schema, connectLDAP, c, tests)
runTests(t, connectLDAP, c, tests)
}
func TestGroupsOnUserEntity(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
# Groups are enumerated as part of the user entity instead of the members being
# a list on the group entity.
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
departmentNumber: 1000
departmentNumber: 1001
dn: cn=john,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
departmentNumber: 1000
departmentNumber: 1002
# Group definitions. Notice that they don't have any "member" field.
dn: ou=Groups,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: admins
gidNumber: 1000
dn: cn=developers,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: developers
gidNumber: 1001
dn: cn=designers,ou=Groups,dc=example,dc=org
objectClass: posixGroup
cn: designers
gidNumber: 1002
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.BaseDN = "ou=People,ou=TestGroupsOnUserEntity,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=Groups,dc=example,dc=org"
c.GroupSearch.UserAttr = "departmentNumber"
c.GroupSearch.GroupAttr = "gidNumber"
c.GroupSearch.BaseDN = "ou=Groups,ou=TestGroupsOnUserEntity,dc=example,dc=org"
c.GroupSearch.UserMatchers = []UserMatcher{
{
UserAttr: "departmentNumber",
GroupAttr: "gidNumber",
},
}
c.GroupSearch.NameAttr = "cn"
tests := []subtest{
{
@ -283,7 +243,7 @@ gidNumber: 1002
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
UserID: "cn=jane,ou=People,ou=TestGroupsOnUserEntity,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
@ -296,7 +256,7 @@ gidNumber: 1002
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,dc=example,dc=org",
UserID: "cn=john,ou=People,ou=TestGroupsOnUserEntity,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
@ -304,31 +264,162 @@ gidNumber: 1002
},
},
}
runTests(t, schema, connectLDAP, c, tests)
runTests(t, connectLDAP, c, tests)
}
func TestGroupFilter(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=People,ou=TestGroupFilter,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=TestGroupFilter,dc=example,dc=org"
c.GroupSearch.UserMatchers = []UserMatcher{
{
UserAttr: "DN",
GroupAttr: "member",
},
}
c.GroupSearch.NameAttr = "cn"
c.GroupSearch.Filter = "(ou:dn:=Seattle)" // ignore other groups
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=TestGroupFilter,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "developers"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,ou=TestGroupFilter,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
Groups: []string{"admins"},
},
},
}
runTests(t, connectLDAP, c, tests)
}
func TestGroupToUserMatchers(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=TestGroupToUserMatchers,dc=example,dc=org"
c.GroupSearch.UserMatchers = []UserMatcher{
{
UserAttr: "DN",
GroupAttr: "member",
},
{
UserAttr: "uid",
GroupAttr: "memberUid",
},
}
c.GroupSearch.NameAttr = "cn"
c.GroupSearch.Filter = "(|(objectClass=posixGroup)(objectClass=groupOfNames))" // search all group types
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "developers", "frontend"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "qa", "logger"},
},
},
}
runTests(t, connectLDAP, c, tests)
}
// Test deprecated group to user matching implementation
// which was left for backward compatibility.
// See "Config.GroupSearch.UserMatchers" comments for the details
func TestDeprecatedGroupToUserMatcher(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
c.GroupSearch.BaseDN = "ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org"
c.GroupSearch.UserAttr = "DN"
c.GroupSearch.GroupAttr = "member"
c.GroupSearch.NameAttr = "cn"
c.GroupSearch.Filter = "(ou:dn:=Seattle)" // ignore other groups
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
groups: true,
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
Groups: []string{"admins", "developers"},
},
},
{
name: "validpassword2",
username: "john",
password: "bar",
groups: true,
want: connector.Identity{
UserID: "cn=john,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org",
Username: "john",
Email: "johndoe@example.com",
EmailVerified: true,
Groups: []string{"admins"},
},
},
}
runTests(t, connectLDAP, c, tests)
}
func TestStartTLS(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.BaseDN = "ou=People,ou=TestStartTLS,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
@ -340,38 +431,43 @@ userpassword: foo
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
UserID: "cn=jane,ou=People,ou=TestStartTLS,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
}
runTests(t, schema, connectStartTLS, c, tests)
runTests(t, connectStartTLS, c, tests)
}
func TestInsecureSkipVerify(t *testing.T) {
c := &Config{}
c.UserSearch.BaseDN = "ou=People,ou=TestInsecureSkipVerify,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
c.UserSearch.Username = "cn"
tests := []subtest{
{
name: "validpassword",
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,ou=TestInsecureSkipVerify,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
}
runTests(t, connectInsecureSkipVerify, c, tests)
}
func TestLDAPS(t *testing.T) {
schema := `
dn: dc=example,dc=org
objectClass: dcObject
objectClass: organization
o: Example Company
dc: example
dn: ou=People,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
`
c := &Config{}
c.UserSearch.BaseDN = "ou=People,dc=example,dc=org"
c.UserSearch.BaseDN = "ou=People,ou=TestLDAPS,dc=example,dc=org"
c.UserSearch.NameAttr = "cn"
c.UserSearch.EmailAttr = "mail"
c.UserSearch.IDAttr = "DN"
@ -383,139 +479,56 @@ userpassword: foo
username: "jane",
password: "foo",
want: connector.Identity{
UserID: "cn=jane,ou=People,dc=example,dc=org",
UserID: "cn=jane,ou=People,ou=TestLDAPS,dc=example,dc=org",
Username: "jane",
Email: "janedoe@example.com",
EmailVerified: true,
},
},
}
runTests(t, schema, connectLDAPS, c, tests)
runTests(t, connectLDAPS, c, tests)
}
// runTests runs a set of tests against an LDAP schema. It does this by
// setting up an OpenLDAP server and injecting the provided scheme.
func TestUsernamePrompt(t *testing.T) {
tests := map[string]struct {
config Config
expected string
}{
"with usernamePrompt unset it returns \"\"": {
config: Config{},
expected: "",
},
"with usernamePrompt set it returns that": {
config: Config{UsernamePrompt: "Email address"},
expected: "Email address",
},
}
for n, d := range tests {
t.Run(n, func(t *testing.T) {
conn := &ldapConnector{Config: d.config}
if actual := conn.Prompt(); actual != d.expected {
t.Errorf("expected %v, got %v", d.expected, actual)
}
})
}
}
func getenv(key, defaultVal string) string {
if val := os.Getenv(key); val != "" {
return val
}
return defaultVal
}
// runTests runs a set of tests against an LDAP schema.
//
// The tests require the slapd and ldapadd binaries available in the host
// machine's PATH.
//
// The DEX_LDAP_TESTS must be set to "1"
func runTests(t *testing.T, schema string, connMethod connectionMethod, config *Config, tests []subtest) {
if os.Getenv(envVar) != "1" {
t.Skipf("%s not set. Skipping test (run 'export %s=1' to run tests)", envVar, envVar)
}
for _, cmd := range []string{"slapd", "ldapadd"} {
if _, err := exec.LookPath(cmd); err != nil {
t.Errorf("%s not available", cmd)
}
}
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
configBytes := new(bytes.Buffer)
data := tmplData{
TempDir: tempDir,
Includes: includes(t, wd),
}
data.TLSCertPath, data.TLSKeyPath = tlsAssets(t, wd)
if err := slapdConfigTmpl.Execute(configBytes, data); err != nil {
t.Fatal(err)
}
configPath := filepath.Join(tempDir, "ldap.conf")
if err := ioutil.WriteFile(configPath, configBytes.Bytes(), 0644); err != nil {
t.Fatal(err)
}
schemaPath := filepath.Join(tempDir, "schema.ldap")
if err := ioutil.WriteFile(schemaPath, []byte(schema), 0644); err != nil {
t.Fatal(err)
}
socketPath := url.QueryEscape(filepath.Join(tempDir, "ldap.unix"))
slapdOut := new(bytes.Buffer)
cmd := exec.Command(
"slapd",
"-d", "any",
"-h", "ldap://localhost:10389/ ldaps://localhost:10636/ ldapi://"+socketPath,
"-f", configPath,
)
cmd.Stdout = slapdOut
cmd.Stderr = slapdOut
if err := cmd.Start(); err != nil {
t.Fatal(err)
}
var (
// Wait group finishes once slapd has exited.
//
// Use a wait group because multiple goroutines can't listen on
// cmd.Wait(). It triggers the race detector.
wg = new(sync.WaitGroup)
// Ensure only one condition can set the slapdFailed boolean.
once = new(sync.Once)
slapdFailed bool
)
wg.Add(1)
go func() { cmd.Wait(); wg.Done() }()
defer func() {
if slapdFailed {
// If slapd exited before it was killed, print its logs.
t.Logf("%s\n", slapdOut)
}
}()
go func() {
wg.Wait()
once.Do(func() { slapdFailed = true })
}()
defer func() {
once.Do(func() { slapdFailed = false })
cmd.Process.Kill()
wg.Wait()
}()
// Try a few times to connect to the LDAP server. On slower machines
// it can take a while for it to come up.
connected := false
wait := 100 * time.Millisecond
for i := 0; i < 5; i++ {
time.Sleep(wait)
ldapadd := exec.Command(
"ldapadd", "-x",
"-D", "cn=admin,dc=example,dc=org",
"-w", "admin",
"-f", schemaPath,
"-H", "ldap://localhost:10389/",
)
if out, err := ldapadd.CombinedOutput(); err != nil {
t.Logf("ldapadd: %s", out)
wait = wait * 2 // backoff
continue
}
connected = true
break
}
if !connected {
t.Errorf("ldapadd command failed")
return
// The tests require LDAP to be runnning.
// You can use the provided docker-compose file to setup an LDAP server.
func runTests(t *testing.T, connMethod connectionMethod, config *Config, tests []subtest) {
ldapHost := os.Getenv("DEX_LDAP_HOST")
if ldapHost == "" {
t.Skipf(`test environment variable "DEX_LDAP_HOST" not set, skipping`)
}
// Shallow copy.
@ -525,21 +538,24 @@ func runTests(t *testing.T, schema string, connMethod connectionMethod, config *
// group search configuration.
switch connMethod {
case connectStartTLS:
c.Host = "localhost:10389"
c.RootCA = "testdata/ca.crt"
c.Host = fmt.Sprintf("%s:%s", ldapHost, getenv("DEX_LDAP_PORT", "389"))
c.RootCA = "testdata/certs/ca.crt"
c.StartTLS = true
case connectLDAPS:
c.Host = "localhost:10636"
c.RootCA = "testdata/ca.crt"
c.Host = fmt.Sprintf("%s:%s", ldapHost, getenv("DEX_LDAP_TLS_PORT", "636"))
c.RootCA = "testdata/certs/ca.crt"
case connectInsecureSkipVerify:
c.Host = fmt.Sprintf("%s:%s", ldapHost, getenv("DEX_LDAP_TLS_PORT", "636"))
c.InsecureSkipVerify = true
case connectLDAP:
c.Host = "localhost:10389"
c.Host = fmt.Sprintf("%s:%s", ldapHost, getenv("DEX_LDAP_PORT", "389"))
c.InsecureNoSSL = true
}
c.BindDN = "cn=admin,dc=example,dc=org"
c.BindPW = "admin"
l := &logrus.Logger{Out: ioutil.Discard, Formatter: &logrus.TextFormatter{}}
l := &logrus.Logger{Out: io.Discard, Formatter: &logrus.TextFormatter{}}
conn, err := c.openConnector(l)
if err != nil {
@ -598,98 +614,3 @@ func runTests(t *testing.T, schema string, connMethod connectionMethod, config *
})
}
}
// Standard OpenLDAP schema files to include.
//
// These are copied from the /etc/openldap/schema directory.
var includeFiles = []string{
"core.schema",
"cosine.schema",
"inetorgperson.schema",
"misc.schema",
"nis.schema",
"openldap.schema",
}
// tmplData is the struct used to execute the SLAPD config template.
type tmplData struct {
// Directory for database to be writen to.
TempDir string
// List of schema files to include.
Includes []string
// TLS assets for LDAPS.
TLSKeyPath string
TLSCertPath string
}
// Config template copied from:
// http://www.zytrax.com/books/ldap/ch5/index.html#step1-slapd
//
// TLS instructions found here:
// http://www.openldap.org/doc/admin24/tls.html
var slapdConfigTmpl = template.Must(template.New("").Parse(`
{{ range $i, $include := .Includes }}
include {{ $include }}
{{ end }}
# MODULELOAD definitions
# not required (comment out) before version 2.3
moduleload back_bdb.la
database bdb
suffix "dc=example,dc=org"
# root or superuser
rootdn "cn=admin,dc=example,dc=org"
rootpw admin
# The database directory MUST exist prior to running slapd AND
# change path as necessary
directory {{ .TempDir }}
TLSCertificateFile {{ .TLSCertPath }}
TLSCertificateKeyFile {{ .TLSKeyPath }}
# Indices to maintain for this directory
# unique id so equality match only
index uid eq
# allows general searching on commonname, givenname and email
index cn,gn,mail eq,sub
# allows multiple variants on surname searching
index sn eq,sub
# sub above includes subintial,subany,subfinal
# optimise department searches
index ou eq
# if searches will include objectClass uncomment following
# index objectClass eq
# shows use of default index parameter
index default eq,sub
# indices missing - uses default eq,sub
index telephonenumber
# other database parameters
# read more in slapd.conf reference section
cachesize 10000
checkpoint 128 15
`))
func tlsAssets(t *testing.T, wd string) (certPath, keyPath string) {
certPath = filepath.Join(wd, "testdata", "server.crt")
keyPath = filepath.Join(wd, "testdata", "server.key")
for _, p := range []string{certPath, keyPath} {
if _, err := os.Stat(p); err != nil {
t.Fatalf("failed to find TLS asset file: %s %v", p, err)
}
}
return
}
func includes(t *testing.T, wd string) (paths []string) {
for _, f := range includeFiles {
p := filepath.Join(wd, "testdata", f)
if _, err := os.Stat(p); err != nil {
t.Fatalf("failed to find schema file: %s %v", p, err)
}
paths = append(paths, p)
}
return
}

View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAx5y2viJKOAAcDYSj55odZsbA7dkSQ9afEPd9uaCLOvRYKLJY1S1V
C4m1eVfna8JndSLdsBGDQe4BlBTkEYMYR8CJHtUuBxeAucOH8KlF8rIHXXi71oex
T7kPtJEDINQKOn06bHqNcn0a7ZMWP8jiQ708OYr5P+1T/N82QTAFpDuqK42ZnBqf
8qzQkkTN0UCktY2EWnFTbNIXcMKWQnYP8zt/CG3Q31b2bnQt2iLEa/DIF7RLNjfx
9wPQBBAqgWbLmWfdPpHsAPtQxtItb+GRbPs3aLm06CFKlQuteDoP+suo0EtglHcV
V9Ynvdz0cdJCJ7EPyET6CtLMzc/Puup/AwIBAg==
-----END DH PARAMETERS-----

View File

@ -1,610 +0,0 @@
# OpenLDAP Core schema
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2016 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
#
## Portions Copyright (C) The Internet Society (1997-2006).
## All Rights Reserved.
##
## This document and translations of it may be copied and furnished to
## others, and derivative works that comment on or otherwise explain it
## or assist in its implementation may be prepared, copied, published
## and distributed, in whole or in part, without restriction of any
## kind, provided that the above copyright notice and this paragraph are
## included on all such copies and derivative works. However, this
## document itself may not be modified in any way, such as by removing
## the copyright notice or references to the Internet Society or other
## Internet organizations, except as needed for the purpose of
## developing Internet standards in which case the procedures for
## copyrights defined in the Internet Standards process must be
## followed, or as required to translate it into languages other than
## English.
##
## The limited permissions granted above are perpetual and will not be
## revoked by the Internet Society or its successors or assigns.
##
## This document and the information contained herein is provided on an
## "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
## TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
## BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
## HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
#
#
# Includes LDAPv3 schema items from:
# RFC 2252/2256 (LDAPv3)
#
# Select standard track schema items:
# RFC 1274 (uid/dc)
# RFC 2079 (URI)
# RFC 2247 (dc/dcObject)
# RFC 2587 (PKI)
# RFC 2589 (Dynamic Directory Services)
# RFC 4524 (associatedDomain)
#
# Select informational schema items:
# RFC 2377 (uidObject)
#
# Standard attribute types from RFC 2256
#
# system schema
#attributetype ( 2.5.4.0 NAME 'objectClass'
# DESC 'RFC2256: object classes of the entity'
# EQUALITY objectIdentifierMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
# system schema
#attributetype ( 2.5.4.1 NAME ( 'aliasedObjectName' 'aliasedEntryName' )
# DESC 'RFC2256: name of aliased object'
# EQUALITY distinguishedNameMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
attributetype ( 2.5.4.2 NAME 'knowledgeInformation'
DESC 'RFC2256: knowledge information'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
# system schema
#attributetype ( 2.5.4.3 NAME ( 'cn' 'commonName' )
# DESC 'RFC2256: common name(s) for which the entity is known by'
# SUP name )
attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known by'
SUP name )
attributetype ( 2.5.4.5 NAME 'serialNumber'
DESC 'RFC2256: serial number of the entity'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
# RFC 4519 definition ('countryName' in X.500 and RFC2256)
attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' )
DESC 'RFC4519: two-letter ISO-3166 country code'
SUP name
SYNTAX 1.3.6.1.4.1.1466.115.121.1.11
SINGLE-VALUE )
#attributetype ( 2.5.4.6 NAME ( 'c' 'countryName' )
# DESC 'RFC2256: ISO-3166 country 2-letter code'
# SUP name SINGLE-VALUE )
attributetype ( 2.5.4.7 NAME ( 'l' 'localityName' )
DESC 'RFC2256: locality which this object resides in'
SUP name )
attributetype ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' )
DESC 'RFC2256: state or province which this object resides in'
SUP name )
attributetype ( 2.5.4.9 NAME ( 'street' 'streetAddress' )
DESC 'RFC2256: street address of this object'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 2.5.4.10 NAME ( 'o' 'organizationName' )
DESC 'RFC2256: organization this object belongs to'
SUP name )
attributetype ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' )
DESC 'RFC2256: organizational unit this object belongs to'
SUP name )
attributetype ( 2.5.4.12 NAME 'title'
DESC 'RFC2256: title associated with the entity'
SUP name )
# system schema
#attributetype ( 2.5.4.13 NAME 'description'
# DESC 'RFC2256: descriptive information'
# EQUALITY caseIgnoreMatch
# SUBSTR caseIgnoreSubstringsMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )
# Deprecated by enhancedSearchGuide
attributetype ( 2.5.4.14 NAME 'searchGuide'
DESC 'RFC2256: search guide, deprecated by enhancedSearchGuide'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )
attributetype ( 2.5.4.15 NAME 'businessCategory'
DESC 'RFC2256: business category'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 2.5.4.16 NAME 'postalAddress'
DESC 'RFC2256: postal address'
EQUALITY caseIgnoreListMatch
SUBSTR caseIgnoreListSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 2.5.4.17 NAME 'postalCode'
DESC 'RFC2256: postal code'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attributetype ( 2.5.4.18 NAME 'postOfficeBox'
DESC 'RFC2256: Post Office Box'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )
attributetype ( 2.5.4.19 NAME 'physicalDeliveryOfficeName'
DESC 'RFC2256: Physical Delivery Office Name'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
attributetype ( 2.5.4.20 NAME 'telephoneNumber'
DESC 'RFC2256: Telephone Number'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
attributetype ( 2.5.4.21 NAME 'telexNumber'
DESC 'RFC2256: Telex Number'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
attributetype ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
DESC 'RFC2256: Teletex Terminal Identifier'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
attributetype ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
DESC 'RFC2256: Facsimile (Fax) Telephone Number'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )
attributetype ( 2.5.4.24 NAME 'x121Address'
DESC 'RFC2256: X.121 Address'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )
attributetype ( 2.5.4.25 NAME 'internationaliSDNNumber'
DESC 'RFC2256: international ISDN number'
EQUALITY numericStringMatch
SUBSTR numericStringSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
attributetype ( 2.5.4.26 NAME 'registeredAddress'
DESC 'RFC2256: registered postal address'
SUP postalAddress
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
attributetype ( 2.5.4.27 NAME 'destinationIndicator'
DESC 'RFC2256: destination indicator'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
attributetype ( 2.5.4.28 NAME 'preferredDeliveryMethod'
DESC 'RFC2256: preferred delivery method'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
SINGLE-VALUE )
attributetype ( 2.5.4.29 NAME 'presentationAddress'
DESC 'RFC2256: presentation address'
EQUALITY presentationAddressMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.43
SINGLE-VALUE )
attributetype ( 2.5.4.30 NAME 'supportedApplicationContext'
DESC 'RFC2256: supported application context'
EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
attributetype ( 2.5.4.31 NAME 'member'
DESC 'RFC2256: member of a group'
SUP distinguishedName )
attributetype ( 2.5.4.32 NAME 'owner'
DESC 'RFC2256: owner (of the object)'
SUP distinguishedName )
attributetype ( 2.5.4.33 NAME 'roleOccupant'
DESC 'RFC2256: occupant of role'
SUP distinguishedName )
# system schema
#attributetype ( 2.5.4.34 NAME 'seeAlso'
# DESC 'RFC2256: DN of related object'
# SUP distinguishedName )
# system schema
#attributetype ( 2.5.4.35 NAME 'userPassword'
# DESC 'RFC2256/2307: password of user'
# EQUALITY octetStringMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
# Must be transferred using ;binary
# with certificateExactMatch rule (per X.509)
attributetype ( 2.5.4.36 NAME 'userCertificate'
DESC 'RFC2256: X.509 user certificate, use ;binary'
EQUALITY certificateExactMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
# Must be transferred using ;binary
# with certificateExactMatch rule (per X.509)
attributetype ( 2.5.4.37 NAME 'cACertificate'
DESC 'RFC2256: X.509 CA certificate, use ;binary'
EQUALITY certificateExactMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )
# Must be transferred using ;binary
attributetype ( 2.5.4.38 NAME 'authorityRevocationList'
DESC 'RFC2256: X.509 authority revocation list, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
# Must be transferred using ;binary
attributetype ( 2.5.4.39 NAME 'certificateRevocationList'
DESC 'RFC2256: X.509 certificate revocation list, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
# Must be stored and requested in the binary form
attributetype ( 2.5.4.40 NAME 'crossCertificatePair'
DESC 'RFC2256: X.509 cross certificate pair, use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )
# system schema
#attributetype ( 2.5.4.41 NAME 'name'
# EQUALITY caseIgnoreMatch
# SUBSTR caseIgnoreSubstringsMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
attributetype ( 2.5.4.42 NAME ( 'givenName' 'gn' )
DESC 'RFC2256: first name(s) for which the entity is known by'
SUP name )
attributetype ( 2.5.4.43 NAME 'initials'
DESC 'RFC2256: initials of some or all of names, but not the surname(s).'
SUP name )
attributetype ( 2.5.4.44 NAME 'generationQualifier'
DESC 'RFC2256: name qualifier indicating a generation'
SUP name )
attributetype ( 2.5.4.45 NAME 'x500UniqueIdentifier'
DESC 'RFC2256: X.500 unique identifier'
EQUALITY bitStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )
attributetype ( 2.5.4.46 NAME 'dnQualifier'
DESC 'RFC2256: DN qualifier'
EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
attributetype ( 2.5.4.47 NAME 'enhancedSearchGuide'
DESC 'RFC2256: enhanced search guide'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
attributetype ( 2.5.4.48 NAME 'protocolInformation'
DESC 'RFC2256: protocol information'
EQUALITY protocolInformationMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )
# system schema
#attributetype ( 2.5.4.49 NAME 'distinguishedName'
# EQUALITY distinguishedNameMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
attributetype ( 2.5.4.50 NAME 'uniqueMember'
DESC 'RFC2256: unique member of a group'
EQUALITY uniqueMemberMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )
attributetype ( 2.5.4.51 NAME 'houseIdentifier'
DESC 'RFC2256: house identifier'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
# Must be transferred using ;binary
attributetype ( 2.5.4.52 NAME 'supportedAlgorithms'
DESC 'RFC2256: supported algorithms'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
# Must be transferred using ;binary
attributetype ( 2.5.4.53 NAME 'deltaRevocationList'
DESC 'RFC2256: delta revocation list; use ;binary'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
attributetype ( 2.5.4.54 NAME 'dmdName'
DESC 'RFC2256: name of DMD'
SUP name )
attributetype ( 2.5.4.65 NAME 'pseudonym'
DESC 'X.520(4th): pseudonym for the object'
SUP name )
# Standard object classes from RFC2256
# system schema
#objectclass ( 2.5.6.0 NAME 'top'
# DESC 'RFC2256: top of the superclass chain'
# ABSTRACT
# MUST objectClass )
# system schema
#objectclass ( 2.5.6.1 NAME 'alias'
# DESC 'RFC2256: an alias'
# SUP top STRUCTURAL
# MUST aliasedObjectName )
objectclass ( 2.5.6.2 NAME 'country'
DESC 'RFC2256: a country'
SUP top STRUCTURAL
MUST c
MAY ( searchGuide $ description ) )
objectclass ( 2.5.6.3 NAME 'locality'
DESC 'RFC2256: a locality'
SUP top STRUCTURAL
MAY ( street $ seeAlso $ searchGuide $ st $ l $ description ) )
objectclass ( 2.5.6.4 NAME 'organization'
DESC 'RFC2256: an organization'
SUP top STRUCTURAL
MUST o
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
objectclass ( 2.5.6.5 NAME 'organizationalUnit'
DESC 'RFC2256: an organizational unit'
SUP top STRUCTURAL
MUST ou
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
objectclass ( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
objectclass ( 2.5.6.7 NAME 'organizationalPerson'
DESC 'RFC2256: an organizational person'
SUP person STRUCTURAL
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
objectclass ( 2.5.6.8 NAME 'organizationalRole'
DESC 'RFC2256: an organizational role'
SUP top STRUCTURAL
MUST cn
MAY ( x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
seeAlso $ roleOccupant $ preferredDeliveryMethod $ street $
postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ ou $ st $ l $ description ) )
objectclass ( 2.5.6.9 NAME 'groupOfNames'
DESC 'RFC2256: a group of names (DNs)'
SUP top STRUCTURAL
MUST ( member $ cn )
MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
objectclass ( 2.5.6.10 NAME 'residentialPerson'
DESC 'RFC2256: an residential person'
SUP person STRUCTURAL
MUST l
MAY ( businessCategory $ x121Address $ registeredAddress $
destinationIndicator $ preferredDeliveryMethod $ telexNumber $
teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ preferredDeliveryMethod $ street $
postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l ) )
objectclass ( 2.5.6.11 NAME 'applicationProcess'
DESC 'RFC2256: an application process'
SUP top STRUCTURAL
MUST cn
MAY ( seeAlso $ ou $ l $ description ) )
objectclass ( 2.5.6.12 NAME 'applicationEntity'
DESC 'RFC2256: an application entity'
SUP top STRUCTURAL
MUST ( presentationAddress $ cn )
MAY ( supportedApplicationContext $ seeAlso $ ou $ o $ l $
description ) )
objectclass ( 2.5.6.13 NAME 'dSA'
DESC 'RFC2256: a directory system agent (a server)'
SUP applicationEntity STRUCTURAL
MAY knowledgeInformation )
objectclass ( 2.5.6.14 NAME 'device'
DESC 'RFC2256: a device'
SUP top STRUCTURAL
MUST cn
MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) )
objectclass ( 2.5.6.15 NAME 'strongAuthenticationUser'
DESC 'RFC2256: a strong authentication user'
SUP top AUXILIARY
MUST userCertificate )
objectclass ( 2.5.6.16 NAME 'certificationAuthority'
DESC 'RFC2256: a certificate authority'
SUP top AUXILIARY
MUST ( authorityRevocationList $ certificateRevocationList $
cACertificate ) MAY crossCertificatePair )
objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames'
DESC 'RFC2256: a group of unique names (DN and Unique Identifier)'
SUP top STRUCTURAL
MUST ( uniqueMember $ cn )
MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )
objectclass ( 2.5.6.18 NAME 'userSecurityInformation'
DESC 'RFC2256: a user security information'
SUP top AUXILIARY
MAY ( supportedAlgorithms ) )
objectclass ( 2.5.6.16.2 NAME 'certificationAuthority-V2'
SUP certificationAuthority
AUXILIARY MAY ( deltaRevocationList ) )
objectclass ( 2.5.6.19 NAME 'cRLDistributionPoint'
SUP top STRUCTURAL
MUST ( cn )
MAY ( certificateRevocationList $ authorityRevocationList $
deltaRevocationList ) )
objectclass ( 2.5.6.20 NAME 'dmd'
SUP top STRUCTURAL
MUST ( dmdName )
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ st $ l $ description ) )
#
# Object Classes from RFC 2587
#
objectclass ( 2.5.6.21 NAME 'pkiUser'
DESC 'RFC2587: a PKI user'
SUP top AUXILIARY
MAY userCertificate )
objectclass ( 2.5.6.22 NAME 'pkiCA'
DESC 'RFC2587: PKI certificate authority'
SUP top AUXILIARY
MAY ( authorityRevocationList $ certificateRevocationList $
cACertificate $ crossCertificatePair ) )
objectclass ( 2.5.6.23 NAME 'deltaCRL'
DESC 'RFC2587: PKI user'
SUP top AUXILIARY
MAY deltaRevocationList )
#
# Standard Track URI label schema from RFC 2079
# system schema
#attributetype ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI'
# DESC 'RFC2079: Uniform Resource Identifier with optional label'
# EQUALITY caseExactMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
objectclass ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject'
DESC 'RFC2079: object that contains the URI attribute type'
SUP top AUXILIARY
MAY ( labeledURI ) )
#
# Derived from RFC 1274, but with new "short names"
#
#attributetype ( 0.9.2342.19200300.100.1.1
# NAME ( 'uid' 'userid' )
# DESC 'RFC1274: user identifier'
# EQUALITY caseIgnoreMatch
# SUBSTR caseIgnoreSubstringsMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
attributetype ( 0.9.2342.19200300.100.1.3
NAME ( 'mail' 'rfc822Mailbox' )
DESC 'RFC1274: RFC822 Mailbox'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
objectclass ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
DESC 'RFC1274: simple security object'
SUP top AUXILIARY
MUST userPassword )
# RFC 1274 + RFC 2247
attributetype ( 0.9.2342.19200300.100.1.25
NAME ( 'dc' 'domainComponent' )
DESC 'RFC1274/2247: domain component'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
# RFC 2247
objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
DESC 'RFC2247: domain component object'
SUP top AUXILIARY MUST dc )
# RFC 2377
objectclass ( 1.3.6.1.1.3.1 NAME 'uidObject'
DESC 'RFC2377: uid object'
SUP top AUXILIARY MUST uid )
# RFC 4524
# The 'associatedDomain' attribute specifies DNS [RFC1034][RFC2181]
# host names [RFC1123] that are associated with an object. That is,
# values of this attribute should conform to the following ABNF:
#
# domain = root / label *( DOT label )
# root = SPACE
# label = LETDIG [ *61( LETDIG / HYPHEN ) LETDIG ]
# LETDIG = %x30-39 / %x41-5A / %x61-7A ; "0" - "9" / "A"-"Z" / "a"-"z"
# SPACE = %x20 ; space (" ")
# HYPHEN = %x2D ; hyphen ("-")
# DOT = %x2E ; period (".")
attributetype ( 0.9.2342.19200300.100.1.37
NAME 'associatedDomain'
DESC 'RFC1274: domain associated with object'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
# RFC 2459 -- deprecated in favor of 'mail' (in cosine.schema)
attributetype ( 1.2.840.113549.1.9.1
NAME ( 'email' 'emailAddress' 'pkcs9email' )
DESC 'RFC3280: legacy attribute for email addresses in DNs'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )

File diff suppressed because it is too large Load Diff

View File

@ -1,155 +0,0 @@
# inetorgperson.schema -- InetOrgPerson (RFC2798)
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2016 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
#
# InetOrgPerson (RFC2798)
#
# Depends upon
# Definition of an X.500 Attribute Type and an Object Class to Hold
# Uniform Resource Identifiers (URIs) [RFC2079]
# (core.schema)
#
# A Summary of the X.500(96) User Schema for use with LDAPv3 [RFC2256]
# (core.schema)
#
# The COSINE and Internet X.500 Schema [RFC1274] (cosine.schema)
# carLicense
# This multivalued field is used to record the values of the license or
# registration plate associated with an individual.
attributetype ( 2.16.840.1.113730.3.1.1
NAME 'carLicense'
DESC 'RFC2798: vehicle license or registration plate'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
# departmentNumber
# Code for department to which a person belongs. This can also be
# strictly numeric (e.g., 1234) or alphanumeric (e.g., ABC/123).
attributetype ( 2.16.840.1.113730.3.1.2
NAME 'departmentNumber'
DESC 'RFC2798: identifies a department within an organization'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
# displayName
# When displaying an entry, especially within a one-line summary list, it
# is useful to be able to identify a name to be used. Since other attri-
# bute types such as 'cn' are multivalued, an additional attribute type is
# needed. Display name is defined for this purpose.
attributetype ( 2.16.840.1.113730.3.1.241
NAME 'displayName'
DESC 'RFC2798: preferred name to be used when displaying entries'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
# employeeNumber
# Numeric or alphanumeric identifier assigned to a person, typically based
# on order of hire or association with an organization. Single valued.
attributetype ( 2.16.840.1.113730.3.1.3
NAME 'employeeNumber'
DESC 'RFC2798: numerically identifies an employee within an organization'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
# employeeType
# Used to identify the employer to employee relationship. Typical values
# used will be "Contractor", "Employee", "Intern", "Temp", "External", and
# "Unknown" but any value may be used.
attributetype ( 2.16.840.1.113730.3.1.4
NAME 'employeeType'
DESC 'RFC2798: type of employment for a person'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
# jpegPhoto
# Used to store one or more images of a person using the JPEG File
# Interchange Format [JFIF].
# Note that the jpegPhoto attribute type was defined for use in the
# Internet X.500 pilots but no referencable definition for it could be
# located.
attributetype ( 0.9.2342.19200300.100.1.60
NAME 'jpegPhoto'
DESC 'RFC2798: a JPEG image'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
# preferredLanguage
# Used to indicate an individual's preferred written or spoken
# language. This is useful for international correspondence or human-
# computer interaction. Values for this attribute type MUST conform to
# the definition of the Accept-Language header field defined in
# [RFC2068] with one exception: the sequence "Accept-Language" ":"
# should be omitted. This is a single valued attribute type.
attributetype ( 2.16.840.1.113730.3.1.39
NAME 'preferredLanguage'
DESC 'RFC2798: preferred written or spoken language for a person'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
# userSMIMECertificate
# A PKCS#7 [RFC2315] SignedData, where the content that is signed is
# ignored by consumers of userSMIMECertificate values. It is
# recommended that values have a `contentType' of data with an absent
# `content' field. Values of this attribute contain a person's entire
# certificate chain and an smimeCapabilities field [RFC2633] that at a
# minimum describes their SMIME algorithm capabilities. Values for
# this attribute are to be stored and requested in binary form, as
# 'userSMIMECertificate;binary'. If available, this attribute is
# preferred over the userCertificate attribute for S/MIME applications.
## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
attributetype ( 2.16.840.1.113730.3.1.40
NAME 'userSMIMECertificate'
DESC 'RFC2798: PKCS#7 SignedData used to support S/MIME'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
# userPKCS12
# PKCS #12 [PKCS12] provides a format for exchange of personal identity
# information. When such information is stored in a directory service,
# the userPKCS12 attribute should be used. This attribute is to be stored
# and requested in binary form, as 'userPKCS12;binary'. The attribute
# values are PFX PDUs stored as binary data.
## OpenLDAP note: ";binary" transfer should NOT be used as syntax is binary
attributetype ( 2.16.840.1.113730.3.1.216
NAME 'userPKCS12'
DESC 'RFC2798: personal identity information, a PKCS #12 PFX'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )
# inetOrgPerson
# The inetOrgPerson represents people who are associated with an
# organization in some way. It is a structural class and is derived
# from the organizationalPerson which is defined in X.521 [X521].
objectclass ( 2.16.840.1.113730.3.2.2
NAME 'inetOrgPerson'
DESC 'RFC2798: Internet Organizational Person'
SUP organizationalPerson
STRUCTURAL
MAY (
audio $ businessCategory $ carLicense $ departmentNumber $
displayName $ employeeNumber $ employeeType $ givenName $
homePhone $ homePostalAddress $ initials $ jpegPhoto $
labeledURI $ mail $ manager $ mobile $ o $ pager $
photo $ roomNumber $ secretary $ uid $ userCertificate $
x500uniqueIdentifier $ preferredLanguage $
userSMIMECertificate $ userPKCS12 )
)

View File

@ -1,75 +0,0 @@
# misc.schema -- assorted schema definitions
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2016 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
#
# Assorted definitions from several sources, including
# ''works in progress''. Contents of this file are
# subject to change (including deletion) without notice.
#
# Not recommended for production use!
# Use with extreme caution!
#-----------------------------------------------------------
# draft-lachman-laser-ldap-mail-routing-02.txt !!!EXPIRED!!!
# (a work in progress)
#
attributetype ( 2.16.840.1.113730.3.1.13
NAME 'mailLocalAddress'
DESC 'RFC822 email address of this recipient'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributetype ( 2.16.840.1.113730.3.1.18
NAME 'mailHost'
DESC 'FQDN of the SMTP/MTA of this recipient'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
SINGLE-VALUE )
attributetype ( 2.16.840.1.113730.3.1.47
NAME 'mailRoutingAddress'
DESC 'RFC822 routing address of this recipient'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
SINGLE-VALUE )
# I-D leaves this OID TBD.
# iPlanet uses 2.16.840.1.113.730.3.2.147 but that is an
# improperly delegated OID. A typo is likely.
objectclass ( 2.16.840.1.113730.3.2.147
NAME 'inetLocalMailRecipient'
DESC 'Internet local mail recipient'
SUP top AUXILIARY
MAY ( mailLocalAddress $ mailHost $ mailRoutingAddress ) )
#-----------------------------------------------------------
# draft-srivastava-ldap-mail-00.txt !!!EXPIRED!!!
# (a work in progress)
#
attributetype ( 1.3.6.1.4.1.42.2.27.2.1.15
NAME 'rfc822MailMember'
DESC 'rfc822 mail address of group member(s)'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
#-----------------------------------------------------------
# !!!no I-D!!!
# (a work in progress)
#
objectclass ( 1.3.6.1.4.1.42.2.27.1.2.5
NAME 'nisMailAlias'
DESC 'NIS mail alias'
SUP top STRUCTURAL
MUST cn
MAY rfc822MailMember )

View File

@ -1,237 +0,0 @@
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2016 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
# Definitions from RFC2307 (Experimental)
# An Approach for Using LDAP as a Network Information Service
# Depends upon core.schema and cosine.schema
# Note: The definitions in RFC2307 are given in syntaxes closely related
# to those in RFC2252, however, some liberties are taken that are not
# supported by RFC2252. This file has been written following RFC2252
# strictly.
# OID Base is iso(1) org(3) dod(6) internet(1) directory(1) nisSchema(1).
# i.e. nisSchema in RFC2307 is 1.3.6.1.1.1
#
# Syntaxes are under 1.3.6.1.1.1.0 (two new syntaxes are defined)
# validaters for these syntaxes are incomplete, they only
# implement printable string validation (which is good as the
# common use of these syntaxes violates the specification).
# Attribute types are under 1.3.6.1.1.1.1
# Object classes are under 1.3.6.1.1.1.2
# Attribute Type Definitions
# builtin
#attributetype ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'
# DESC 'An integer uniquely identifying a user in an administrative domain'
# EQUALITY integerMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
# builtin
#attributetype ( 1.3.6.1.1.1.1.1 NAME 'gidNumber'
# DESC 'An integer uniquely identifying a group in an administrative domain'
# EQUALITY integerMatch
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.2 NAME 'gecos'
DESC 'The GECOS field; the common name'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory'
DESC 'The absolute path to the home directory'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.4 NAME 'loginShell'
DESC 'The path to the login shell'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.6 NAME 'shadowMin'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.7 NAME 'shadowMax'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.12 NAME 'memberUid'
EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup'
EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
DESC 'Netgroup triple'
SYNTAX 1.3.6.1.1.1.0.0 )
attributetype ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol'
SUP name )
attributetype ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber'
DESC 'IP address'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
attributetype ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber'
DESC 'IP network'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber'
DESC 'IP netmask'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} SINGLE-VALUE )
attributetype ( 1.3.6.1.1.1.1.22 NAME 'macAddress'
DESC 'MAC address'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
attributetype ( 1.3.6.1.1.1.1.23 NAME 'bootParameter'
DESC 'rpc.bootparamd parameter'
SYNTAX 1.3.6.1.1.1.0.1 )
attributetype ( 1.3.6.1.1.1.1.24 NAME 'bootFile'
DESC 'Boot image name'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.1.1.1.26 NAME 'nisMapName'
SUP name )
attributetype ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry'
EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{1024} SINGLE-VALUE )
# Object Class Definitions
objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
DESC 'Abstraction of an account with POSIX attributes'
SUP top AUXILIARY
MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
MAY ( userPassword $ loginShell $ gecos $ description ) )
objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount'
DESC 'Additional attributes for shadow passwords'
SUP top AUXILIARY
MUST uid
MAY ( userPassword $ shadowLastChange $ shadowMin $
shadowMax $ shadowWarning $ shadowInactive $
shadowExpire $ shadowFlag $ description ) )
objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup'
DESC 'Abstraction of a group of accounts'
SUP top STRUCTURAL
MUST ( cn $ gidNumber )
MAY ( userPassword $ memberUid $ description ) )
objectclass ( 1.3.6.1.1.1.2.3 NAME 'ipService'
DESC 'Abstraction an Internet Protocol service'
SUP top STRUCTURAL
MUST ( cn $ ipServicePort $ ipServiceProtocol )
MAY ( description ) )
objectclass ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol'
DESC 'Abstraction of an IP protocol'
SUP top STRUCTURAL
MUST ( cn $ ipProtocolNumber $ description )
MAY description )
objectclass ( 1.3.6.1.1.1.2.5 NAME 'oncRpc'
DESC 'Abstraction of an ONC/RPC binding'
SUP top STRUCTURAL
MUST ( cn $ oncRpcNumber $ description )
MAY description )
objectclass ( 1.3.6.1.1.1.2.6 NAME 'ipHost'
DESC 'Abstraction of a host, an IP device'
SUP top AUXILIARY
MUST ( cn $ ipHostNumber )
MAY ( l $ description $ manager ) )
objectclass ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork'
DESC 'Abstraction of an IP network'
SUP top STRUCTURAL
MUST ( cn $ ipNetworkNumber )
MAY ( ipNetmaskNumber $ l $ description $ manager ) )
objectclass ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup'
DESC 'Abstraction of a netgroup'
SUP top STRUCTURAL
MUST cn
MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
objectclass ( 1.3.6.1.1.1.2.9 NAME 'nisMap'
DESC 'A generic abstraction of a NIS map'
SUP top STRUCTURAL
MUST nisMapName
MAY description )
objectclass ( 1.3.6.1.1.1.2.10 NAME 'nisObject'
DESC 'An entry in a NIS map'
SUP top STRUCTURAL
MUST ( cn $ nisMapEntry $ nisMapName )
MAY description )
objectclass ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device'
DESC 'A device with a MAC address'
SUP top AUXILIARY
MAY macAddress )
objectclass ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice'
DESC 'A device with boot parameters'
SUP top AUXILIARY
MAY ( bootFile $ bootParameter ) )

View File

@ -1,54 +0,0 @@
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2016 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
#
# OpenLDAP Project's directory schema items
#
# depends upon:
# core.schema
# cosine.schema
# inetorgperson.schema
#
# These are provided for informational purposes only.
objectIdentifier OpenLDAProot 1.3.6.1.4.1.4203
objectIdentifier OpenLDAP OpenLDAProot:1
objectIdentifier OpenLDAPattributeType OpenLDAP:3
objectIdentifier OpenLDAPobjectClass OpenLDAP:4
objectClass ( OpenLDAPobjectClass:3
NAME 'OpenLDAPorg'
DESC 'OpenLDAP Organizational Object'
SUP organization
MAY ( buildingName $ displayName $ labeledURI ) )
objectClass ( OpenLDAPobjectClass:4
NAME 'OpenLDAPou'
DESC 'OpenLDAP Organizational Unit Object'
SUP organizationalUnit
MAY ( buildingName $ displayName $ labeledURI $ o ) )
objectClass ( OpenLDAPobjectClass:5
NAME 'OpenLDAPperson'
DESC 'OpenLDAP Person'
SUP ( pilotPerson $ inetOrgPerson )
MUST ( uid $ cn )
MAY ( givenName $ labeledURI $ o ) )
objectClass ( OpenLDAPobjectClass:6
NAME 'OpenLDAPdisplayableObject'
DESC 'OpenLDAP Displayable Object'
AUXILIARY
MAY displayName )

447
connector/ldap/testdata/schema.ldif vendored Normal file
View File

@ -0,0 +1,447 @@
dn: ou=TestQuery,dc=example,dc=org
objectClass: organizationalUnit
ou: TestQuery
dn: ou=People,ou=TestQuery,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestQuery,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,ou=TestQuery,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
########################################################################
dn: ou=TestQueryWithEmailSuffix,dc=example,dc=org
objectClass: organizationalUnit
ou: TestQueryWithEmailSuffix
dn: ou=People,ou=TestQueryWithEmailSuffix,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestQueryWithEmailSuffix,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,ou=TestQueryWithEmailSuffix,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
userpassword: bar
########################################################################
dn: ou=TestUserFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: TestUserFilter
dn: ou=Seattle,ou=TestUserFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: Seattle
dn: ou=Portland,ou=TestUserFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: Portland
dn: ou=People,ou=Seattle,ou=TestUserFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: ou=People,ou=Portland,ou=TestUserFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=Seattle,ou=TestUserFilter,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=jane,ou=People,ou=Portland,ou=TestUserFilter,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoefromportland@example.com
userpassword: baz
dn: cn=john,ou=People,ou=Seattle,ou=TestUserFilter,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
########################################################################
dn: ou=TestGroupQuery,dc=example,dc=org
objectClass: organizationalUnit
ou: TestGroupQuery
dn: ou=People,ou=TestGroupQuery,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestGroupQuery,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,ou=TestGroupQuery,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Groups,ou=TestGroupQuery,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,ou=TestGroupQuery,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,ou=TestGroupQuery,dc=example,dc=org
member: cn=jane,ou=People,ou=TestGroupQuery,dc=example,dc=org
dn: cn=developers,ou=Groups,ou=TestGroupQuery,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,ou=TestGroupQuery,dc=example,dc=org
########################################################################
dn: ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: organizationalUnit
ou: TestGroupsOnUserEntity
dn: ou=People,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: organizationalUnit
ou: People
# Groups are enumerated as part of the user entity instead of the members being
# a list on the group entity.
dn: cn=jane,ou=People,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
departmentNumber: 1000
departmentNumber: 1001
dn: cn=john,ou=People,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
departmentNumber: 1000
departmentNumber: 1002
# Group definitions. Notice that they don't have any "member" field.
dn: ou=Groups,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=admins,ou=Groups,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: posixGroup
cn: admins
gidNumber: 1000
dn: cn=developers,ou=Groups,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: posixGroup
cn: developers
gidNumber: 1001
dn: cn=designers,ou=Groups,ou=TestGroupsOnUserEntity,dc=example,dc=org
objectClass: posixGroup
cn: designers
gidNumber: 1002
########################################################################
dn: ou=TestGroupFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: TestGroupFilter
dn: ou=People,ou=TestGroupFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestGroupFilter,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,ou=TestGroupFilter,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Seattle,ou=TestGroupFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: Seattle
dn: ou=Portland,ou=TestGroupFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: Portland
dn: ou=Groups,ou=Seattle,ou=TestGroupFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: ou=Groups,ou=Portland,ou=TestGroupFilter,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=qa,ou=Groups,ou=Portland,ou=TestGroupFilter,dc=example,dc=org
objectClass: groupOfNames
cn: qa
member: cn=john,ou=People,ou=TestGroupFilter,dc=example,dc=org
dn: cn=admins,ou=Groups,ou=Seattle,ou=TestGroupFilter,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,ou=TestGroupFilter,dc=example,dc=org
member: cn=jane,ou=People,ou=TestGroupFilter,dc=example,dc=org
dn: cn=developers,ou=Groups,ou=Seattle,ou=TestGroupFilter,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,ou=TestGroupFilter,dc=example,dc=org
########################################################################
dn: ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: TestGroupToUserMatchers
dn: ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
uid: janedoe
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
uid: johndoe
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Seattle,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: Seattle
dn: ou=Portland,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: Portland
dn: ou=Groups,ou=Seattle,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: ou=UnixGroups,ou=Seattle,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: UnixGroups
dn: ou=Groups,ou=Portland,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: ou=UnixGroups,ou=Portland,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: organizationalUnit
ou: UnixGroups
dn: cn=qa,ou=Groups,ou=Portland,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: groupOfNames
cn: qa
member: cn=john,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
dn: cn=logger,ou=UnixGroups,ou=Portland,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: posixGroup
gidNumber: 1000
cn: logger
memberUid: johndoe
dn: cn=admins,ou=Groups,ou=Seattle,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
member: cn=jane,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
dn: cn=developers,ou=Groups,ou=Seattle,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,ou=TestGroupToUserMatchers,dc=example,dc=org
dn: cn=frontend,ou=UnixGroups,ou=Seattle,ou=TestGroupToUserMatchers,dc=example,dc=org
objectClass: posixGroup
gidNumber: 1001
cn: frontend
memberUid: janedoe
########################################################################
dn: ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: organizationalUnit
ou: TestDeprecatedGroupToUserMatcher
dn: ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
dn: cn=john,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: john
mail: johndoe@example.com
userpassword: bar
# Group definitions.
dn: ou=Seattle,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: organizationalUnit
ou: Seattle
dn: ou=Portland,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: organizationalUnit
ou: Portland
dn: ou=Groups,ou=Seattle,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: ou=Groups,ou=Portland,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
dn: cn=qa,ou=Groups,ou=Portland,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: groupOfNames
cn: qa
member: cn=john,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
dn: cn=admins,ou=Groups,ou=Seattle,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: cn=john,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
member: cn=jane,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
dn: cn=developers,ou=Groups,ou=Seattle,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
objectClass: groupOfNames
cn: developers
member: cn=jane,ou=People,ou=TestDeprecatedGroupToUserMatcher,dc=example,dc=org
########################################################################
dn: ou=TestStartTLS,dc=example,dc=org
objectClass: organizationalUnit
ou: TestStartTLS
dn: ou=People,ou=TestStartTLS,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestStartTLS,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
########################################################################
dn: ou=TestInsecureSkipVerify,dc=example,dc=org
objectClass: organizationalUnit
ou: TestInsecureSkipVerify
dn: ou=People,ou=TestInsecureSkipVerify,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestInsecureSkipVerify,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo
########################################################################
dn: ou=TestLDAPS,dc=example,dc=org
objectClass: organizationalUnit
ou: TestLDAPS
dn: ou=People,ou=TestLDAPS,dc=example,dc=org
objectClass: organizationalUnit
ou: People
dn: cn=jane,ou=People,ou=TestLDAPS,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
sn: doe
cn: jane
mail: janedoe@example.com
userpassword: foo

View File

@ -0,0 +1,242 @@
// Package linkedin provides authentication strategies using LinkedIn
package linkedin
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"golang.org/x/oauth2"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
const (
apiURL = "https://api.linkedin.com/v2"
authURL = "https://www.linkedin.com/oauth/v2/authorization"
tokenURL = "https://www.linkedin.com/oauth/v2/accessToken"
)
// Config holds configuration options for LinkedIn logins.
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
}
// Open returns a strategy for logging in through LinkedIn
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
return &linkedInConnector{
oauth2Config: &oauth2.Config{
ClientID: c.ClientID,
ClientSecret: c.ClientSecret,
Endpoint: oauth2.Endpoint{
AuthURL: authURL,
TokenURL: tokenURL,
},
Scopes: []string{"r_liteprofile", "r_emailaddress"},
RedirectURL: c.RedirectURI,
},
logger: logger,
}, nil
}
type connectorData struct {
AccessToken string `json:"accessToken"`
}
type linkedInConnector struct {
oauth2Config *oauth2.Config
logger log.Logger
}
// LinkedIn doesn't provide refresh tokens, so refresh tokens issued by Dex
// will expire in 60 days (default LinkedIn token lifetime).
var (
_ connector.CallbackConnector = (*linkedInConnector)(nil)
_ connector.RefreshConnector = (*linkedInConnector)(nil)
)
// LoginURL returns an access token request URL
func (c *linkedInConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
if c.oauth2Config.RedirectURL != callbackURL {
return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q",
callbackURL, c.oauth2Config.RedirectURL)
}
return c.oauth2Config.AuthCodeURL(state), nil
}
// HandleCallback handles HTTP redirect from LinkedIn
func (c *linkedInConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
q := r.URL.Query()
if errType := q.Get("error"); errType != "" {
return identity, &oauth2Error{errType, q.Get("error_description")}
}
ctx := r.Context()
token, err := c.oauth2Config.Exchange(ctx, q.Get("code"))
if err != nil {
return identity, fmt.Errorf("linkedin: get token: %v", err)
}
client := c.oauth2Config.Client(ctx, token)
profile, err := c.profile(ctx, client)
if err != nil {
return identity, fmt.Errorf("linkedin: get profile: %v", err)
}
identity = connector.Identity{
UserID: profile.ID,
Username: profile.fullname(),
Email: profile.Email,
EmailVerified: true,
}
if s.OfflineAccess {
data := connectorData{AccessToken: token.AccessToken}
connData, err := json.Marshal(data)
if err != nil {
return identity, fmt.Errorf("linkedin: marshal connector data: %v", err)
}
identity.ConnectorData = connData
}
return identity, nil
}
func (c *linkedInConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
if len(ident.ConnectorData) == 0 {
return ident, fmt.Errorf("linkedin: no upstream access token found")
}
var data connectorData
if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
return ident, fmt.Errorf("linkedin: unmarshal access token: %v", err)
}
client := c.oauth2Config.Client(ctx, &oauth2.Token{AccessToken: data.AccessToken})
profile, err := c.profile(ctx, client)
if err != nil {
return ident, fmt.Errorf("linkedin: get profile: %v", err)
}
ident.Username = profile.fullname()
ident.Email = profile.Email
return ident, nil
}
type profile struct {
ID string `json:"id"`
FirstName string `json:"localizedFirstName"`
LastName string `json:"localizedLastName"`
Email string `json:"emailAddress"`
}
type emailresp struct {
Elements []struct {
Handle struct {
EmailAddress string `json:"emailAddress"`
} `json:"handle~"`
} `json:"elements"`
}
// fullname returns a full name of a person, or email if the resulting name is
// empty
func (p profile) fullname() string {
fname := strings.TrimSpace(p.FirstName + " " + p.LastName)
if fname == "" {
return p.Email
}
return fname
}
func (c *linkedInConnector) primaryEmail(ctx context.Context, client *http.Client) (email string, err error) {
req, err := http.NewRequest("GET", apiURL+"/emailAddress?q=members&projection=(elements*(handle~))", nil)
if err != nil {
return email, fmt.Errorf("new req: %v", err)
}
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
return email, fmt.Errorf("get URL %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return email, fmt.Errorf("read body: %v", err)
}
if resp.StatusCode != http.StatusOK {
return email, fmt.Errorf("%s: %s", resp.Status, body)
}
var parsedResp emailresp
err = json.Unmarshal(body, &parsedResp)
if err == nil {
for _, elem := range parsedResp.Elements {
email = elem.Handle.EmailAddress
}
}
if email == "" {
err = fmt.Errorf("email is not set")
}
return email, err
}
func (c *linkedInConnector) profile(ctx context.Context, client *http.Client) (p profile, err error) {
// https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api
// https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/primary-contact-api
// https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/migration-faq#how-do-i-retrieve-the-members-email-address
req, err := http.NewRequest("GET", apiURL+"/me", nil)
if err != nil {
return p, fmt.Errorf("new req: %v", err)
}
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
return p, fmt.Errorf("get URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return p, fmt.Errorf("read body: %v", err)
}
return p, fmt.Errorf("%s: %s", resp.Status, body)
}
if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
return p, fmt.Errorf("JSON decode: %v", err)
}
email, err := c.primaryEmail(ctx, client)
if err != nil {
return p, fmt.Errorf("fetching email: %v", err)
}
p.Email = email
return p, err
}
type oauth2Error struct {
error string
errorDescription string
}
func (e *oauth2Error) Error() string {
if e.errorDescription == "" {
return e.error
}
return e.error + ": " + e.errorDescription
}

View File

@ -0,0 +1,515 @@
// Package microsoft provides authentication strategies using Microsoft.
package microsoft
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"sync"
"time"
"golang.org/x/oauth2"
"github.com/dexidp/dex/connector"
groups_pkg "github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
)
// GroupNameFormat represents the format of the group identifier
// we use type of string instead of int because it's easier to
// marshall/unmarshall
type GroupNameFormat string
// Possible values for GroupNameFormat
const (
GroupID GroupNameFormat = "id"
GroupName GroupNameFormat = "name"
)
const (
// Microsoft requires this scope to access user's profile
scopeUser = "user.read"
// Microsoft requires this scope to list groups the user is a member of
// and resolve their ids to groups names.
scopeGroups = "directory.read.all"
// Microsoft requires this scope to return a refresh token
// see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#offline_access
scopeOfflineAccess = "offline_access"
)
// Config holds configuration options for microsoft logins.
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
Tenant string `json:"tenant"`
OnlySecurityGroups bool `json:"onlySecurityGroups"`
Groups []string `json:"groups"`
GroupNameFormat GroupNameFormat `json:"groupNameFormat"`
UseGroupsAsWhitelist bool `json:"useGroupsAsWhitelist"`
EmailToLowercase bool `json:"emailToLowercase"`
// PromptType is used for the prompt query parameter.
// For valid values, see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code.
PromptType string `json:"promptType"`
DomainHint string `json:"domainHint"`
Scopes []string `json:"scopes"` // defaults to scopeUser (user.read)
}
// Open returns a strategy for logging in through Microsoft.
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
m := microsoftConnector{
apiURL: "https://login.microsoftonline.com",
graphURL: "https://graph.microsoft.com",
redirectURI: c.RedirectURI,
clientID: c.ClientID,
clientSecret: c.ClientSecret,
tenant: c.Tenant,
onlySecurityGroups: c.OnlySecurityGroups,
groups: c.Groups,
groupNameFormat: c.GroupNameFormat,
useGroupsAsWhitelist: c.UseGroupsAsWhitelist,
logger: logger,
emailToLowercase: c.EmailToLowercase,
promptType: c.PromptType,
domainHint: c.DomainHint,
scopes: c.Scopes,
}
// By default allow logins from both personal and business/school
// accounts.
if m.tenant == "" {
m.tenant = "common"
}
// By default, use group names
switch m.groupNameFormat {
case "":
m.groupNameFormat = GroupName
case GroupID, GroupName:
default:
return nil, fmt.Errorf("invalid groupNameFormat: %s", m.groupNameFormat)
}
return &m, nil
}
type connectorData struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
Expiry time.Time `json:"expiry"`
}
var (
_ connector.CallbackConnector = (*microsoftConnector)(nil)
_ connector.RefreshConnector = (*microsoftConnector)(nil)
)
type microsoftConnector struct {
apiURL string
graphURL string
redirectURI string
clientID string
clientSecret string
tenant string
onlySecurityGroups bool
groupNameFormat GroupNameFormat
groups []string
useGroupsAsWhitelist bool
logger log.Logger
emailToLowercase bool
promptType string
domainHint string
scopes []string
}
func (c *microsoftConnector) isOrgTenant() bool {
return c.tenant != "common" && c.tenant != "consumers" && c.tenant != "organizations"
}
func (c *microsoftConnector) groupsRequired(groupScope bool) bool {
return (len(c.groups) > 0 || groupScope) && c.isOrgTenant()
}
func (c *microsoftConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
var microsoftScopes []string
if len(c.scopes) > 0 {
microsoftScopes = c.scopes
} else {
microsoftScopes = append(microsoftScopes, scopeUser)
}
if c.groupsRequired(scopes.Groups) {
microsoftScopes = append(microsoftScopes, scopeGroups)
}
if scopes.OfflineAccess {
microsoftScopes = append(microsoftScopes, scopeOfflineAccess)
}
return &oauth2.Config{
ClientID: c.clientID,
ClientSecret: c.clientSecret,
Endpoint: oauth2.Endpoint{
AuthURL: c.apiURL + "/" + c.tenant + "/oauth2/v2.0/authorize",
TokenURL: c.apiURL + "/" + c.tenant + "/oauth2/v2.0/token",
},
Scopes: microsoftScopes,
RedirectURL: c.redirectURI,
}
}
func (c *microsoftConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
if c.redirectURI != callbackURL {
return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", callbackURL, c.redirectURI)
}
var options []oauth2.AuthCodeOption
if c.promptType != "" {
options = append(options, oauth2.SetAuthURLParam("prompt", c.promptType))
}
if c.domainHint != "" {
options = append(options, oauth2.SetAuthURLParam("domain_hint", c.domainHint))
}
return c.oauth2Config(scopes).AuthCodeURL(state, options...), nil
}
func (c *microsoftConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
q := r.URL.Query()
if errType := q.Get("error"); errType != "" {
return identity, &oauth2Error{errType, q.Get("error_description")}
}
oauth2Config := c.oauth2Config(s)
ctx := r.Context()
token, err := oauth2Config.Exchange(ctx, q.Get("code"))
if err != nil {
return identity, fmt.Errorf("microsoft: failed to get token: %v", err)
}
client := oauth2Config.Client(ctx, token)
user, err := c.user(ctx, client)
if err != nil {
return identity, fmt.Errorf("microsoft: get user: %v", err)
}
if c.emailToLowercase {
user.Email = strings.ToLower(user.Email)
}
identity = connector.Identity{
UserID: user.ID,
Username: user.Name,
Email: user.Email,
EmailVerified: true,
}
if c.groupsRequired(s.Groups) {
groups, err := c.getGroups(ctx, client, user.ID)
if err != nil {
return identity, fmt.Errorf("microsoft: get groups: %v", err)
}
identity.Groups = groups
}
if s.OfflineAccess {
data := connectorData{
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
Expiry: token.Expiry,
}
connData, err := json.Marshal(data)
if err != nil {
return identity, fmt.Errorf("microsoft: marshal connector data: %v", err)
}
identity.ConnectorData = connData
}
return identity, nil
}
type tokenNotifyFunc func(*oauth2.Token) error
// notifyRefreshTokenSource is essentially `oauth2.ReuseTokenSource` with `TokenNotifyFunc` added.
type notifyRefreshTokenSource struct {
new oauth2.TokenSource
mu sync.Mutex // guards t
t *oauth2.Token
f tokenNotifyFunc // called when token refreshed so new refresh token can be persisted
}
// Token returns the current token if it's still valid, else will
// refresh the current token (using r.Context for HTTP client
// information) and return the new one.
func (s *notifyRefreshTokenSource) Token() (*oauth2.Token, error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.t.Valid() {
return s.t, nil
}
t, err := s.new.Token()
if err != nil {
return nil, err
}
s.t = t
return t, s.f(t)
}
func (c *microsoftConnector) Refresh(ctx context.Context, s connector.Scopes, identity connector.Identity) (connector.Identity, error) {
if len(identity.ConnectorData) == 0 {
return identity, errors.New("microsoft: no upstream access token found")
}
var data connectorData
if err := json.Unmarshal(identity.ConnectorData, &data); err != nil {
return identity, fmt.Errorf("microsoft: unmarshal access token: %v", err)
}
tok := &oauth2.Token{
AccessToken: data.AccessToken,
RefreshToken: data.RefreshToken,
Expiry: data.Expiry,
}
client := oauth2.NewClient(ctx, &notifyRefreshTokenSource{
new: c.oauth2Config(s).TokenSource(ctx, tok),
t: tok,
f: func(tok *oauth2.Token) error {
data := connectorData{
AccessToken: tok.AccessToken,
RefreshToken: tok.RefreshToken,
Expiry: tok.Expiry,
}
connData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("microsoft: marshal connector data: %v", err)
}
identity.ConnectorData = connData
return nil
},
})
user, err := c.user(ctx, client)
if err != nil {
return identity, fmt.Errorf("microsoft: get user: %v", err)
}
identity.Username = user.Name
identity.Email = user.Email
if c.groupsRequired(s.Groups) {
groups, err := c.getGroups(ctx, client, user.ID)
if err != nil {
return identity, fmt.Errorf("microsoft: get groups: %v", err)
}
identity.Groups = groups
}
return identity, nil
}
// https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/user
// id - The unique identifier for the user. Inherited from
// directoryObject. Key. Not nullable. Read-only.
// displayName - The name displayed in the address book for the user.
// This is usually the combination of the user's first name,
// middle initial and last name. This property is required
// when a user is created and it cannot be cleared during
// updates. Supports $filter and $orderby.
// userPrincipalName - The user principal name (UPN) of the user.
// The UPN is an Internet-style login name for the user
// based on the Internet standard RFC 822. By convention,
// this should map to the user's email name. The general
// format is alias@domain, where domain must be present in
// the tenants collection of verified domains. This
// property is required when a user is created. The
// verified domains for the tenant can be accessed from the
// verifiedDomains property of organization. Supports
// $filter and $orderby.
type user struct {
ID string `json:"id"`
Name string `json:"displayName"`
Email string `json:"userPrincipalName"`
}
func (c *microsoftConnector) user(ctx context.Context, client *http.Client) (u user, err error) {
// https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_get
req, err := http.NewRequest("GET", c.graphURL+"/v1.0/me?$select=id,displayName,userPrincipalName", nil)
if err != nil {
return u, fmt.Errorf("new req: %v", err)
}
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
return u, fmt.Errorf("get URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return u, newGraphError(resp.Body)
}
if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {
return u, fmt.Errorf("JSON decode: %v", err)
}
return u, err
}
// https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/group
// displayName - The display name for the group. This property is required when
// a group is created and it cannot be cleared during updates.
// Supports $filter and $orderby.
type group struct {
Name string `json:"displayName"`
}
func (c *microsoftConnector) getGroups(ctx context.Context, client *http.Client, userID string) ([]string, error) {
userGroups, err := c.getGroupIDs(ctx, client)
if err != nil {
return nil, err
}
if c.groupNameFormat == GroupName {
userGroups, err = c.getGroupNames(ctx, client, userGroups)
if err != nil {
return nil, err
}
}
// ensure that the user is in at least one required group
filteredGroups := groups_pkg.Filter(userGroups, c.groups)
if len(c.groups) > 0 && len(filteredGroups) == 0 {
return nil, fmt.Errorf("microsoft: user %v not in any of the required groups", userID)
} else if c.useGroupsAsWhitelist {
return filteredGroups, nil
}
return userGroups, nil
}
func (c *microsoftConnector) getGroupIDs(ctx context.Context, client *http.Client) (ids []string, err error) {
// https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_getmembergroups
in := &struct {
SecurityEnabledOnly bool `json:"securityEnabledOnly"`
}{c.onlySecurityGroups}
reqURL := c.graphURL + "/v1.0/me/getMemberGroups"
for {
var out []string
var next string
next, err = c.post(ctx, client, reqURL, in, &out)
if err != nil {
return ids, err
}
ids = append(ids, out...)
if next == "" {
return
}
reqURL = next
}
}
func (c *microsoftConnector) getGroupNames(ctx context.Context, client *http.Client, ids []string) (groups []string, err error) {
if len(ids) == 0 {
return
}
// https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/directoryobject_getbyids
in := &struct {
IDs []string `json:"ids"`
Types []string `json:"types"`
}{ids, []string{"group"}}
reqURL := c.graphURL + "/v1.0/directoryObjects/getByIds"
for {
var out []group
var next string
next, err = c.post(ctx, client, reqURL, in, &out)
if err != nil {
return groups, err
}
for _, g := range out {
groups = append(groups, g.Name)
}
if next == "" {
return
}
reqURL = next
}
}
func (c *microsoftConnector) post(ctx context.Context, client *http.Client, reqURL string, in interface{}, out interface{}) (string, error) {
var payload bytes.Buffer
err := json.NewEncoder(&payload).Encode(in)
if err != nil {
return "", fmt.Errorf("microsoft: JSON encode: %v", err)
}
req, err := http.NewRequest("POST", reqURL, &payload)
if err != nil {
return "", fmt.Errorf("new req: %v", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
return "", fmt.Errorf("post URL %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", newGraphError(resp.Body)
}
var next string
if err = json.NewDecoder(resp.Body).Decode(&struct {
NextLink *string `json:"@odata.nextLink"`
Value interface{} `json:"value"`
}{&next, out}); err != nil {
return "", fmt.Errorf("JSON decode: %v", err)
}
return next, nil
}
type graphError struct {
Code string `json:"code"`
Message string `json:"message"`
}
func (e *graphError) Error() string {
return e.Code + ": " + e.Message
}
func newGraphError(r io.Reader) error {
// https://developer.microsoft.com/en-us/graph/docs/concepts/errors
var ge graphError
if err := json.NewDecoder(r).Decode(&struct {
Error *graphError `json:"error"`
}{&ge}); err != nil {
return fmt.Errorf("JSON error decode: %v", err)
}
return &ge
}
type oauth2Error struct {
error string
errorDescription string
}
func (e *oauth2Error) Error() string {
if e.errorDescription == "" {
return e.error
}
return e.error + ": " + e.errorDescription
}

View File

@ -0,0 +1,146 @@
package microsoft
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
"testing"
"github.com/dexidp/dex/connector"
)
type testResponse struct {
data interface{}
}
const (
tenant = "9b1c3439-a67e-4e92-bb0d-0571d44ca965"
clientID = "a115ebf3-6020-4384-8eb1-c0c42e667b6f"
)
var dummyToken = testResponse{data: map[string]interface{}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
"expires_in": "30",
}}
func TestLoginURL(t *testing.T) {
testURL := "https://test.com"
testState := "some-state"
conn := microsoftConnector{
apiURL: testURL,
graphURL: testURL,
redirectURI: testURL,
clientID: clientID,
tenant: tenant,
}
loginURL, _ := conn.LoginURL(connector.Scopes{}, conn.redirectURI, testState)
parsedLoginURL, _ := url.Parse(loginURL)
queryParams := parsedLoginURL.Query()
expectEquals(t, parsedLoginURL.Path, "/"+tenant+"/oauth2/v2.0/authorize")
expectEquals(t, queryParams.Get("client_id"), clientID)
expectEquals(t, queryParams.Get("redirect_uri"), testURL)
expectEquals(t, queryParams.Get("response_type"), "code")
expectEquals(t, queryParams.Get("scope"), "user.read")
expectEquals(t, queryParams.Get("state"), testState)
expectEquals(t, queryParams.Get("prompt"), "")
expectEquals(t, queryParams.Get("domain_hint"), "")
}
func TestLoginURLWithOptions(t *testing.T) {
testURL := "https://test.com"
promptType := "consent"
domainHint := "domain.hint"
conn := microsoftConnector{
apiURL: testURL,
graphURL: testURL,
redirectURI: testURL,
clientID: clientID,
tenant: tenant,
promptType: promptType,
domainHint: domainHint,
}
loginURL, _ := conn.LoginURL(connector.Scopes{}, conn.redirectURI, "some-state")
parsedLoginURL, _ := url.Parse(loginURL)
queryParams := parsedLoginURL.Query()
expectEquals(t, queryParams.Get("prompt"), promptType)
expectEquals(t, queryParams.Get("domain_hint"), domainHint)
}
func TestUserIdentityFromGraphAPI(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/v1.0/me?$select=id,displayName,userPrincipalName": {
data: user{ID: "S56767889", Name: "Jane Doe", Email: "jane.doe@example.com"},
},
"/" + tenant + "/oauth2/v2.0/token": dummyToken,
})
defer s.Close()
req, _ := http.NewRequest("GET", s.URL, nil)
c := microsoftConnector{apiURL: s.URL, graphURL: s.URL, tenant: tenant}
identity, err := c.HandleCallback(connector.Scopes{Groups: false}, req)
expectNil(t, err)
expectEquals(t, identity.Username, "Jane Doe")
expectEquals(t, identity.UserID, "S56767889")
expectEquals(t, identity.PreferredUsername, "")
expectEquals(t, identity.Email, "jane.doe@example.com")
expectEquals(t, identity.EmailVerified, true)
expectEquals(t, len(identity.Groups), 0)
}
func TestUserGroupsFromGraphAPI(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/v1.0/me?$select=id,displayName,userPrincipalName": {data: user{}},
"/v1.0/me/getMemberGroups": {data: map[string]interface{}{
"value": []string{"a", "b"},
}},
"/" + tenant + "/oauth2/v2.0/token": dummyToken,
})
defer s.Close()
req, _ := http.NewRequest("GET", s.URL, nil)
c := microsoftConnector{apiURL: s.URL, graphURL: s.URL, tenant: tenant}
identity, err := c.HandleCallback(connector.Scopes{Groups: true}, req)
expectNil(t, err)
expectEquals(t, identity.Groups, []string{"a", "b"})
}
func newTestServer(responses map[string]testResponse) *httptest.Server {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response, found := responses[r.RequestURI]
if !found {
fmt.Fprintf(os.Stderr, "Mock response for %q not found\n", r.RequestURI)
http.NotFound(w, r)
return
}
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(response.data)
}))
return s
}
func expectNil(t *testing.T, a interface{}) {
if a != nil {
t.Errorf("Expected %+v to equal nil", a)
}
}
func expectEquals(t *testing.T, a interface{}, b interface{}) {
if !reflect.DeepEqual(a, b) {
t.Errorf("Expected %+v to equal %+v", a, b)
}
}

View File

@ -8,13 +8,13 @@ import (
"net/http"
"net/url"
"github.com/coreos/dex/connector"
"github.com/sirupsen/logrus"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
// NewCallbackConnector returns a mock connector which requires no user interaction. It always returns
// the same (fake) identity.
func NewCallbackConnector(logger logrus.FieldLogger) connector.Connector {
func NewCallbackConnector(logger log.Logger) connector.Connector {
return &Callback{
Identity: connector.Identity{
UserID: "0-385-28089-0",
@ -32,13 +32,14 @@ var (
_ connector.CallbackConnector = &Callback{}
_ connector.PasswordConnector = passwordConnector{}
_ connector.RefreshConnector = passwordConnector{}
)
// Callback is a connector that requires no user interaction and always returns the same identity.
type Callback struct {
// The returned identity.
Identity connector.Identity
Logger logrus.FieldLogger
Logger log.Logger
}
// LoginURL returns the URL to redirect the user to login with.
@ -69,7 +70,7 @@ func (m *Callback) Refresh(ctx context.Context, s connector.Scopes, identity con
type CallbackConfig struct{}
// Open returns an authentication strategy which requires no user interaction.
func (c *CallbackConfig) Open(logger logrus.FieldLogger) (connector.Connector, error) {
func (c *CallbackConfig) Open(id string, logger log.Logger) (connector.Connector, error) {
return NewCallbackConnector(logger), nil
}
@ -81,7 +82,7 @@ type PasswordConfig struct {
}
// Open returns an authentication strategy which prompts for a predefined username and password.
func (c *PasswordConfig) Open(logger logrus.FieldLogger) (connector.Connector, error) {
func (c *PasswordConfig) Open(id string, logger log.Logger) (connector.Connector, error) {
if c.Username == "" {
return nil, errors.New("no username supplied")
}
@ -94,7 +95,7 @@ func (c *PasswordConfig) Open(logger logrus.FieldLogger) (connector.Connector, e
type passwordConnector struct {
username string
password string
logger logrus.FieldLogger
logger log.Logger
}
func (p passwordConnector) Close() error { return nil }
@ -106,7 +107,14 @@ func (p passwordConnector) Login(ctx context.Context, s connector.Scopes, userna
Username: "Kilgore Trout",
Email: "kilgore@kilgore.trout",
EmailVerified: true,
ConnectorData: []byte(`{"test": "true"}`),
}, true, nil
}
return identity, false, nil
}
func (p passwordConnector) Prompt() string { return "" }
func (p passwordConnector) Refresh(_ context.Context, _ connector.Scopes, identity connector.Identity) (connector.Identity, error) {
return identity, nil
}

298
connector/oauth/oauth.go Normal file
View File

@ -0,0 +1,298 @@
package oauth
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"os"
"strings"
"time"
"golang.org/x/oauth2"
"github.com/dexidp/dex/connector"
"github.com/dexidp/dex/pkg/log"
)
type oauthConnector struct {
clientID string
clientSecret string
redirectURI string
tokenURL string
authorizationURL string
userInfoURL string
scopes []string
userIDKey string
userNameKey string
preferredUsernameKey string
emailKey string
emailVerifiedKey string
groupsKey string
httpClient *http.Client
logger log.Logger
}
type connectorData struct {
AccessToken string
}
type Config struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
RedirectURI string `json:"redirectURI"`
TokenURL string `json:"tokenURL"`
AuthorizationURL string `json:"authorizationURL"`
UserInfoURL string `json:"userInfoURL"`
Scopes []string `json:"scopes"`
RootCAs []string `json:"rootCAs"`
InsecureSkipVerify bool `json:"insecureSkipVerify"`
UserIDKey string `json:"userIDKey"` // defaults to "id"
ClaimMapping struct {
UserNameKey string `json:"userNameKey"` // defaults to "user_name"
PreferredUsernameKey string `json:"preferredUsernameKey"` // defaults to "preferred_username"
GroupsKey string `json:"groupsKey"` // defaults to "groups"
EmailKey string `json:"emailKey"` // defaults to "email"
EmailVerifiedKey string `json:"emailVerifiedKey"` // defaults to "email_verified"
} `json:"claimMapping"`
}
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
var err error
userIDKey := c.UserIDKey
if userIDKey == "" {
userIDKey = "id"
}
userNameKey := c.ClaimMapping.UserNameKey
if userNameKey == "" {
userNameKey = "user_name"
}
preferredUsernameKey := c.ClaimMapping.PreferredUsernameKey
if preferredUsernameKey == "" {
preferredUsernameKey = "preferred_username"
}
groupsKey := c.ClaimMapping.GroupsKey
if groupsKey == "" {
groupsKey = "groups"
}
emailKey := c.ClaimMapping.EmailKey
if emailKey == "" {
emailKey = "email"
}
emailVerifiedKey := c.ClaimMapping.EmailVerifiedKey
if emailVerifiedKey == "" {
emailVerifiedKey = "email_verified"
}
oauthConn := &oauthConnector{
clientID: c.ClientID,
clientSecret: c.ClientSecret,
tokenURL: c.TokenURL,
authorizationURL: c.AuthorizationURL,
userInfoURL: c.UserInfoURL,
scopes: c.Scopes,
redirectURI: c.RedirectURI,
logger: logger,
userIDKey: userIDKey,
userNameKey: userNameKey,
preferredUsernameKey: preferredUsernameKey,
groupsKey: groupsKey,
emailKey: emailKey,
emailVerifiedKey: emailVerifiedKey,
}
oauthConn.httpClient, err = newHTTPClient(c.RootCAs, c.InsecureSkipVerify)
if err != nil {
return nil, err
}
return oauthConn, err
}
func newHTTPClient(rootCAs []string, insecureSkipVerify bool) (*http.Client, error) {
pool, err := x509.SystemCertPool()
if err != nil {
return nil, err
}
tlsConfig := tls.Config{RootCAs: pool, InsecureSkipVerify: insecureSkipVerify}
for _, rootCA := range rootCAs {
rootCABytes, err := os.ReadFile(rootCA)
if err != nil {
return nil, fmt.Errorf("failed to read root-ca: %v", err)
}
if !tlsConfig.RootCAs.AppendCertsFromPEM(rootCABytes) {
return nil, fmt.Errorf("no certs found in root CA file %q", rootCA)
}
}
return &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tlsConfig,
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}, nil
}
func (c *oauthConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
if c.redirectURI != callbackURL {
return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", callbackURL, c.redirectURI)
}
oauth2Config := &oauth2.Config{
ClientID: c.clientID,
ClientSecret: c.clientSecret,
Endpoint: oauth2.Endpoint{TokenURL: c.tokenURL, AuthURL: c.authorizationURL},
RedirectURL: c.redirectURI,
Scopes: c.scopes,
}
return oauth2Config.AuthCodeURL(state), nil
}
func (c *oauthConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
q := r.URL.Query()
if errType := q.Get("error"); errType != "" {
return identity, errors.New(q.Get("error_description"))
}
oauth2Config := &oauth2.Config{
ClientID: c.clientID,
ClientSecret: c.clientSecret,
Endpoint: oauth2.Endpoint{TokenURL: c.tokenURL, AuthURL: c.authorizationURL},
RedirectURL: c.redirectURI,
Scopes: c.scopes,
}
ctx := context.WithValue(r.Context(), oauth2.HTTPClient, c.httpClient)
token, err := oauth2Config.Exchange(ctx, q.Get("code"))
if err != nil {
return identity, fmt.Errorf("OAuth connector: failed to get token: %v", err)
}
client := oauth2.NewClient(ctx, oauth2.StaticTokenSource(token))
userInfoResp, err := client.Get(c.userInfoURL)
if err != nil {
return identity, fmt.Errorf("OAuth Connector: failed to execute request to userinfo: %v", err)
}
defer userInfoResp.Body.Close()
if userInfoResp.StatusCode != http.StatusOK {
return identity, fmt.Errorf("OAuth Connector: failed to execute request to userinfo: status %d", userInfoResp.StatusCode)
}
var userInfoResult map[string]interface{}
err = json.NewDecoder(userInfoResp.Body).Decode(&userInfoResult)
if err != nil {
return identity, fmt.Errorf("OAuth Connector: failed to parse userinfo: %v", err)
}
userID, found := userInfoResult[c.userIDKey]
if !found {
return identity, fmt.Errorf("OAuth Connector: not found %v claim", c.userIDKey)
}
switch userID.(type) {
case float64, int64, string:
identity.UserID = fmt.Sprintf("%v", userID)
default:
return identity, fmt.Errorf("OAuth Connector: %v claim should be string or number, got %T", c.userIDKey, userID)
}
identity.Username, _ = userInfoResult[c.userNameKey].(string)
identity.PreferredUsername, _ = userInfoResult[c.preferredUsernameKey].(string)
identity.Email, _ = userInfoResult[c.emailKey].(string)
identity.EmailVerified, _ = userInfoResult[c.emailVerifiedKey].(bool)
if s.Groups {
groups := map[string]struct{}{}
c.addGroupsFromMap(groups, userInfoResult)
c.addGroupsFromToken(groups, token.AccessToken)
for groupName := range groups {
identity.Groups = append(identity.Groups, groupName)
}
}
if s.OfflineAccess {
data := connectorData{AccessToken: token.AccessToken}
connData, err := json.Marshal(data)
if err != nil {
return identity, fmt.Errorf("OAuth Connector: failed to parse connector data for offline access: %v", err)
}
identity.ConnectorData = connData
}
return identity, nil
}
func (c *oauthConnector) addGroupsFromMap(groups map[string]struct{}, result map[string]interface{}) error {
groupsClaim, ok := result[c.groupsKey].([]interface{})
if !ok {
return errors.New("cannot convert to slice")
}
for _, group := range groupsClaim {
if groupString, ok := group.(string); ok {
groups[groupString] = struct{}{}
}
if groupMap, ok := group.(map[string]interface{}); ok {
if groupName, ok := groupMap["name"].(string); ok {
groups[groupName] = struct{}{}
}
}
}
return nil
}
func (c *oauthConnector) addGroupsFromToken(groups map[string]struct{}, token string) error {
parts := strings.Split(token, ".")
if len(parts) < 2 {
return errors.New("invalid token")
}
decoded, err := decode(parts[1])
if err != nil {
return err
}
var claimsMap map[string]interface{}
err = json.Unmarshal(decoded, &claimsMap)
if err != nil {
return err
}
return c.addGroupsFromMap(groups, claimsMap)
}
func decode(seg string) ([]byte, error) {
if l := len(seg) % 4; l > 0 {
seg += strings.Repeat("=", 4-l)
}
return base64.URLEncoding.DecodeString(seg)
}

View File

@ -0,0 +1,299 @@
package oauth
import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"sort"
"testing"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
jose "gopkg.in/square/go-jose.v2"
"github.com/dexidp/dex/connector"
)
func TestOpen(t *testing.T) {
tokenClaims := map[string]interface{}{}
userInfoClaims := map[string]interface{}{}
testServer := testSetup(t, tokenClaims, userInfoClaims)
defer testServer.Close()
conn := newConnector(t, testServer.URL)
sort.Strings(conn.scopes)
assert.Equal(t, conn.clientID, "testClient")
assert.Equal(t, conn.clientSecret, "testSecret")
assert.Equal(t, conn.redirectURI, testServer.URL+"/callback")
assert.Equal(t, conn.tokenURL, testServer.URL+"/token")
assert.Equal(t, conn.authorizationURL, testServer.URL+"/authorize")
assert.Equal(t, conn.userInfoURL, testServer.URL+"/userinfo")
assert.Equal(t, len(conn.scopes), 2)
assert.Equal(t, conn.scopes[0], "groups")
assert.Equal(t, conn.scopes[1], "openid")
}
func TestLoginURL(t *testing.T) {
tokenClaims := map[string]interface{}{}
userInfoClaims := map[string]interface{}{}
testServer := testSetup(t, tokenClaims, userInfoClaims)
defer testServer.Close()
conn := newConnector(t, testServer.URL)
loginURL, err := conn.LoginURL(connector.Scopes{}, conn.redirectURI, "some-state")
assert.Equal(t, err, nil)
expectedURL, err := url.Parse(testServer.URL + "/authorize")
assert.Equal(t, err, nil)
values := url.Values{}
values.Add("client_id", "testClient")
values.Add("redirect_uri", conn.redirectURI)
values.Add("response_type", "code")
values.Add("scope", "openid groups")
values.Add("state", "some-state")
expectedURL.RawQuery = values.Encode()
assert.Equal(t, loginURL, expectedURL.String())
}
func TestHandleCallBackForGroupsInUserInfo(t *testing.T) {
tokenClaims := map[string]interface{}{}
userInfoClaims := map[string]interface{}{
"name": "test-name",
"user_id_key": "test-user-id",
"user_name_key": "test-username",
"preferred_username": "test-preferred-username",
"mail": "mod_mail",
"has_verified_email": false,
"groups_key": []string{"admin-group", "user-group"},
}
testServer := testSetup(t, tokenClaims, userInfoClaims)
defer testServer.Close()
conn := newConnector(t, testServer.URL)
req := newRequestWithAuthCode(t, testServer.URL, "TestHandleCallBackForGroupsInUserInfo")
identity, err := conn.HandleCallback(connector.Scopes{Groups: true}, req)
assert.Equal(t, err, nil)
sort.Strings(identity.Groups)
assert.Equal(t, len(identity.Groups), 2)
assert.Equal(t, identity.Groups[0], "admin-group")
assert.Equal(t, identity.Groups[1], "user-group")
assert.Equal(t, identity.UserID, "test-user-id")
assert.Equal(t, identity.Username, "test-username")
assert.Equal(t, identity.PreferredUsername, "test-preferred-username")
assert.Equal(t, identity.Email, "mod_mail")
assert.Equal(t, identity.EmailVerified, false)
}
func TestHandleCallBackForGroupMapsInUserInfo(t *testing.T) {
tokenClaims := map[string]interface{}{}
userInfoClaims := map[string]interface{}{
"name": "test-name",
"user_id_key": "test-user-id",
"user_name_key": "test-username",
"preferred_username": "test-preferred-username",
"mail": "mod_mail",
"has_verified_email": false,
"groups_key": []interface{}{
map[string]string{"name": "admin-group", "id": "111"},
map[string]string{"name": "user-group", "id": "222"},
},
}
testServer := testSetup(t, tokenClaims, userInfoClaims)
defer testServer.Close()
conn := newConnector(t, testServer.URL)
req := newRequestWithAuthCode(t, testServer.URL, "TestHandleCallBackForGroupMapsInUserInfo")
identity, err := conn.HandleCallback(connector.Scopes{Groups: true}, req)
assert.Equal(t, err, nil)
sort.Strings(identity.Groups)
assert.Equal(t, len(identity.Groups), 2)
assert.Equal(t, identity.Groups[0], "admin-group")
assert.Equal(t, identity.Groups[1], "user-group")
assert.Equal(t, identity.UserID, "test-user-id")
assert.Equal(t, identity.Username, "test-username")
assert.Equal(t, identity.PreferredUsername, "test-preferred-username")
assert.Equal(t, identity.Email, "mod_mail")
assert.Equal(t, identity.EmailVerified, false)
}
func TestHandleCallBackForGroupsInToken(t *testing.T) {
tokenClaims := map[string]interface{}{
"groups_key": []string{"test-group"},
}
userInfoClaims := map[string]interface{}{
"name": "test-name",
"user_id_key": "test-user-id",
"user_name_key": "test-username",
"preferred_username": "test-preferred-username",
"email": "test-email",
"email_verified": true,
}
testServer := testSetup(t, tokenClaims, userInfoClaims)
defer testServer.Close()
conn := newConnector(t, testServer.URL)
req := newRequestWithAuthCode(t, testServer.URL, "TestHandleCallBackForGroupsInToken")
identity, err := conn.HandleCallback(connector.Scopes{Groups: true}, req)
assert.Equal(t, err, nil)
assert.Equal(t, len(identity.Groups), 1)
assert.Equal(t, identity.Groups[0], "test-group")
assert.Equal(t, identity.PreferredUsername, "test-preferred-username")
assert.Equal(t, identity.UserID, "test-user-id")
assert.Equal(t, identity.Username, "test-username")
assert.Equal(t, identity.Email, "")
assert.Equal(t, identity.EmailVerified, false)
}
func TestHandleCallbackForNumericUserID(t *testing.T) {
tokenClaims := map[string]interface{}{}
userInfoClaims := map[string]interface{}{
"name": "test-name",
"user_id_key": 1000,
"user_name_key": "test-username",
"preferred_username": "test-preferred-username",
"mail": "mod_mail",
"has_verified_email": false,
}
testServer := testSetup(t, tokenClaims, userInfoClaims)
defer testServer.Close()
conn := newConnector(t, testServer.URL)
req := newRequestWithAuthCode(t, testServer.URL, "TestHandleCallbackForNumericUserID")
identity, err := conn.HandleCallback(connector.Scopes{Groups: true}, req)
assert.Equal(t, err, nil)
assert.Equal(t, identity.UserID, "1000")
assert.Equal(t, identity.Username, "test-username")
assert.Equal(t, identity.PreferredUsername, "test-preferred-username")
assert.Equal(t, identity.Email, "mod_mail")
assert.Equal(t, identity.EmailVerified, false)
}
func testSetup(t *testing.T, tokenClaims map[string]interface{}, userInfoClaims map[string]interface{}) *httptest.Server {
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
t.Fatal("Failed to generate rsa key", err)
}
jwk := jose.JSONWebKey{
Key: key,
KeyID: "some-key",
Algorithm: "RSA",
}
mux := http.NewServeMux()
mux.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
token, err := newToken(&jwk, tokenClaims)
if err != nil {
t.Fatal("unable to generate token", err)
}
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(&map[string]string{
"access_token": token,
"id_token": token,
"token_type": "Bearer",
})
})
mux.HandleFunc("/userinfo", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(userInfoClaims)
})
return httptest.NewServer(mux)
}
func newToken(key *jose.JSONWebKey, claims map[string]interface{}) (string, error) {
signingKey := jose.SigningKey{Key: key, Algorithm: jose.RS256}
signer, err := jose.NewSigner(signingKey, &jose.SignerOptions{})
if err != nil {
return "", fmt.Errorf("new signer: %v", err)
}
payload, err := json.Marshal(claims)
if err != nil {
return "", fmt.Errorf("marshaling claims: %v", err)
}
signature, err := signer.Sign(payload)
if err != nil {
return "", fmt.Errorf("signing payload: %v", err)
}
return signature.CompactSerialize()
}
func newConnector(t *testing.T, serverURL string) *oauthConnector {
testConfig := Config{
ClientID: "testClient",
ClientSecret: "testSecret",
RedirectURI: serverURL + "/callback",
TokenURL: serverURL + "/token",
AuthorizationURL: serverURL + "/authorize",
UserInfoURL: serverURL + "/userinfo",
Scopes: []string{"openid", "groups"},
UserIDKey: "user_id_key",
}
testConfig.ClaimMapping.UserNameKey = "user_name_key"
testConfig.ClaimMapping.GroupsKey = "groups_key"
testConfig.ClaimMapping.EmailKey = "mail"
testConfig.ClaimMapping.EmailVerifiedKey = "has_verified_email"
log := logrus.New()
conn, err := testConfig.Open("id", log)
if err != nil {
t.Fatal(err)
}
oauthConn, ok := conn.(*oauthConnector)
if !ok {
t.Fatal(errors.New("failed to convert to oauthConnector"))
}
return oauthConn
}
func newRequestWithAuthCode(t *testing.T, serverURL string, code string) *http.Request {
req, err := http.NewRequest("GET", serverURL, nil)
if err != nil {
t.Fatal("failed to create request", err)
}
values := req.URL.Query()
values.Add("code", code)
req.URL.RawQuery = values.Encode()
return req
}

Some files were not shown because too many files have changed in this diff Show More