diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index c79655c..d67930e 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -39,11 +39,11 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v2
+ uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v1
+ uses: github/codeql-action/init@168b99b3c22180941ae7dbdd5f5c9678ede476ba # v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -54,7 +54,7 @@ jobs:
# 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@v1
+ uses: github/codeql-action/autobuild@168b99b3c22180941ae7dbdd5f5c9678ede476ba # v2
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
@@ -68,4 +68,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ uses: github/codeql-action/analyze@168b99b3c22180941ae7dbdd5f5c9678ede476ba # v2
diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml
new file mode 100644
index 0000000..dbd14c5
--- /dev/null
+++ b/.github/workflows/fuzz.yml
@@ -0,0 +1,16 @@
+name: Go fuzz test
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+jobs:
+ fuzz-lexer-test:
+ name: Fuzz escapeValue(...) test
+ runs-on: ubuntu-latest
+ steps:
+ # commit hash == v1.2.0
+ - uses: jidicula/go-fuzz-action@4f24eed45b25214f31a9fe035ca68ea2c88c6a13
+ with:
+ fuzz-time: 30s
+ fuzz-regexp: Fuzz_EscapeValue
\ No newline at end of file
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 7328425..22034d8 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -2,53 +2,55 @@ name: Go
on:
push:
- branches: [ main ]
+ branches: [main]
pull_request:
- branches: [ main ]
+ branches: [main]
jobs:
-
build:
name: Build
- runs-on: ubuntu-latest
- steps:
-
- - name: Set up Go 1.x
- uses: actions/setup-go@v2
- with:
- go-version: ^1.13
-
- - name: Check out code into the Go module directory
- uses: actions/checkout@v2
+ strategy:
+ fail-fast: true
+ matrix:
+ go: ["1.20", "1.19", "1.18"]
+ platform: [ubuntu-latest] # can not run in windows OS
+ runs-on: ${{ matrix.platform }}
- - name: Get dependencies
- run: |
- go get -v -t -d ./...
- if [ -f Gopkg.toml ]; then
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- dep ensure
- fi
-
- - name: Build
- run: |
- set -e
- exit_status=
- for f in $(find . -name go.mod)
- do
- pushd $(dirname $f) > /dev/null
- go build ./... || exit_status=$?
- popd > /dev/null
- done
- exit $status
-
- - name: Test
- run: |
- set -e
- exit_status=
- for f in $(find . -name go.mod)
- do
- pushd $(dirname $f) > /dev/null
- go test -test.v ./... || exit_status=$?
- popd > /dev/null
- done
- exit $exit_status
+ steps:
+ - name: Set up Go 1.x
+ uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
+ with:
+ go-version: ${{ matrix.go }}
+
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0
+
+ - name: go mod package cache
+ uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1
+ with:
+ path: ~/go/pkg/mod
+ key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('tests/go.mod') }}
+
+ - name: Build
+ run: |
+ set -e
+ exit_status=
+ for f in $(find . -name go.mod)
+ do
+ pushd $(dirname $f) > /dev/null
+ go build ./... || exit_status=$?
+ popd > /dev/null
+ done
+ exit $status
+
+ - name: Test
+ run: |
+ set -e
+ exit_status=
+ for f in $(find . -name go.mod)
+ do
+ pushd $(dirname $f) > /dev/null
+ go test -test.v ./... || exit_status=$?
+ popd > /dev/null
+ done
+ exit $exit_status
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1c49fe..c53f5c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,58 @@ Canonical reference for changes, improvements, and bugfixes for cap.
## Next
-* Add Validator `ValidateAllowMissingIatNbfExp` method to allow all of iat/nbf/exp to be missing.
+* LDAP
+ * Add worker pool for LDAP token group lookups ([**PR**](https://github.com/hashicorp/cap/pull/98))
+
+## 0.3.4
+
+### Bug fixes
+
+* OIDC/examples/cli
+ * Use free port if OIDC_PORT is not set for the example ([**PR**](https://github.com/hashicorp/cap/pull/79))
+
+
+## 0.3.3
+### Bug fixes:
+* LDAP
+ * A more compete fix for `escapeValue(...)` and we've stopped exporting it ([**PR**](https://github.com/hashicorp/cap/pull/78))
+## 0.3.2
+
+### Bug fixes:
+* Address a set of LDAP issues ([**PR**](https://github.com/hashicorp/cap/pull/77)):
+ * Properly escape user filters when using UPN domains
+ * Increase max tls to 1.3
+ * Improve `EscapeValue(...)`
+ * Use text template for rendering filters
+
+## 0.3.1
+
+### Bug Fixes
+* Fixes integer overflow in `auth_time` claim validation when compiled for 32-bit
+ architecture ([**PR**](https://github.com/hashicorp/cap/pull/76))
+
+## 0.3.0
+#### OIDC
+* Add `ProviderConfig` which creates a provider that doesn't support
+ OIDC discovery. It's probably better to use NewProvider(...) with discovery
+ whenever possible ([**PR**](https://github.com/hashicorp/cap/pull/57) and [issue](https://github.com/hashicorp/cap/issues/55)).
+* Improve WSL detection ([**PR**](https://github.com/hashicorp/cap/pull/51))
+* Add option to allow all of IAT, NBF, and EXP to be missing
+ ([**PR**](https://github.com/hashicorp/cap/pull/50))
+* Validate sub and aud are present in an id_token ([**PR**](https://github.com/hashicorp/cap/pull/48))
+
+#### LDAP
+* Add better (more consistent) timeouts ([**PR**](https://github.com/hashicorp/cap/pull/61))
+* Add better error msgs on failed search queries ([**PR**](https://github.com/hashicorp/cap/pull/60))
+* Add new config fields for including/excluding user attrs ([**PR**](https://github.com/hashicorp/cap/pull/59))
+* Add `WithUserAttributes(...)` option to the ldap package that allows callers
+ to request that attributes be returned for the authenticating user ([**PR**](https://github.com/hashicorp/cap/pull/58))
+
+
+
+## 0.2.0 (2022/04/08)
+* Add support for LDAP/AD authentication ([**PR**](https://github.com/hashicorp/cap/pull/47))
+
## 0.1.1 (2021/06/24)
diff --git a/LICENSE b/LICENSE
index be2cc4d..8d84ded 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,5 @@
+Copyright (c) 2020 HashiCorp, Inc.
+
Mozilla Public License, version 2.0
1. Definitions
diff --git a/docs.go b/docs.go
index 22d49bc..da17702 100644
--- a/docs.go
+++ b/docs.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
// cap (collection of authentication packages) provides a collection of related
// packages which enable support for OIDC, JWT Verification, and Distributed Claims.
//
diff --git a/docs_test.go b/docs_test.go
index 8bd2663..e9b4a8b 100644
--- a/docs_test.go
+++ b/docs_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package cap_test
import (
diff --git a/go.mod b/go.mod
index 7da4cd8..8334f18 100644
--- a/go.mod
+++ b/go.mod
@@ -1,26 +1,32 @@
module github.com/hashicorp/cap
-go 1.15
+go 1.20
require (
- github.com/coreos/go-oidc/v3 v3.1.0
- github.com/fatih/color v1.13.0 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
- github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/coreos/go-oidc/v3 v3.5.0
+ github.com/go-jose/go-jose/v3 v3.0.0
github.com/hashicorp/go-cleanhttp v0.5.2
- github.com/hashicorp/go-hclog v1.0.0
+ github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-multierror v1.1.1
- github.com/hashicorp/go-uuid v1.0.2
- github.com/mattn/go-colorable v0.1.12 // indirect
- github.com/stretchr/testify v1.7.0
+ github.com/hashicorp/go-uuid v1.0.3
+ github.com/stretchr/testify v1.8.1
github.com/yhat/scrape v0.0.0-20161128144610-24b7890b0945
- golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
- golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
- golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
- golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
- golang.org/x/text v0.3.7
+ golang.org/x/net v0.7.0
+ golang.org/x/oauth2 v0.5.0
+ golang.org/x/text v0.7.0
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/fatih/color v1.14.1 // indirect
+ github.com/golang/protobuf v1.5.2 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ golang.org/x/crypto v0.6.0 // indirect
+ golang.org/x/sys v0.5.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/protobuf v1.27.1 // indirect
- gopkg.in/square/go-jose.v2 v2.6.0
- gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+ google.golang.org/protobuf v1.28.1 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 54097fd..e92c873 100644
--- a/go.sum
+++ b/go.sum
@@ -1,431 +1,122 @@
-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=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
-cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
-cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
-cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
-cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
-cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
-cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
-cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
-cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
-cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-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/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw=
-github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
+cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw=
+github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
+github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
+github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
+github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/golang/protobuf v1.3.1/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.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
-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.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/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-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.4.1/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.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
-github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo=
-github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
+github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
-github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yhat/scrape v0.0.0-20161128144610-24b7890b0945 h1:6Ju8pZBYFTN9FaV/JvNBiIHcsgEmP4z4laciqjfjY8E=
github.com/yhat/scrape v0.0.0-20161128144610-24b7890b0945/go.mod h1:4vRFPPNYllgCacoj+0FoKOjTW68rUhEfqPLiEJaK2w8=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-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/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
-golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
+golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
+golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
-golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
-google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-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/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
-google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
-google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-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 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
-gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/jwt/algs.go b/jwt/algs.go
index 32771d6..86dff35 100644
--- a/jwt/algs.go
+++ b/jwt/algs.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt
import "fmt"
diff --git a/jwt/algs_test.go b/jwt/algs_test.go
index c251f9a..25a9dcb 100644
--- a/jwt/algs_test.go
+++ b/jwt/algs_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt
import (
diff --git a/jwt/docs.go b/jwt/docs.go
index d1d7cd4..a5d5b7e 100644
--- a/jwt/docs.go
+++ b/jwt/docs.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
/*
Package jwt provides signature verification and claims set validation for JSON Web Tokens (JWT)
of the JSON Web Signature (JWS) form.
diff --git a/jwt/docs_test.go b/jwt/docs_test.go
index 0e85c13..ee5cecc 100644
--- a/jwt/docs_test.go
+++ b/jwt/docs_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt_test
import (
diff --git a/jwt/jwt.go b/jwt/jwt.go
index 155ea3b..e095d52 100644
--- a/jwt/jwt.go
+++ b/jwt/jwt.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt
import (
@@ -7,8 +10,8 @@ import (
"fmt"
"time"
- "gopkg.in/square/go-jose.v2"
- "gopkg.in/square/go-jose.v2/jwt"
+ "github.com/go-jose/go-jose/v3"
+ "github.com/go-jose/go-jose/v3/jwt"
)
// DefaultLeewaySeconds defines the amount of leeway that's used by default
diff --git a/jwt/jwt_test.go b/jwt/jwt_test.go
index 6a87041..bd69317 100644
--- a/jwt/jwt_test.go
+++ b/jwt/jwt_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt
import (
@@ -8,9 +11,10 @@ import (
"testing"
"time"
- "github.com/hashicorp/cap/oidc"
+ "github.com/go-jose/go-jose/v3/jwt"
"github.com/stretchr/testify/require"
- "gopkg.in/square/go-jose.v2/jwt"
+
+ "github.com/hashicorp/cap/oidc"
)
var priv *rsa.PrivateKey
diff --git a/jwt/keyset.go b/jwt/keyset.go
index f58caa6..cfb3a02 100644
--- a/jwt/keyset.go
+++ b/jwt/keyset.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt
import (
@@ -17,9 +20,9 @@ import (
"strings"
"github.com/coreos/go-oidc/v3/oidc"
+ "github.com/go-jose/go-jose/v3/jwt"
"github.com/hashicorp/go-cleanhttp"
"golang.org/x/oauth2"
- "gopkg.in/square/go-jose.v2/jwt"
)
// KeySet represents a set of keys that can be used to verify the signatures of JWTs.
diff --git a/jwt/keyset_test.go b/jwt/keyset_test.go
index 01be08e..0d38655 100644
--- a/jwt/keyset_test.go
+++ b/jwt/keyset_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package jwt
import (
diff --git a/ldap/README.md b/ldap/README.md
index c5079c1..b83150f 100644
--- a/ldap/README.md
+++ b/ldap/README.md
@@ -1,4 +1,5 @@
# ldap
+
[![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/cap/ldap.svg)](https://pkg.go.dev/github.com/hashicorp/cap/ldap)
ldap is a package for writing clients that authenticate using Active Directory
@@ -11,7 +12,7 @@ Primary types provided by the package:
-## Examples:
+## Examples
* [CLI example](examples/cli/) which implements an ldap
user authentication CLI.
@@ -45,22 +46,24 @@ information on how to authenticate users, and instructions on how to query for
group membership. The configuration options are categorized and detailed below.
### Connection parameters
+
* `URLS` ([]string, required) - The LDAP server to connect to. Examples:
`ldap://ldap.myorg.com`, `ldaps://ldap.myorg.com:636`. If there's more than one
URL configured, the directories will be tried in-order if there are errors
during the connection process.
* `StartTLS` (bool, optional) - If true, issues a StartTLS command after
- establishing an unencrypted connection.
+ establishing an unencrypted connection.
* `InsecureTLS` (bool, optional) - If true, skips LDAP server SSL certificate
- verification - insecure, use with caution!
+ verification - insecure, use with caution!
* `Certificate` (string, optional) - CA certificate to use when verifying LDAP
- server certificate, must be x509 PEM encoded.
+ server certificate, must be x509 PEM encoded.
* `ClientTLSCert` (string, optional) - Client certificate to provide to the LDAP
- server, must be x509 PEM encoded.
+ server, must be x509 PEM encoded.
* `ClientTLSKey` (string, optional) - Client certificate key to provide to the
- LDAP server, must be x509 PEM encoded.
+ LDAP server, must be x509 PEM encoded.
### Binding parameters
+
There are two alternate methods of resolving the user object used to
authenticate the end user: *Search* or *User Principal Name*. When using
*Search*, the bind can be either anonymous or authenticated. *User Principal
@@ -68,13 +71,14 @@ Name* is a method of specifying users supported by Active Directory. More
information on UPN can be found
[here](https://docs.microsoft.com/en-us/windows/win32/ad/naming-properties?redirectedfrom=MSDN#userPrincipalName).
-**Binding - Authenticated Search**
+#### Binding - Authenticated Search
+
* `BindDN` (string, optional) - Distinguished name of object to bind when
performing user and group search. Example: `cn=application-acct,ou=Users,dc=example,dc=com`
* `BindPassword` (string, optional) - Password to use along with binddn when
- performing user search.
+ performing user search.
* `UserDN` (string, optional) - Base DN under which to perform user search.
- Example: `ou=Users,dc=example,dc=com`
+ Example: `ou=Users,dc=example,dc=com`
* `UserAttr` (string, optional) - Attribute on user attribute object matching
the username passed when authenticating. Examples: "cn", "uid"
* `UserFilter` (string, optional) - Go template used to construct a ldap user
@@ -87,7 +91,8 @@ information on UPN can be found
could write
`(&(objectClass=user)({{.UserAttr}}={{.Username}})(!(employeeType=Contractor)))`.
-**Binding - Anonymous Search**
+#### Binding - Anonymous Search
+
* `DiscoverDN` (bool, optional) - If true, use anonymous bind to discover the bind DN of a user
* `UserDN` (string, optional) - Base DN under which to perform user search.
Example: `ou=Users,dc=example,dc=com`
@@ -96,16 +101,47 @@ information on UPN can be found
* `AllowEmptyPasswordBinds` (bool, optional) - This option prevents users from bypassing authentication when providing an empty password. The default is `false`.
* `AnonymousGroupSearch` (bool, optional) - Use anonymous binds when performing LDAP group searches. Defaults to `false`.
-**Binding - User Principal Name (AD)**
+#### Binding - User Principal Name (AD)
+
* `UPNDomain` (string, optional) - userPrincipalDomain used to construct the UPN
string for the authenticating user. The constructed UPN will appear as
`[username]@UPNDomain`. Example: `example.com`, which will result in binding as `username@example.com`.
+#### Alias dereferencing
+
+* `DerefAliases` (string, optional) - Will control how aliases are dereferenced
+ when performing the search. Possible values are: `never`, `finding`,
+ `searching`, and `always`. If unset, a default of `never` is used. When set to
+ `finding`, it will only dereference aliases during name resolution of the
+ base. When set to `searching`, it will dereference aliases after name
+ resolution.
+
+### Group Membership Resolution
-## Group Membership Resolution
Once a user has been authenticated, the LDAP auth method must know how to resolve which groups the user is a member of. The configuration for this can vary depending on your LDAP server and your directory schema. There are two main strategies when resolving group membership - the first is searching for the authenticated user object and following an attribute to groups it is a member of. The second is to search for group objects of which the authenticated user is a member of. Both methods are supported.
* `GroupFilter` (string, optional) - Go template used when constructing the group membership query. The template can access the following context variables: [UserDN, Username]. The default is `(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))`, which is compatible with several common directory schemas. To support nested group resolution for Active Directory, instead use the following query: `(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))`.
* `GroupDN` (string, required) - LDAP search base to use for group membership search. This can be the root containing either groups or users. Example: `ou=Groups,dc=example,dc=com`
* `GroupAttr` (string, optional) - LDAP attribute to follow on objects returned by GroupFilter in order to enumerate user group membership. Examples: for GroupFilter queries returning group objects, use: `cn`. For queries returning user objects, use: `memberOf`. The default is `cn`.
-Note: When using Authenticated Search for binding parameters (see above) the distinguished name defined for `BindDN` is used for the group search. Otherwise, the authenticating user is used to perform the group search.
\ No newline at end of file
+Note: When using Authenticated Search for binding parameters (see above) the
+distinguished name defined for `BindDN` is used for the group search. Otherwise,
+the authenticating user is used to perform the group search.
+
+### User Attributes
+
+Using configuration you can choose to optionally include an authenticated
+user's DN and entry attributes in the results of an authentication request.
+
+* `IncludeUserAttributes` (bool, optional) - If true, specifies that the
+ authenticating user's DN and attributes be included an authentication
+ AuthResult. Note: the default password attribute for both openLDAP
+ (userPassword) and AD (unicodePwd) will always be excluded.
+
+* `ExcludeUserAttributes` ([]string, optional) - If specified, optionally
+ defines a set of user attributes to be excluded when an authenticating user's
+ attributes are included in an AuthResult.Note: the default password attribute
+ for both openLDAP (userPassword) and AD (unicodePwd) will always be excluded.
+
+### Other
+
+* `MaximumPageSize` (int, optional) - If set to a value greater than 0, the LDAP backend will use the LDAP server's paged search control to request pages of up to the given size. This can be used to avoid hitting the LDAP server's maximum result size limit. Otherwise, the LDAP backend will not use the paged search control.
diff --git a/ldap/client.go b/ldap/client.go
index 5a05cbe..b57ebb8 100644
--- a/ldap/client.go
+++ b/ldap/client.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap
import (
@@ -6,16 +9,19 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/binary"
+ "encoding/hex"
"fmt"
- "html/template"
"math"
"net"
"net/url"
"strings"
+ "sync"
+ "text/template"
"time"
"github.com/go-ldap/ldap/v3"
"github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/go-secure-stdlib/tlsutil"
)
@@ -39,12 +45,12 @@ func fmtWarning(format string, a ...interface{}) Warning {
// NewClient will create a new client from the configuration. The following
// defaults will be used if no config value is provided for them:
-// * URLs: see constant DefaultURL
-// * UserAttr: see constant DefaultUserAttr
-// * GroupAttr: see constant DefaultGroupAttr
-// * GroupFilter: see constant DefaultGroupFilter
-// * TLSMinVersion: see constant DefaultTLSMinVersion
-// * TLSMaxVersion: see constant DefaultTLSMaxVersion
+// - URLs: see constant DefaultURL
+// - UserAttr: see constant DefaultUserAttr
+// - GroupAttr: see constant DefaultGroupAttr
+// - GroupFilter: see constant DefaultGroupFilter
+// - TLSMinVersion: see constant DefaultTLSMinVersion
+// - TLSMaxVersion: see constant DefaultTLSMaxVersion
func NewClient(ctx context.Context, conf *ClientConfig) (*Client, error) {
const op = "ldap.NewClient"
if conf == nil {
@@ -109,7 +115,7 @@ func (c *Client) connect(ctx context.Context, opt ...Option) error {
var tlsConfig *tls.Config
switch u.Scheme {
case schemeLDAP:
- conn, err = ldap.DialURL(uut)
+ conn, err = ldap.DialURL(uut, ldap.DialWithDialer(&net.Dialer{Timeout: c.getTimeout()}))
if err != nil {
break
}
@@ -123,7 +129,7 @@ func (c *Client) connect(ctx context.Context, opt ...Option) error {
withInsecureTLS(c.conf.InsecureTLS),
withTLSMinVersion(c.conf.TLSMinVersion),
withTLSMaxVersion(c.conf.TLSMaxVersion),
- withCertificate(c.conf.Certificate),
+ withCertificates(c.conf.Certificates...),
withClientTLSCert(c.conf.ClientTLSCert),
withClientTLSKey(c.conf.ClientTLSKey),
)
@@ -138,14 +144,14 @@ func (c *Client) connect(ctx context.Context, opt ...Option) error {
withInsecureTLS(c.conf.InsecureTLS),
withTLSMinVersion(c.conf.TLSMinVersion),
withTLSMaxVersion(c.conf.TLSMaxVersion),
- withCertificate(c.conf.Certificate),
+ withCertificates(c.conf.Certificates...),
withClientTLSCert(c.conf.ClientTLSCert),
withClientTLSKey(c.conf.ClientTLSKey),
)
if err != nil {
break
}
- conn, err = ldap.DialURL(uut, ldap.DialWithTLSConfig(tlsConfig))
+ conn, err = ldap.DialURL(uut, ldap.DialWithTLSDialer(tlsConfig, &net.Dialer{Timeout: c.getTimeout()}))
default:
retErr = multierror.Append(retErr, fmt.Errorf("%s: invalid LDAP scheme in url %q: %w", op, uut, ErrInvalidParameter))
continue
@@ -159,13 +165,20 @@ func (c *Client) connect(ctx context.Context, opt ...Option) error {
if retErr != nil {
return retErr
}
- if timeout := c.conf.RequestTimeout; timeout > 0 {
- conn.SetTimeout(time.Duration(timeout) * time.Second)
- }
+ conn.SetTimeout(c.getTimeout())
c.conn = conn
return nil
}
+func (c *Client) getTimeout() time.Duration {
+ switch c.conf.RequestTimeout {
+ case 0:
+ return DefaultTimeout * time.Second
+ default:
+ return time.Duration(c.conf.RequestTimeout) * time.Second
+ }
+}
+
// AuthResult is the result from a user authentication request via Client.Authenticate(...)
type AuthResult struct {
// Success represents whether or not the attempt was successful
@@ -175,17 +188,34 @@ type AuthResult struct {
// user (optional, see WithGroups() option)
Groups []string
+ // UserDN of the authenticated user (optional see WithUserAttributes()
+ // option along with IncludeUserAttributes and ExcludedUserAttributes config
+ // fields).
+ UserDN string
+
+ // UserAttributes that are associated with the authenticated user (optional
+ // see WithUserAttributes() option along with IncludeUserAttributes and
+ // ExcludedUserAttributes config fields)
+ UserAttributes map[string][]string
+
// Warnings are warnings that happen during either authentication or when
// attempting to find the groups associated with the authenticated user (see
// the WithGroups option)
Warnings []Warning
}
+type Attribute struct {
+ // Name is the name of the LDAP attribute
+ Name string
+ // Vals are the LDAP attribute values
+ Vals []string
+}
+
// Authenticate the user using the client's configured directory service. If
// the WithGroups option is specified, it will also return the user's groups
// from the directory.
//
-// Supported options: WithGroups, WithDialer, WithURLs
+// Supported options: WithUserAttributes, WithGroups, WithDialer, WithURLs
func (c *Client) Authenticate(ctx context.Context, username, password string, opt ...Option) (*AuthResult, error) {
const op = "ldap.(Client).Authenticate"
if username == "" {
@@ -214,7 +244,8 @@ func (c *Client) Authenticate(ctx context.Context, username, password string, op
return nil, fmt.Errorf("%s: unable to bind user: %w", op, err)
}
opts := getConfigOpts(opt...)
- if !opts.withGroups {
+ if !opts.withGroups && !c.conf.IncludeUserGroups &&
+ !opts.withUserAttributes && !c.conf.IncludeUserAttributes {
return &AuthResult{
Success: true,
}, nil
@@ -235,6 +266,24 @@ func (c *Client) Authenticate(ctx context.Context, username, password string, op
return nil, fmt.Errorf("%s: failed to get the DN for the authenticated user: %w", op, err)
}
+ userAttrs := map[string][]string{}
+ if c.conf.IncludeUserAttributes || opts.withUserAttributes {
+ attrs, err := c.getUserAttributes(userDN)
+ if err != nil {
+ return nil, fmt.Errorf("%s: failed to get user attributes: %w", op, err)
+ }
+ for _, a := range attrs {
+ userAttrs[a.Name] = a.Vals
+ }
+ }
+ if !opts.withGroups && !c.conf.IncludeUserGroups {
+ return &AuthResult{
+ Success: true,
+ UserDN: userDN,
+ UserAttributes: userAttrs,
+ }, nil
+ }
+
if c.conf.AnonymousGroupSearch {
if err := c.conn.UnauthenticatedBind(userDN); err != nil {
return nil, fmt.Errorf("%s: group search anonymous bind failed: %w", op, err)
@@ -246,11 +295,22 @@ func (c *Client) Authenticate(ctx context.Context, username, password string, op
return nil, fmt.Errorf("%s: unable to get user groups: %w", op, err)
}
- return &AuthResult{
- Success: true,
- Groups: ldapGroups,
- Warnings: warnings,
- }, nil
+ switch {
+ case c.conf.IncludeUserAttributes || opts.withUserAttributes:
+ return &AuthResult{
+ Success: true,
+ UserDN: userDN,
+ UserAttributes: userAttrs,
+ Groups: ldapGroups,
+ Warnings: warnings,
+ }, nil
+ default:
+ return &AuthResult{
+ Success: true,
+ Groups: ldapGroups,
+ Warnings: warnings,
+ }, nil
+ }
}
// Close will close the client's connection to the directory service.
@@ -260,6 +320,45 @@ func (c *Client) Close(ctx context.Context) {
}
}
+func (c *Client) getUserAttributes(userDN string) ([]Attribute, error) {
+ const op = "ldap.(Client).getUserAttributes"
+ switch {
+ case userDN == "":
+ return nil, fmt.Errorf("%s: missing user dn: %w", op, ErrInvalidParameter)
+ }
+
+ result, err := c.conn.Search(&ldap.SearchRequest{
+ BaseDN: userDN,
+ Scope: ldap.ScopeBaseObject,
+ DerefAliases: derefAliasMap[c.conf.DerefAliases],
+ Filter: "(objectClass=*)",
+ })
+ switch {
+ case err != nil:
+ return nil, fmt.Errorf("%s: LDAP search for user attributes failed (baseDN: %q / filter: %q): %w", op, userDN, "(objectClass=*)", err)
+ case len(result.Entries) != 1:
+ return nil, fmt.Errorf("%s: LDAP search for user attributes was 0 or not unique", op)
+ }
+ userEntry := result.Entries[0]
+ attributes := make([]Attribute, 0, len(userEntry.Attributes))
+ for _, a := range userEntry.Attributes {
+ switch {
+ // exclude the default openLDAP password attribute
+ case strings.EqualFold(a.Name, DefaultOpenLDAPUserPasswordAttribute):
+ // exclude the default AD password attribute
+ case strings.EqualFold(a.Name, DefaultADUserPasswordAttribute):
+ // filter out excluded attributes
+ case strutil.StrListContainsCaseInsensitive(c.conf.ExcludedUserAttributes, a.Name):
+ default:
+ attributes = append(attributes, Attribute{
+ Name: a.Name,
+ Vals: a.Values,
+ })
+ }
+ }
+ return attributes, nil
+}
+
// getGroups queries LDAP and returns a slice describing the set of groups the
// authenticated user is a member of.
//
@@ -271,18 +370,20 @@ func (c *Client) Close(ctx context.Context) {
// defined in c.conf.GroupAttr.
//
// c.conf.GroupFilter is a go template and is compiled with the following context: [UserDN, Username]
-// UserDN - The DN of the authenticated user
-// Username - The Username of the authenticated user
+//
+// UserDN - The DN of the authenticated user
+// Username - The Username of the authenticated user
//
// Example:
-// c.conf.GroupFilter = "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))"
-// c.conf.GroupDN = "OU=Groups,DC=myorg,DC=com"
-// c.conf.GroupAttr = "cn"
//
-// NOTE - If the config GroupFilter is empty, no query is performed and an
-// empty result slice is returned.
+// c.conf.GroupFilter = "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))"
+// c.conf.GroupDN = "OU=Groups,DC=myorg,DC=com"
+// c.conf.GroupAttr = "cn"
+//
+// NOTE - If the config GroupFilter is empty, no query is performed and an
+// empty result slice is returned.
func (c *Client) getGroups(userDN string, username string) ([]string, []Warning, error) {
- const op = "ldap.(Client).getLDAPGroups"
+ const op = "ldap.(Client).getGroups"
var warnings []Warning
if userDN == "" {
return nil, warnings, fmt.Errorf("%s: missing user dn: %w", op, ErrInvalidParameter)
@@ -339,16 +440,17 @@ func (c *Client) tokenGroupsSearch(userDN string) ([]*ldap.Entry, []Warning, err
return nil, warnings, fmt.Errorf("%s: missing user dn: %w", op, ErrInvalidParameter)
}
result, err := c.conn.Search(&ldap.SearchRequest{
- BaseDN: userDN,
- Scope: ldap.ScopeBaseObject,
- Filter: "(objectClass=*)",
+ BaseDN: userDN,
+ Scope: ldap.ScopeBaseObject,
+ DerefAliases: derefAliasMap[c.conf.DerefAliases],
+ Filter: "(objectClass=*)",
Attributes: []string{
"tokenGroups",
},
SizeLimit: 1,
})
if err != nil {
- return nil, warnings, fmt.Errorf("%s: search failed: %w", op, err)
+ return nil, warnings, fmt.Errorf("%s: search failed (baseDN: %q / filter: %q): %w", op, userDN, "(objectClass=*)", err)
}
if len(result.Entries) == 0 {
warnings = append(warnings, fmtWarning("%s: unable to read object for group attributes: userdn %s and groupattr %s", op, userDN, c.conf.GroupAttr))
@@ -357,34 +459,63 @@ func (c *Client) tokenGroupsSearch(userDN string) ([]*ldap.Entry, []Warning, err
userEntry := result.Entries[0]
groupAttrValues := userEntry.GetRawAttributeValues("tokenGroups")
-
groupEntries := make([]*ldap.Entry, 0, len(groupAttrValues))
- for _, sidBytes := range groupAttrValues {
- sidString, err := sidBytesToString(sidBytes)
- if err != nil {
- warnings = append(warnings, fmtWarning("%s: unable to read sid: %s", op, err.Error()))
- continue
- }
- groupResult, err := c.conn.Search(&ldap.SearchRequest{
- BaseDN: fmt.Sprintf("", sidString),
- Scope: ldap.ScopeBaseObject,
- Filter: "(objectClass=*)",
- Attributes: []string{
- "1.1", // RFC no attributes
- },
- SizeLimit: 1,
- })
- if err != nil {
- warnings = append(warnings, fmtWarning("%s: unable to read the group sid: %s", op, sidString))
- continue
+ {
+ // we're using worker pool to make looking up token groups more
+ // performant. token groups have to be looked up individually, so if a
+ // user is a member of MANY groups it can be helpful to do these lookups
+ // concurrently vs serially. This is based on benchmarks and a
+ // subsequent implementation within vault's codebase for looking up token
+ // groups. See: https://github.com/hashicorp/vault/pull/22659
+ const maxWorkers = 10
+ var wg sync.WaitGroup
+ var lock sync.Mutex
+ taskChan := make(chan string) // intentionally an unbuffered chan so we can iterate (range) over it before it's closed.
+ for i := 0; i < maxWorkers; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for sidString := range taskChan {
+ groupResult, err := c.conn.Search(&ldap.SearchRequest{
+ BaseDN: fmt.Sprintf("", sidString),
+ Scope: ldap.ScopeBaseObject,
+ DerefAliases: derefAliasMap[c.conf.DerefAliases],
+ Filter: "(objectClass=*)",
+ Attributes: []string{
+ "1.1", // RFC no attributes
+ },
+ SizeLimit: 1,
+ })
+ if err != nil {
+ warnings = append(warnings, fmtWarning("%s: unable to read the group sid (baseDN: %q / filter: %q): %s", op, fmt.Sprintf("", sidString), "(objectClass=*)", sidString))
+ continue
+ }
+ if len(groupResult.Entries) == 0 {
+ warnings = append(warnings, fmtWarning("%s: unable to find the group sid (baseDN: %q / filter: %q): %s", op, fmt.Sprintf("", sidString), "(objectClass=*)", sidString))
+ continue
+ }
+ lock.Lock()
+ groupEntries = append(groupEntries, groupResult.Entries[0])
+ lock.Unlock()
+ }
+ }()
}
- if len(groupResult.Entries) == 0 {
- warnings = append(warnings, fmtWarning("%s: unable to find the group sid: %s", op, sidString))
- continue
+ for _, sidBytes := range groupAttrValues {
+ sidString, err := sidBytesToString(sidBytes)
+ if err != nil {
+ warnings = append(warnings, fmtWarning("%s: unable to read sid: %s", op, err.Error()))
+ continue
+ }
+ taskChan <- sidString
}
+ // closing the taskChan will allow the workers to start iterating
+ // (range) - this unblocks them
+ close(taskChan)
- groupEntries = append(groupEntries, groupResult.Entries[0])
+ // wait for all the workers to finish up the token group lookups and
+ // adding all the groups to the slice of group entries
+ wg.Wait()
}
return groupEntries, warnings, nil
@@ -426,17 +557,31 @@ func (c *Client) filterGroupsSearch(userDN string, username string) ([]*ldap.Ent
return nil, warnings, fmt.Errorf("%s: LDAP search failed due to template parsing error: %w", op, err)
}
- result, err := c.conn.Search(&ldap.SearchRequest{
- BaseDN: c.conf.GroupDN,
- Scope: ldap.ScopeWholeSubtree,
- Filter: renderedQuery.String(),
+ var result *ldap.SearchResult
+ req := ldap.SearchRequest{
+ BaseDN: c.conf.GroupDN,
+ Scope: ldap.ScopeWholeSubtree,
+ DerefAliases: derefAliasMap[c.conf.DerefAliases],
+ Filter: renderedQuery.String(),
Attributes: []string{
c.conf.GroupAttr,
},
SizeLimit: math.MaxInt32,
- })
+ }
+ switch {
+ case c.conf.MaximumPageSize > 0:
+ result, err = c.conn.SearchWithPaging(&req, uint32(c.conf.MaximumPageSize))
+ default:
+ result, err = c.conn.Search(&req)
+ }
if err != nil {
- return nil, warnings, fmt.Errorf("%s: LDAP search failed: %w", op, err)
+ switch {
+ case ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject):
+ warnings = append(warnings, Warning(err.Error()))
+ return []*ldap.Entry{}, warnings, nil
+ default:
+ return nil, warnings, fmt.Errorf("%s: LDAP search failed (baseDN: %q / filter: %q): %w", op, c.conf.GroupDN, renderedQuery.String(), err)
+ }
}
return result.Entries, warnings, nil
@@ -526,13 +671,14 @@ func (c *Client) getUserBindDN(username string) (string, error) {
}
result, err := c.conn.Search(&ldap.SearchRequest{
- BaseDN: c.conf.UserDN,
- Scope: ldap.ScopeWholeSubtree,
- Filter: filter,
- SizeLimit: math.MaxInt32,
+ BaseDN: c.conf.UserDN,
+ Scope: ldap.ScopeWholeSubtree,
+ DerefAliases: derefAliasMap[c.conf.DerefAliases],
+ Filter: filter,
+ SizeLimit: math.MaxInt32,
})
if err != nil {
- return "", fmt.Errorf("%s: LDAP search for binddn failed: %w", op, err)
+ return "", fmt.Errorf("%s: LDAP search for binddn failed using (baseDN: %q / filter: %q): %w", op, c.conf.UserDN, filter, err)
}
if len(result.Entries) != 1 {
return "", fmt.Errorf("LDAP search for binddn 0 or not unique")
@@ -540,9 +686,9 @@ func (c *Client) getUserBindDN(username string) (string, error) {
bindDN = result.Entries[0].DN
} else {
if c.conf.UPNDomain != "" {
- bindDN = fmt.Sprintf("%s@%s", EscapeValue(username), c.conf.UPNDomain)
+ bindDN = fmt.Sprintf("%s@%s", escapeValue(username), c.conf.UPNDomain)
} else {
- bindDN = fmt.Sprintf("%s=%s,%s", c.conf.UserAttr, EscapeValue(username), c.conf.UserDN)
+ bindDN = fmt.Sprintf("%s=%s,%s", c.conf.UserAttr, escapeValue(username), c.conf.UserDN)
}
}
return bindDN, nil
@@ -562,15 +708,16 @@ func (c *Client) getUserDN(bindDN, username string) (string, error) {
var userDN string
if c.conf.UPNDomain != "" {
// Find the distinguished name for the user if userPrincipalName used for login
- filter := fmt.Sprintf("(userPrincipalName=%s@%s)", EscapeValue(username), c.conf.UPNDomain)
+ filter := fmt.Sprintf("(userPrincipalName=%s@%s)", escapeValue(username), c.conf.UPNDomain)
result, err := c.conn.Search(&ldap.SearchRequest{
- BaseDN: c.conf.UserDN,
- Scope: ldap.ScopeWholeSubtree,
- Filter: filter,
- SizeLimit: math.MaxInt32,
+ BaseDN: c.conf.UserDN,
+ Scope: ldap.ScopeWholeSubtree,
+ DerefAliases: derefAliasMap[c.conf.DerefAliases],
+ Filter: filter,
+ SizeLimit: math.MaxInt32,
})
if err != nil {
- return userDN, fmt.Errorf("%s: LDAP search failed for detecting user: %w", op, err)
+ return userDN, fmt.Errorf("%s: LDAP search failed for detecting user (baseDN: %q / filter: %q): %w", op, c.conf.UserDN, filter, err)
}
for _, e := range result.Entries {
userDN = e.DN
@@ -649,7 +796,11 @@ func (c *Client) renderUserSearchFilter(username string) (string, error) {
}
if c.conf.UPNDomain != "" {
context.UserAttr = "userPrincipalName"
- context.Username = fmt.Sprintf("%s@%s", EscapeValue(username), c.conf.UPNDomain)
+ // Intentionally, calling EscapeFilter(...) (vs EscapeValue) since the
+ // username is being injected into a search filter.
+ // As an untrusted string, the username must be escaped according to RFC
+ // 4515, in order to prevent attackers from injecting characters that could modify the filter
+ context.Username = fmt.Sprintf("%s@%s", EscapeFilter(username), c.conf.UPNDomain)
}
var renderedFilter bytes.Buffer
@@ -689,11 +840,13 @@ func getTLSConfig(host string, opt ...Option) (*tls.Config, error) {
if opts.withInsecureTLS {
tlsConfig.InsecureSkipVerify = true
}
- if opts.withCertificate != "" {
+ if opts.withCertificates != nil {
caPool := x509.NewCertPool()
- ok := caPool.AppendCertsFromPEM([]byte(opts.withCertificate))
- if !ok {
- return nil, fmt.Errorf("%s: could not append CA certificate: %w", op, ErrUnknown)
+ for _, c := range opts.withCertificates {
+ ok := caPool.AppendCertsFromPEM([]byte(c))
+ if !ok {
+ return nil, fmt.Errorf("%s: could not append CA certificate: %w", op, ErrUnknown)
+ }
}
tlsConfig.RootCAs = caPool
}
@@ -709,43 +862,61 @@ func getTLSConfig(host string, opt ...Option) (*tls.Config, error) {
return tlsConfig, nil
}
-// EscapeValue will properly escape the input string as an ldap value
-func EscapeValue(input string) string {
+// escapeValue will properly escape the input string as an ldap value
+// rfc4514 states the following must be escaped:
+// - leading space or hash
+// - trailing space
+// - special characters '"', '+', ',', ';', '<', '>', '\\'
+// - hex
+func escapeValue(input string) string {
+ const op = "ldap.EscapeValue"
if input == "" {
return ""
}
- // RFC4514 forbids un-escaped:
- // - leading space or hash
- // - trailing space
- // - special characters '"', '+', ',', ';', '<', '>', '\\'
- // - null
- for i := 0; i < len(input); i++ {
- escaped := false
- if input[i] == '\\' {
- i++
- escaped = true
- }
- switch input[i] {
- case '"', '+', ',', ';', '<', '>', '\\':
- if !escaped {
- input = input[0:i] + "\\" + input[i:]
- i++
- }
+ buf := bytes.Buffer{}
+
+ escFn := func(c byte) {
+ buf.WriteByte('\\')
+ buf.WriteByte(c)
+ }
+
+ inputLen := len(input)
+ for i := 0; i < inputLen; i++ {
+ char := input[i]
+ switch {
+ case i == 0 && char == ' ' || char == '#':
+ // leading space or hash.
+ escFn(char)
continue
- }
- if escaped {
- input = input[0:i] + "\\" + input[i:]
- i++
+ case i == inputLen-1 && char == ' ':
+ // trailing space.
+ escFn(char)
+ continue
+ case specialChar(char):
+ // special characters '"', '+', ',', ';', '<', '>', '\\'
+ escFn(char)
+ continue
+ case char < ' ' || char > '~':
+ // anything that's not between the ascii space and tilde must be hex
+ buf.WriteByte('\\')
+ buf.WriteString(hex.EncodeToString([]byte{char}))
+ continue
+ default:
+ // everything remaining, doesn't need to be escaped
+ buf.WriteByte(char)
}
}
- if input[0] == ' ' || input[0] == '#' {
- input = "\\" + input
- }
- if input[len(input)-1] == ' ' {
- input = input[0:len(input)-1] + "\\ "
+ return buf.String()
+}
+
+func specialChar(char byte) bool {
+ switch char {
+ case '"', '+', ',', ';', '<', '>', '\\':
+ return true
+ default:
+ return false
}
- return input
}
func EscapeFilter(filter string) string {
diff --git a/ldap/client_exported_test.go b/ldap/client_exported_test.go
index e487b6f..8304f73 100644
--- a/ldap/client_exported_test.go
+++ b/ldap/client_exported_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap_test
import (
@@ -44,29 +47,40 @@ func TestClient_Authenticate(t *testing.T) {
testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}),
testdirectory.WithMembersOf(t, "admin"))...,
)
+ // add some attributes that we always want to filter out of an AuthResult,
+ // so if we ever start seeing tests fail because of them; we know that we've
+ // messed up the default filtering
+ for _, u := range users {
+ u.Attributes = append(u.Attributes,
+ gldap.NewEntryAttribute(ldap.DefaultADUserPasswordAttribute, []string{"password"}),
+ gldap.NewEntryAttribute(ldap.DefaultOpenLDAPUserPasswordAttribute, []string{"password"}),
+ )
+ }
td.SetUsers(users...)
td.SetGroups(groups...)
td.SetTokenGroups(tokenGroups)
tests := []struct {
- name string
- username string
- password string
- clientConfig *ldap.ClientConfig
- opts []ldap.Option
- wantGroups []string
- wantErr bool
- wantErrIs error
- wantErrContains string
+ name string
+ username string
+ password string
+ clientConfig *ldap.ClientConfig
+ opts []ldap.Option
+ wantGroups []string
+ wantUserAttributes map[string][]string
+ wantUserDN string
+ wantErr bool
+ wantErrIs error
+ wantErrContains string
}{
{
name: "missing-username",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
},
wantErr: true,
wantErrIs: ldap.ErrInvalidParameter,
@@ -76,11 +90,11 @@ func TestClient_Authenticate(t *testing.T) {
name: "missing-password",
username: "alice",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
},
wantErr: true,
wantErrIs: ldap.ErrInvalidParameter,
@@ -91,11 +105,11 @@ func TestClient_Authenticate(t *testing.T) {
username: "alice",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", 65535)},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", 65535)},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
},
wantErr: true,
wantErrContains: "failed to connect",
@@ -105,11 +119,11 @@ func TestClient_Authenticate(t *testing.T) {
username: "invalid-name",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
},
wantErr: true,
wantErrContains: "discovery of user bind DN failed",
@@ -119,26 +133,116 @@ func TestClient_Authenticate(t *testing.T) {
username: "alice",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
},
+ {
+ name: "success-with-user-attributes",
+ username: "alice",
+ password: "password",
+ clientConfig: &ldap.ClientConfig{
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ ExcludedUserAttributes: []string{"password", "memberof"},
+ },
+ opts: []ldap.Option{ldap.WithUserAttributes()},
+ wantUserAttributes: map[string][]string{
+ "email": {"alice@example.com"},
+ "name": {"alice"},
+ "tokenGroups": {"\x01\x00\x00\x00\x00\x00\x00\x01"},
+ },
+ wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
+ },
+ {
+ name: "success-include-user-attributes",
+ username: "alice",
+ password: "password",
+ clientConfig: &ldap.ClientConfig{
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ ExcludedUserAttributes: []string{"password", "memberof"},
+ IncludeUserAttributes: true,
+ },
+ wantUserAttributes: map[string][]string{
+ "email": {"alice@example.com"},
+ "name": {"alice"},
+ "tokenGroups": {"\x01\x00\x00\x00\x00\x00\x00\x01"},
+ },
+ wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
+ },
+ {
+ name: "success-include-user-groups",
+ username: "alice",
+ password: "password",
+ clientConfig: &ldap.ClientConfig{
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ IncludeUserGroups: true,
+ },
+ wantGroups: []string{groups[0].DN},
+ },
+ {
+ name: "success-include-user-groups-but-no-groups",
+ username: "bob",
+ password: "password",
+ clientConfig: &ldap.ClientConfig{
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ IncludeUserGroups: true,
+ },
+ wantGroups: []string{},
+ },
+ {
+ name: "success-with-groups-and-user-attributes",
+ username: "alice",
+ password: "password",
+ clientConfig: &ldap.ClientConfig{
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ },
+ opts: []ldap.Option{ldap.WithGroups(), ldap.WithUserAttributes()},
+ wantUserAttributes: map[string][]string{
+ "email": {"alice@example.com"},
+ "memberOf": {"admin"},
+ "name": {"alice"},
+ "password": {"password"},
+ "tokenGroups": {"\x01\x00\x00\x00\x00\x00\x00\x01"},
+ },
+ wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
+ wantGroups: []string{groups[0].DN},
+ },
{
name: "success-with-user-filter",
username: "alice",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
- UserFilter: "({{.UserAttr}}={{.Username}})",
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ UserFilter: "({{.UserAttr}}={{.Username}})",
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
@@ -148,12 +252,12 @@ func TestClient_Authenticate(t *testing.T) {
username: "alice",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
- UserFilter: "({{.BadFilter}}={{.Username}})",
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ UserFilter: "({{.BadFilter}}={{.Username}})",
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
@@ -166,7 +270,7 @@ func TestClient_Authenticate(t *testing.T) {
password: "password",
clientConfig: &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
+ Certificates: []string{td.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
@@ -180,12 +284,12 @@ func TestClient_Authenticate(t *testing.T) {
username: "eve",
password: "password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
- UPNDomain: "example.com",
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
+ UPNDomain: "example.com",
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
@@ -196,26 +300,34 @@ func TestClient_Authenticate(t *testing.T) {
password: "password",
clientConfig: &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
+ Certificates: []string{td.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
BindDN: fmt.Sprintf("%s=%s,%s", testdirectory.DefaultUserAttr, "bob", testdirectory.DefaultUserDN),
BindPassword: "password",
},
- opts: []ldap.Option{ldap.WithGroups()},
+ opts: []ldap.Option{ldap.WithGroups(), ldap.WithUserAttributes()},
wantGroups: []string{groups[0].DN},
+ wantUserAttributes: map[string][]string{
+ "email": {"alice@example.com"},
+ "memberOf": {"admin"},
+ "name": {"alice"},
+ "password": {"password"},
+ "tokenGroups": {"\x01\x00\x00\x00\x00\x00\x00\x01"},
+ },
+ wantUserDN: "cn=alice,ou=people,dc=example,dc=org",
},
{
name: "failed-bind-aka-authentication",
username: "alice",
password: "invalid-password",
clientConfig: &ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
},
opts: []ldap.Option{ldap.WithGroups()},
wantGroups: []string{groups[0].DN},
@@ -228,7 +340,7 @@ func TestClient_Authenticate(t *testing.T) {
password: "password",
clientConfig: &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
+ Certificates: []string{td.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
@@ -261,6 +373,8 @@ func TestClient_Authenticate(t *testing.T) {
}
require.NoError(err)
require.NotNil(authResult)
+ assert.Equal(tc.wantUserAttributes, authResult.UserAttributes)
+ assert.Equal(tc.wantUserDN, authResult.UserDN)
assert.Equal(tc.wantGroups, authResult.Groups)
})
}
@@ -268,7 +382,7 @@ func TestClient_Authenticate(t *testing.T) {
assert, require := assert.New(t), require.New(t)
client, err := ldap.NewClient(testCtx, &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
+ Certificates: []string{td.Cert()},
AllowEmptyPasswordBinds: true,
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
@@ -292,7 +406,7 @@ func TestClient_Authenticate(t *testing.T) {
td2.SetTokenGroups(tokenGroups)
client, err := ldap.NewClient(testCtx, &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td2.Port())},
- Certificate: td2.Cert(),
+ Certificates: []string{td2.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
diff --git a/ldap/client_test.go b/ldap/client_test.go
index 463e345..b85c7e5 100644
--- a/ldap/client_test.go
+++ b/ldap/client_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap
import (
@@ -13,6 +16,72 @@ import (
"github.com/stretchr/testify/require"
)
+func TestClient_renderUserSearchFilter(t *testing.T) {
+ t.Parallel()
+ // just ensure that rendered filters are properly escaped
+ testCtx := context.Background()
+ tests := []struct {
+ name string
+ conf *ClientConfig
+ userName string
+ want string
+ errContains string
+ }{
+ {
+ name: "valid-default",
+ userName: "alice",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ },
+ want: "(cn=alice)",
+ },
+ {
+ name: "escaped-malicious-filter",
+ userName: "foo@example.com)((((((((((((((((((((((((((((((((((((((userPrincipalName=foo",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ UPNDomain: "example.com",
+ UserFilter: "(&({{.UserAttr}}={{.Username}})({{.UserAttr}}=admin@example.com))",
+ },
+ want: "(&(userPrincipalName=foo@example.com\\29\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28\\28userPrincipalName=foo@example.com)(userPrincipalName=admin@example.com))",
+ },
+ {
+ name: "bad-filter-unclosed-action",
+ userName: "alice",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ UserFilter: "hello{{range",
+ },
+ errContains: "search failed due to template compilation error",
+ },
+ {
+ name: "missing-username",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ },
+ errContains: "missing username",
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ assert, require := assert.New(t), require.New(t)
+ c, err := NewClient(testCtx, tc.conf)
+ require.NoError(err)
+
+ f, err := c.renderUserSearchFilter(tc.userName)
+ if tc.errContains != "" {
+ require.Error(err)
+ assert.ErrorContains(err, tc.errContains)
+ return
+ }
+ require.NoError(err)
+ assert.NotEmpty(f)
+ assert.Equal(tc.want, f)
+ })
+ }
+
+}
+
func TestClient_NewClient(t *testing.T) {
t.Parallel()
testCtx := context.Background()
@@ -24,6 +93,7 @@ func TestClient_NewClient(t *testing.T) {
tests := []struct {
name string
conf *ClientConfig
+ want *Client
wantErr bool
wantErrIs error
wantErrContains string
@@ -61,6 +131,23 @@ func TestClient_NewClient(t *testing.T) {
wantErrIs: ErrInvalidParameter,
wantErrContains: "invalid 'tls_min_version' in config",
},
+ {
+ name: "valid-tls-max",
+ conf: &ClientConfig{
+ TLSMaxVersion: "tls13",
+ },
+ want: &Client{
+ conf: &ClientConfig{
+ URLs: []string{"ldaps://127.0.0.1:686"},
+ DerefAliases: "never",
+ GroupFilter: "(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))",
+ GroupAttr: "cn",
+ UserAttr: "cn",
+ TLSMinVersion: "tls12",
+ TLSMaxVersion: "tls13",
+ },
+ },
+ },
{
name: "invalid-tls-max",
conf: &ClientConfig{
@@ -83,7 +170,7 @@ func TestClient_NewClient(t *testing.T) {
{
name: "invalid-cert",
conf: &ClientConfig{
- Certificate: "invalid-cert",
+ Certificates: []string{"invalid-cert"},
},
wantErr: true,
wantErrIs: ErrInvalidParameter,
@@ -104,13 +191,70 @@ func TestClient_NewClient(t *testing.T) {
URLs: []string{"localhost"},
TLSMinVersion: "tls12",
TLSMaxVersion: "tls13",
- Certificate: td.Cert(),
+ Certificates: []string{td.Cert()},
ClientTLSKey: td.ClientKey(),
ClientTLSCert: td.ClientCert(),
},
+ want: &Client{
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ DerefAliases: "never",
+ GroupFilter: "(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))",
+ GroupAttr: "cn",
+ UserAttr: "cn",
+ TLSMinVersion: "tls12",
+ TLSMaxVersion: "tls13",
+ Certificates: []string{td.Cert()},
+ ClientTLSKey: td.ClientKey(),
+ ClientTLSCert: td.ClientCert(),
+ },
+ },
+ },
+ {
+ name: "invalid-deref-aliases",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ DerefAliases: "invalid",
+ },
+ wantErr: true,
+ wantErrContains: `invalid dereference_aliases "invalid"`,
+ },
+ {
+ name: "default-deref-aliases",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ },
+ want: &Client{
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ DerefAliases: "never",
+ GroupFilter: "(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))",
+ GroupAttr: "cn",
+ UserAttr: "cn",
+ TLSMinVersion: "tls12",
+ TLSMaxVersion: "tls13",
+ },
+ },
+ },
+ {
+ name: "valid-deref-aliases",
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ DerefAliases: "always",
+ },
+ want: &Client{
+ conf: &ClientConfig{
+ URLs: []string{"localhost"},
+ DerefAliases: "always",
+ GroupFilter: "(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))",
+ GroupAttr: "cn",
+ UserAttr: "cn",
+ TLSMinVersion: "tls12",
+ TLSMaxVersion: "tls13",
+ },
+ },
},
}
-
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
@@ -134,8 +278,9 @@ func TestClient_NewClient(t *testing.T) {
assert.Equal(DefaultGroupFilter, c.conf.GroupFilter)
assert.Equal(DefaultTLSMinVersion, c.conf.TLSMinVersion)
assert.Equal(DefaultTLSMaxVersion, c.conf.TLSMaxVersion)
- } else {
-
+ }
+ if tc.want != nil {
+ assert.Equal(tc.want, c)
}
})
}
@@ -198,6 +343,26 @@ func TestClient_connect(t *testing.T) {
wantErr: true,
wantErrContains: "invalid LDAP scheme in url",
},
+ {
+ name: "error-ldap-timeout",
+ conf: &ClientConfig{
+ RequestTimeout: 1,
+ // invalid-port on ldap (non-tls) scheme
+ URLs: []string{fmt.Sprintf("ldap://ldap.forumsys.com:%d", freePort(t))},
+ },
+ wantErr: true,
+ wantErrContains: "i/o timeout",
+ },
+ {
+ name: "error-ldaps-timeout",
+ conf: &ClientConfig{
+ // invalid-port on ldaps (tls) scheme
+ RequestTimeout: 1,
+ URLs: []string{fmt.Sprintf("ldaps://ldap.forumsys.com:%d", freePort(t))},
+ },
+ wantErr: true,
+ wantErrContains: "i/o timeout",
+ },
{
name: "error-connecting",
conf: &ClientConfig{
@@ -210,14 +375,14 @@ func TestClient_connect(t *testing.T) {
{
name: "tls",
conf: &ClientConfig{
- Certificate: tdTLS.Cert(),
- URLs: []string{fmt.Sprintf("ldaps://localhost:%d", tdTLS.Port())},
+ Certificates: []string{tdTLS.Cert()},
+ URLs: []string{fmt.Sprintf("ldaps://localhost:%d", tdTLS.Port())},
},
},
{
name: "tls-with-all-opts",
conf: &ClientConfig{
- Certificate: tdTLS.Cert(),
+ Certificates: []string{tdTLS.Cert()},
URLs: []string{fmt.Sprintf("ldaps://localhost:%d", tdTLS.Port())},
RequestTimeout: 2,
},
@@ -228,16 +393,16 @@ func TestClient_connect(t *testing.T) {
{
name: "non-tls",
conf: &ClientConfig{
- Certificate: tdTLS.Cert(),
- URLs: []string{fmt.Sprintf("ldap://localhost:%d", tdNonTLS.Port())},
+ Certificates: []string{tdTLS.Cert()},
+ URLs: []string{fmt.Sprintf("ldap://localhost:%d", tdNonTLS.Port())},
},
},
{
name: "start-tls",
conf: &ClientConfig{
- Certificate: tdNonTLS.Cert(),
- URLs: []string{fmt.Sprintf("ldap://localhost:%d", tdNonTLS.Port())},
- StartTLS: true,
+ Certificates: []string{tdNonTLS.Cert()},
+ URLs: []string{fmt.Sprintf("ldap://localhost:%d", tdNonTLS.Port())},
+ StartTLS: true,
},
},
}
@@ -276,9 +441,8 @@ func TestClient_connect(t *testing.T) {
Name: "test-logger",
Level: hclog.Error,
})
- ln, err := net.Listen("tcp", ":"+"389")
- ln.Close()
- if err == nil {
+ if ln, err := net.Listen("tcp", ":"+"389"); err == nil {
+ ln.Close()
_ = testdirectory.Start(t, testdirectory.WithNoTLS(t), testdirectory.WithLogger(t, logger), testdirectory.WithPort(t, 389))
c, err := NewClient(testCtx, &ClientConfig{
URLs: []string{"ldap://127.0.0.1"},
@@ -287,6 +451,8 @@ func TestClient_connect(t *testing.T) {
err = c.connect(testCtx)
defer func() { c.Close(testCtx) }()
assert.NoError(err)
+ } else {
+ t.Logf("warning: failed to listen on port 389, err=%s", err)
}
})
}
@@ -362,3 +528,15 @@ MIICUTCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADBXMQswCQYDVQQGEwJDTjEL
})
}
}
+
+func freePort(t *testing.T) int {
+ t.Helper()
+ require := require.New(t)
+ addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+ require.NoError(err)
+
+ l, err := net.ListenTCP("tcp", addr)
+ require.NoError(err)
+ defer l.Close()
+ return l.Addr().(*net.TCPAddr).Port
+}
diff --git a/ldap/config.go b/ldap/config.go
index 1bc248d..97bddca 100644
--- a/ldap/config.go
+++ b/ldap/config.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap
import (
@@ -5,11 +8,38 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
+ "strings"
+ "github.com/go-ldap/ldap/v3"
"github.com/hashicorp/go-secure-stdlib/tlsutil"
)
+var derefAliasMap = map[string]int{
+ "never": ldap.NeverDerefAliases,
+ "finding": ldap.DerefFindingBaseObj,
+ "searching": ldap.DerefInSearching,
+ "always": ldap.DerefAlways,
+}
+
+func validateDerefAlias(deref string) (string, error) {
+ const op = "ldap.validateDerefAlias"
+ lowerDeref := strings.ToLower(deref)
+ _, found := derefAliasMap[lowerDeref]
+ switch {
+ case found:
+ return lowerDeref, nil
+ case deref == "":
+ return DefaultDerefAliases, nil
+ default:
+ return "", fmt.Errorf("%s: invalid dereference_aliases %q: %w", op, deref, ErrInvalidParameter)
+ }
+}
+
const (
+ // DefaultTimeout is the timeout value used for both dialing and requests to
+ // the LDAP server
+ DefaultTimeout = 60
+
// DefaultURL for the ClientConfig.URLs
DefaultURL = "ldaps://127.0.0.1:686"
@@ -28,7 +58,18 @@ const (
DefaultTLSMinVersion = "tls12"
// DefaultTLSMaxVersion for the ClientConfig.TLSMaxVersion
- DefaultTLSMaxVersion = "tls12"
+ DefaultTLSMaxVersion = "tls13"
+
+ // DefaultOpenLDAPUserPasswordAttribute defines the attribute name for the
+ // openLDAP default password attribute which will always be excluded
+ DefaultOpenLDAPUserPasswordAttribute = "userPassword"
+
+ // DefaultADUserPasswordAttribute defines the attribute name for the
+ // AD default password attribute which will always be excluded
+ DefaultADUserPasswordAttribute = "unicodePwd"
+
+ // DefaultDerefAliases defines the default for dereferencing aliases
+ DefaultDerefAliases = "never"
)
type ClientConfig struct {
@@ -60,7 +101,7 @@ type ClientConfig struct {
GroupFilter string `json:"groupfilter"`
// GroupAttr is the attribute which identifies group members in entries
- // returned from GroupFilter queries. Examples: for groupfilter queries
+ // returned from GroupFilter queries. Examples: for groupattr queries
// returning group objects, use: cn. For queries returning user objects,
// use: memberOf.
// Default: cn
@@ -85,9 +126,9 @@ type ClientConfig struct {
// either the cn in ActiveDirectory or uid in openLDAP (default: cn)
UserAttr string `json:"userattr"`
- // Certificate to use verify the identity of the directory service and is a
- // PEM encoded x509 (optional)
- Certificate string `json:"certificate"`
+ // Certificates to use verify the identity of the directory service and is a
+ // set of PEM encoded x509 (optional)
+ Certificates []string `json:"certificates"`
// ClientTLSCert is the client certificate used with the ClientTLSKey to
// authenticate the client to the directory service. It must be PEM encoded
@@ -137,10 +178,45 @@ type ClientConfig struct {
// security groups including nested ones.",
UseTokenGroups bool `json:"use_token_groups"`
- // RequestTimeout in seconds, for the connection when making requests
- // against the server before returning back an error.
+ // RequestTimeout in seconds is used when dialing to establish the
+ // connection and when making requests against the server via a connection
+ // before returning back an error. If not set, then the DefaultTimeout is
+ // used.
RequestTimeout int `json:"request_timeout"`
+ // IncludeUserAttributes optionally specifies that the authenticating user's
+ // DN and attributes be included an authentication AuthResult.
+ //
+ // Note: the default password attribute for both openLDAP (userPassword) and
+ // AD (unicodePwd) will always be excluded.
+ IncludeUserAttributes bool
+
+ // ExcludedUserAttributes optionally defines a set of user attributes to be
+ // excluded when an authenticating user's attributes are included in an
+ // AuthResult (see: Config.IncludeUserAttributes or the WithUserAttributes()
+ // option).
+ //
+ // Note: the default password attribute for both openLDAP (userPassword) and
+ // AD (unicodePwd) will always be excluded.
+ ExcludedUserAttributes []string
+
+ // IncludeUserGroups optionally specifies that the authenticating user's
+ // group membership be included an authentication AuthResult.
+ IncludeUserGroups bool
+
+ // MaximumPageSize optionally specifies a maximum ldap search result size to
+ // use when retrieving the authenticated user's group memberships. This can
+ // be used to avoid reaching the LDAP server's max result size.
+ MaximumPageSize int `json:"max_page_size"`
+
+ // DerefAliases will control how aliases are dereferenced when
+ // performing the search. Possible values are: never, finding, searching,
+ // and always. If unset, a default of "never" is used. When set to
+ // "finding", it will only dereference aliases during name resolution of the
+ // base. When set to "searching", it will dereference aliases after name
+ // resolution.
+ DerefAliases string `json:"dereference_aliases"`
+
// DeprecatedVaultPre111GroupCNBehavior: if true, group searching reverts to
// the pre 1.1.1 Vault behavior.
// see: https://www.vaultproject.io/docs/upgrading/upgrade-to-1.1.1
@@ -168,9 +244,11 @@ func (c *ClientConfig) validate() error {
if tlsMaxVersion < tlsMinVersion {
return fmt.Errorf("%s: 'tls_max_version' must be greater than or equal to 'tls_min_version': %w", op, ErrInvalidParameter)
}
- if c.Certificate != "" {
- if err := validateCertificate([]byte(c.Certificate)); err != nil {
- return fmt.Errorf("%s: failed to parse server tls cert: %w", op, err)
+ if c.Certificates != nil {
+ for _, cert := range c.Certificates {
+ if err := validateCertificate([]byte(cert)); err != nil {
+ return fmt.Errorf("%s: failed to parse server tls cert: %w", op, err)
+ }
}
}
if (c.ClientTLSCert != "" && c.ClientTLSKey == "") ||
@@ -182,6 +260,11 @@ func (c *ClientConfig) validate() error {
return fmt.Errorf("%s: failed to parse client X509 key pair: %w", op, err)
}
}
+ var err error
+ c.DerefAliases, err = validateDerefAlias(c.DerefAliases)
+ if err != nil {
+ return fmt.Errorf("%s: %w", op, err)
+ }
return nil
}
diff --git a/ldap/conn_test.go b/ldap/conn_test.go
index 930ae14..ad73923 100644
--- a/ldap/conn_test.go
+++ b/ldap/conn_test.go
@@ -1,21 +1,44 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap
-import "testing"
+import (
+ "testing"
+)
-func Test_EscapeValue(t *testing.T) {
- testcases := map[string]string{
- "#test": "\\#test",
- "test,hello": "test\\,hello",
- "test,hel+lo": "test\\,hel\\+lo",
- "test\\hello": "test\\\\hello",
- " test ": "\\ test \\ ",
- "": "",
- }
+var testcases = map[string]string{
+ "#test": "\\#test",
+ "test,hello": "test\\,hello",
+ "test,hel+lo": "test\\,hel\\+lo",
+ "test\\hello": "test\\\\hello",
+ " test ": "\\ test \\ ",
+ "": "",
+ `\`: `\\`,
+ "trailing\000": `trailing\00`,
+ "mid\000dle": `mid\00dle`,
+ "\000": `\00`,
+ "multiple\000\000": `multiple\00\00`,
+ "backlash-before-null\\\000": `backlash-before-null\\\00`,
+ "trailing\\": `trailing\\`,
+ "double-escaping\\>": `double-escaping\\\>`,
+}
+func Test_EscapeValue(t *testing.T) {
for test, answer := range testcases {
- res := EscapeValue(test)
+ res := escapeValue(test)
if res != answer {
- t.Errorf("Failed to escape %s: %s != %s\n", test, res, answer)
+ t.Errorf("Failed to escape %q: %q != %q\n", test, res, answer)
}
}
}
+
+// Fuzz_EscapeValue is only focused on finding panics
+func Fuzz_EscapeValue(f *testing.F) {
+ for tc, _ := range testcases {
+ f.Add(tc)
+ }
+ f.Fuzz(func(t *testing.T, s string) {
+ _ = escapeValue(s)
+ })
+}
diff --git a/ldap/error.go b/ldap/error.go
index f5336a8..5fa149c 100644
--- a/ldap/error.go
+++ b/ldap/error.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap
import "errors"
diff --git a/ldap/examples/cli/go.mod b/ldap/examples/cli/go.mod
index f4ad090..378098d 100644
--- a/ldap/examples/cli/go.mod
+++ b/ldap/examples/cli/go.mod
@@ -1,34 +1,35 @@
module github.com/hashicorp/cap/ldap/examples/cli
-go 1.17
+go 1.20
require (
- github.com/hashicorp/cap/ldap v0.0.0-20220408131637-6d654cde3216
- github.com/hashicorp/go-hclog v1.1.0
+ github.com/hashicorp/cap/ldap v0.0.0-20230221101954-1a2212073391
+ github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-secure-stdlib/password v0.1.1
- github.com/jimlambrt/gldap v0.1.1
+ github.com/jimlambrt/gldap v0.1.4
)
require (
- github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
+ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
+ github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/fatih/color v1.7.0 // indirect
+ github.com/fatih/color v1.14.1 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
- github.com/go-ldap/ldap/v3 v3.4.3 // indirect
+ github.com/go-ldap/ldap/v3 v3.4.4 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/go-secure-stdlib/parseutil v0.1.4 // indirect
+ github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
- github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 // indirect
+ github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
- github.com/mattn/go-colorable v0.1.4 // indirect
- github.com/mattn/go-isatty v0.0.10 // indirect
- github.com/mitchellh/mapstructure v1.4.3 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
- github.com/stretchr/testify v1.7.0 // indirect
- golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
- golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 // indirect
- golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
- gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+ github.com/stretchr/testify v1.8.1 // indirect
+ golang.org/x/crypto v0.6.0 // indirect
+ golang.org/x/sys v0.5.0 // indirect
+ golang.org/x/term v0.5.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/ldap/examples/cli/go.sum b/ldap/examples/cli/go.sum
index e6c0c68..41999b4 100644
--- a/ldap/examples/cli/go.sum
+++ b/ldap/examples/cli/go.sum
@@ -1,52 +1,61 @@
-github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ=
-github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
+github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
-github.com/go-ldap/ldap/v3 v3.4.3 h1:JCKUtJPIcyOuG7ctGabLKMgIlKnGumD/iGjuWeEruDI=
-github.com/go-ldap/ldap/v3 v3.4.3/go.mod h1:7LdHfVt6iIOESVEe3Bs4Jp2sHEKgDeduAhgM1/f9qmo=
-github.com/hashicorp/cap/ldap v0.0.0-20220408131637-6d654cde3216 h1:dLuZYSsWXHumfFoVY27aEUffI7zVh4WSQSCHTTWSVNs=
-github.com/hashicorp/cap/ldap v0.0.0-20220408131637-6d654cde3216/go.mod h1:raCUTLtdFrAMx/rsQNeYoWDrsfFcqQuTK1vJ5tYd3qA=
+github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
+github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
+github.com/hashicorp/cap/ldap v0.0.0-20230221101954-1a2212073391 h1:vsM7arWbvvSY+igm+2bZYwVNqOJGVAPj2ylcvUrr1x0=
+github.com/hashicorp/cap/ldap v0.0.0-20230221101954-1a2212073391/go.mod h1:9rAvcOfZF5fAYoN4GRtEI5w0F9Uj/oDAqMndkoRnPrI=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-hclog v1.1.0 h1:QsGcniKx5/LuX2eYoeL+Np3UKYPNaN7YKpTh29h8rbw=
-github.com/hashicorp/go-hclog v1.1.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
+github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
-github.com/hashicorp/go-secure-stdlib/parseutil v0.1.4 h1:hrIH/qrOTHfG9a1Jz6Z2jQf7Xe77AaD464W1fCFLwPQ=
-github.com/hashicorp/go-secure-stdlib/parseutil v0.1.4/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60=
github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
-github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8=
-github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
+github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 h1:phcbL8urUzF/kxA/Oj6awENaRwfWsjP59GW7u2qlDyY=
+github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
-github.com/jimlambrt/gldap v0.1.1 h1:TKkPrI/32H8vIwzw29wfGpBEU1AH2W3CFxLTz58Y2oc=
-github.com/jimlambrt/gldap v0.1.1/go.mod h1:sKo9VprcJwZRj7OoE7p8YLaPEeNxw3WIEY42NS/iV7E=
+github.com/jimlambrt/gldap v0.1.4 h1:PoB5u4ND0E+6W99JtQJvcjGFw+iKi3Gx3M60oOJBOqE=
+github.com/jimlambrt/gldap v0.1.4/go.mod h1:ia/l4Jhm+tdupLvZe7tRCbpv+HyXr1B5QFirsewfWEA=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
-github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
-github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -54,29 +63,40 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
-golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 h1:A0Qkn7Z/n8zC1xd9LTw17AiKlBRK64tw3ejWQiEqca0=
-golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/ldap/examples/cli/main.go b/ldap/examples/cli/main.go
index 58c50e4..61b5e73 100644
--- a/ldap/examples/cli/main.go
+++ b/ldap/examples/cli/main.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
@@ -27,11 +30,11 @@ func main() {
td := startTestDirectory()
defer func() { td.Stop() }()
clientConfig = ldap.ClientConfig{
- URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
- Certificate: td.Cert(),
- DiscoverDN: true,
- UserDN: testdirectory.DefaultUserDN,
- GroupDN: testdirectory.DefaultGroupDN,
+ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
+ Certificates: []string{td.Cert()},
+ DiscoverDN: true,
+ UserDN: testdirectory.DefaultUserDN,
+ GroupDN: testdirectory.DefaultGroupDN,
}
} else {
configFile, err := os.Open(*cfgFilename)
diff --git a/ldap/examples/cli/start-local-ldap.sh b/ldap/examples/cli/start-local-ldap.sh
index e15e99c..864a743 100755
--- a/ldap/examples/cli/start-local-ldap.sh
+++ b/ldap/examples/cli/start-local-ldap.sh
@@ -1,4 +1,7 @@
#!/bin/bash
+# Copyright (c) HashiCorp, Inc.
+# SPDX-License-Identifier: MPL-2.0
+
# this is just part of an example way to use your own directory with the cli.
#
diff --git a/ldap/go.mod b/ldap/go.mod
index 2091f70..13fc968 100644
--- a/ldap/go.mod
+++ b/ldap/go.mod
@@ -1,31 +1,33 @@
module github.com/hashicorp/cap/ldap
-go 1.17
+go 1.20
require (
- github.com/go-ldap/ldap/v3 v3.4.3
- github.com/hashicorp/go-hclog v1.1.0
+ github.com/go-ldap/ldap/v3 v3.4.6
+ github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-multierror v1.1.1
- github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1
- github.com/jimlambrt/gldap v0.1.1
- github.com/stretchr/testify v1.7.0
+ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2
+ github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2
+ github.com/jimlambrt/gldap v0.1.4
+ github.com/stretchr/testify v1.8.1
)
require (
- github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
+ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
+ github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/fatih/color v1.7.0 // indirect
- github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
+ github.com/fatih/color v1.14.1 // indirect
+ github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
+ github.com/google/uuid v1.3.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/hashicorp/go-secure-stdlib/parseutil v0.1.4 // indirect
- github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
+ github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
- github.com/mattn/go-colorable v0.1.4 // indirect
- github.com/mattn/go-isatty v0.0.10 // indirect
- github.com/mitchellh/mapstructure v1.4.3 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
- golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
- golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 // indirect
- gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+ golang.org/x/crypto v0.13.0 // indirect
+ golang.org/x/sys v0.12.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/ldap/go.sum b/ldap/go.sum
index 51809dc..e571610 100644
--- a/ldap/go.sum
+++ b/ldap/go.sum
@@ -1,48 +1,60 @@
-github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ=
-github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
+github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
-github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
-github.com/go-ldap/ldap/v3 v3.4.3 h1:JCKUtJPIcyOuG7ctGabLKMgIlKnGumD/iGjuWeEruDI=
-github.com/go-ldap/ldap/v3 v3.4.3/go.mod h1:7LdHfVt6iIOESVEe3Bs4Jp2sHEKgDeduAhgM1/f9qmo=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
+github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
+github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
+github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
+github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
+github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
+github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-hclog v1.1.0 h1:QsGcniKx5/LuX2eYoeL+Np3UKYPNaN7YKpTh29h8rbw=
-github.com/hashicorp/go-hclog v1.1.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
+github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
-github.com/hashicorp/go-secure-stdlib/parseutil v0.1.4 h1:hrIH/qrOTHfG9a1Jz6Z2jQf7Xe77AaD464W1fCFLwPQ=
-github.com/hashicorp/go-secure-stdlib/parseutil v0.1.4/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
-github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8=
-github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
+github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2 h1:phcbL8urUzF/kxA/Oj6awENaRwfWsjP59GW7u2qlDyY=
+github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.2/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
-github.com/jimlambrt/gldap v0.1.1 h1:TKkPrI/32H8vIwzw29wfGpBEU1AH2W3CFxLTz58Y2oc=
-github.com/jimlambrt/gldap v0.1.1/go.mod h1:sKo9VprcJwZRj7OoE7p8YLaPEeNxw3WIEY42NS/iV7E=
+github.com/jimlambrt/gldap v0.1.4 h1:PoB5u4ND0E+6W99JtQJvcjGFw+iKi3Gx3M60oOJBOqE=
+github.com/jimlambrt/gldap v0.1.4/go.mod h1:ia/l4Jhm+tdupLvZe7tRCbpv+HyXr1B5QFirsewfWEA=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
-github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
-github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -50,24 +62,63 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
-golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827 h1:A0Qkn7Z/n8zC1xd9LTw17AiKlBRK64tw3ejWQiEqca0=
-golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/ldap/options.go b/ldap/options.go
index 7f10630..7a2a79d 100644
--- a/ldap/options.go
+++ b/ldap/options.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package ldap
// Option defines a common functional options type which can be used in a
@@ -5,14 +8,15 @@ package ldap
type Option func(interface{})
type configOptions struct {
- withURLs []string
- withInsecureTLS bool
- withTLSMinVersion string
- withTLSMaxVersion string
- withCertificate string
- withClientTLSCert string
- withClientTLSKey string
- withGroups bool
+ withURLs []string
+ withInsecureTLS bool
+ withTLSMinVersion string
+ withTLSMaxVersion string
+ withCertificates []string
+ withClientTLSCert string
+ withClientTLSKey string
+ withGroups bool
+ withUserAttributes bool
}
func configDefaults() configOptions {
@@ -58,6 +62,19 @@ func WithGroups() Option {
}
}
+// WithUserAttributes requests that authenticating user's DN and attributes be
+// included in the response. Note: the default password attribute for both
+// openLDAP (userPassword) and AD (unicodePwd) will always be excluded. To
+// exclude additional attributes see: Config.ExcludedUserAttributes.
+func WithUserAttributes() Option {
+ return func(o interface{}) {
+ switch v := o.(type) {
+ case *configOptions:
+ v.withUserAttributes = true
+ }
+ }
+}
+
func withTLSMinVersion(version string) Option {
return func(o interface{}) {
switch v := o.(type) {
@@ -85,11 +102,11 @@ func withInsecureTLS(withInsecure bool) Option {
}
}
-func withCertificate(cert string) Option {
+func withCertificates(cert ...string) Option {
return func(o interface{}) {
switch v := o.(type) {
case *configOptions:
- v.withCertificate = cert
+ v.withCertificates = cert
}
}
}
diff --git a/oidc/access_token.go b/oidc/access_token.go
index fd6d6e4..9375983 100644
--- a/oidc/access_token.go
+++ b/oidc/access_token.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import "encoding/json"
diff --git a/oidc/access_token_test.go b/oidc/access_token_test.go
index 3128fc9..bc2b734 100644
--- a/oidc/access_token_test.go
+++ b/oidc/access_token_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/algs.go b/oidc/algs.go
index 224b0b4..7f66cca 100644
--- a/oidc/algs.go
+++ b/oidc/algs.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
// Alg represents asymmetric signing algorithms
diff --git a/oidc/callback/authcode.go b/oidc/callback/authcode.go
index 5badb0b..c10eee4 100644
--- a/oidc/callback/authcode.go
+++ b/oidc/callback/authcode.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/authcode_test.go b/oidc/callback/authcode_test.go
index e394383..f5805ee 100644
--- a/oidc/callback/authcode_test.go
+++ b/oidc/callback/authcode_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/docs.go b/oidc/callback/docs.go
index fa31deb..bba49fe 100644
--- a/oidc/callback/docs.go
+++ b/oidc/callback/docs.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
/*
callback is a package that provides callbacks (in the form of http.HandlerFunc)
for handling OIDC provider responses to authorization code flow (with optional
diff --git a/oidc/callback/docs_test.go b/oidc/callback/docs_test.go
index 663ad0a..93e13b7 100644
--- a/oidc/callback/docs_test.go
+++ b/oidc/callback/docs_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/implicit.go b/oidc/callback/implicit.go
index 7531195..35ba4e2 100644
--- a/oidc/callback/implicit.go
+++ b/oidc/callback/implicit.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/implicit_test.go b/oidc/callback/implicit_test.go
index 0e5b4f5..6aa23af 100644
--- a/oidc/callback/implicit_test.go
+++ b/oidc/callback/implicit_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/request_reader.go b/oidc/callback/request_reader.go
index d866f71..2f41642 100644
--- a/oidc/callback/request_reader.go
+++ b/oidc/callback/request_reader.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/request_reader_test.go b/oidc/callback/request_reader_test.go
index a6597cd..dd30b2e 100644
--- a/oidc/callback/request_reader_test.go
+++ b/oidc/callback/request_reader_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/response_func.go b/oidc/callback/response_func.go
index c4f5399..98bd980 100644
--- a/oidc/callback/response_func.go
+++ b/oidc/callback/response_func.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/callback/testing.go b/oidc/callback/testing.go
index b5a9d10..4269d77 100644
--- a/oidc/callback/testing.go
+++ b/oidc/callback/testing.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package callback
import (
diff --git a/oidc/config.go b/oidc/config.go
index d8bb199..db2f4a6 100644
--- a/oidc/config.go
+++ b/oidc/config.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -90,7 +93,12 @@ type Config struct {
ProviderCA string
// NowFunc is a time func that returns the current time.
- NowFunc func() time.Time
+ NowFunc func() time.Time `json:"-"`
+
+ // ProviderConfig is an optional ProviderConfig that supports creating a
+ // provider that doesn't support OIDC discovery. It's probably better to use
+ // NewProvider(...) with discovery whenever possible.
+ ProviderConfig *ProviderConfig
}
// NewConfig composes a new config for a provider.
@@ -99,7 +107,7 @@ type Config struct {
// regardless of what additional scopes are requested via the WithScopes option
// and duplicate scopes are allowed.
//
-// Supported options: WithProviderCA, WithScopes, WithAudiences, WithNow
+// Supported options: WithProviderCA, WithScopes, WithAudiences, WithNow, WithProviderConfig
func NewConfig(issuer string, clientID string, clientSecret ClientSecret, supported []Alg, allowedRedirectURLs []string, opt ...Option) (*Config, error) {
const op = "NewConfig"
opts := getConfigOpts(opt...)
@@ -113,6 +121,7 @@ func NewConfig(issuer string, clientID string, clientSecret ClientSecret, suppor
Audiences: opts.withAudiences,
NowFunc: opts.withNowFunc,
AllowedRedirectURLs: allowedRedirectURLs,
+ ProviderConfig: opts.withProviderConfig,
}
if err := c.Validate(); err != nil {
return nil, fmt.Errorf("%s: invalid provider config: %w", op, err)
@@ -158,6 +167,16 @@ func (c *Config) Hash() (uint64, error) {
args = append(args, scopes...)
args = append(args, audiences...)
args = append(args, redirects...)
+
+ if c.ProviderConfig != nil {
+ args = append(
+ args,
+ c.ProviderConfig.AuthURL,
+ c.ProviderConfig.JWKSURL,
+ c.ProviderConfig.TokenURL,
+ c.ProviderConfig.UserInfoURL,
+ )
+ }
if h, err = hashStrings(args...); err != nil {
return 0, fmt.Errorf("hashing error: %w", err)
}
@@ -250,6 +269,19 @@ func (c *Config) Validate() error {
return fmt.Errorf("%s: %w", op, ErrInvalidCACert)
}
}
+
+ if c.ProviderConfig != nil {
+ switch {
+ case c.ProviderConfig.AuthURL == "":
+ return fmt.Errorf("%s: missing AuthURL: %w", op, ErrInvalidParameter)
+ case c.ProviderConfig.JWKSURL == "":
+ return fmt.Errorf("%s: missing JWKSURL: %w", op, ErrInvalidParameter)
+ case c.ProviderConfig.TokenURL == "":
+ return fmt.Errorf("%s: missing TokenURL: %w", op, ErrInvalidParameter)
+ case c.ProviderConfig.UserInfoURL == "":
+ return fmt.Errorf("%s: missing UserInfoURL: %w", op, ErrInvalidParameter)
+ }
+ }
return nil
}
@@ -263,10 +295,11 @@ func (c *Config) Now() time.Time {
// configOptions is the set of available options
type configOptions struct {
- withScopes []string
- withAudiences []string
- withProviderCA string
- withNowFunc func() time.Time
+ withScopes []string
+ withAudiences []string
+ withProviderCA string
+ withNowFunc func() time.Time
+ withProviderConfig *ProviderConfig
}
// configDefaults is a handy way to get the defaults at runtime and
@@ -321,3 +354,33 @@ func EncodeCertificates(certs ...*x509.Certificate) (string, error) {
}
return buffer.String(), nil
}
+
+// ProviderConfig supports creating a provider that doesn't support OIDC
+// discovery. It's probably better to use NewProvider(...) with discovery
+// whenever possible.
+type ProviderConfig struct {
+ // AuthURL is the provider's OAuth 2.0 authorization endpoint.
+ AuthURL string
+
+ // TokenURL is the provider's OAuth2.0 token endpoint.
+ TokenURL string
+ // UserInfoURL is the provider's OpenID UserInfo endpoint.
+ //
+ // See: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
+ UserInfoURL string
+
+ // JWKSURL is the provider's OpenID JWKS endpoint (where it publishes the
+ // pub keys.
+ JWKSURL string
+}
+
+// WithProviderConfig provides an optional ProviderConfig which supports
+// creating a provider that doesn't support OIDC discovery. It's probably better
+// to use NewProvider(...) with discovery whenever possible.
+func WithProviderConfig(cfg *ProviderConfig) Option {
+ return func(o interface{}) {
+ if o, ok := o.(*configOptions); ok {
+ o.withProviderConfig = cfg
+ }
+ }
+}
diff --git a/oidc/config_test.go b/oidc/config_test.go
index 80f323d..43f37e5 100644
--- a/oidc/config_test.go
+++ b/oidc/config_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -50,11 +53,12 @@ func TestNewConfig(t *testing.T) {
opt []Option
}
tests := []struct {
- name string
- args args
- want *Config
- wantErr bool
- wantIsErr error
+ name string
+ args args
+ want *Config
+ wantErr bool
+ wantIsErr error
+ wantErrContains string
}{
{
name: "valid-with-all-valid-opts",
@@ -69,6 +73,12 @@ func TestNewConfig(t *testing.T) {
WithScopes("email", "profile"),
WithProviderCA(testCaPem),
WithNow(testNow),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
},
},
want: &Config{
@@ -85,7 +95,89 @@ func TestNewConfig(t *testing.T) {
"http://redirect_url_two",
"http://redirect_url_three",
},
+ ProviderConfig: &ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ },
+ },
+ },
+ {
+ name: "missing-provider-config-auth-url",
+ args: args{
+ issuer: "http://your_issuer/",
+ clientID: "your_client_id",
+ clientSecret: "your_client_secret",
+ supported: []Alg{RS512},
+ opt: []Option{
+ WithProviderConfig(&ProviderConfig{
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ },
+ },
+ wantErr: true,
+ wantIsErr: ErrInvalidParameter,
+ wantErrContains: "missing AuthURL",
+ },
+ {
+ name: "missing-provider-config-jwks-url",
+ args: args{
+ issuer: "http://your_issuer/",
+ clientID: "your_client_id",
+ clientSecret: "your_client_secret",
+ supported: []Alg{RS512},
+ opt: []Option{
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ },
+ },
+ wantErr: true,
+ wantIsErr: ErrInvalidParameter,
+ wantErrContains: "missing JWKSURL",
+ },
+ {
+ name: "missing-provider-config-token-url",
+ args: args{
+ issuer: "http://your_issuer/",
+ clientID: "your_client_id",
+ clientSecret: "your_client_secret",
+ supported: []Alg{RS512},
+ opt: []Option{
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ },
+ },
+ wantErr: true,
+ wantIsErr: ErrInvalidParameter,
+ wantErrContains: "missing TokenURL",
+ },
+ {
+ name: "missing-provider-config-userinfo-url",
+ args: args{
+ issuer: "http://your_issuer/",
+ clientID: "your_client_id",
+ clientSecret: "your_client_secret",
+ supported: []Alg{RS512},
+ opt: []Option{
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ }),
+ },
},
+ wantErr: true,
+ wantIsErr: ErrInvalidParameter,
+ wantErrContains: "missing UserInfoURL",
},
{
name: "valid-empty-redirect",
@@ -210,6 +302,9 @@ func TestNewConfig(t *testing.T) {
if tt.wantErr {
require.Error(err)
assert.Truef(errors.Is(err, tt.wantIsErr), "wanted \"%s\" but got \"%s\"", tt.wantIsErr, err)
+ if tt.wantErrContains != "" {
+ assert.Contains(err.Error(), tt.wantErrContains)
+ }
return
}
require.NoError(err)
@@ -228,7 +323,7 @@ func TestNewConfig(t *testing.T) {
}
func TestConfig_Validate(t *testing.T) {
- // Validate testing is covered by TestNewConfig() but we do have just more
+ // Validate testing is covered by TestNewConfig() but we do have just one
// more test to add here.
t.Parallel()
t.Run("nil-config", func(t *testing.T) {
@@ -353,6 +448,12 @@ func TestConfig_Hash(t *testing.T) {
WithAudiences("alice.com", "bob.com"),
WithProviderCA(pem),
WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
),
c2: newCfg(
"https://www.alice.com",
@@ -363,6 +464,12 @@ func TestConfig_Hash(t *testing.T) {
WithAudiences("bob.com", "alice.com"),
WithProviderCA(pem),
WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
),
wantEqual: true,
},
@@ -583,6 +690,150 @@ func TestConfig_Hash(t *testing.T) {
),
wantEqual: false,
},
+ {
+ name: "diff-provider-config-auth-url",
+ c1: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://diff-auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ c2: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ wantEqual: false,
+ },
+ {
+ name: "diff-provider-config-jwks-url",
+ c1: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://diff-jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ c2: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ wantEqual: false,
+ },
+ {
+ name: "diff-provider-config-token-url",
+ c1: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://diff-token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ c2: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ wantEqual: false,
+ },
+ {
+ name: "diff-provider-config-userinfo-url",
+ c1: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://diff-userinfo-endpoint",
+ }),
+ ),
+ c2: newCfg(
+ "https://www.alice.com",
+ "client-id", "client-secret",
+ []Alg{RS256},
+ []string{"www.alice.com/callback"},
+ WithScopes("email", "profile"),
+ WithAudiences("alice.com", "bob.com"),
+ WithProviderCA(pem),
+ WithNow(time.Now),
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: "https://auth-endpoint",
+ JWKSURL: "https://jwks-endpoint",
+ TokenURL: "https://token-endpoint",
+ UserInfoURL: "https://userinfo-endpoint",
+ }),
+ ),
+ wantEqual: false,
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/oidc/display.go b/oidc/display.go
index b214bbc..897dd34 100644
--- a/oidc/display.go
+++ b/oidc/display.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
// Display is a string value that specifies how the Authorization Server
diff --git a/oidc/docs.go b/oidc/docs.go
index 2689d85..e7edca0 100644
--- a/oidc/docs.go
+++ b/oidc/docs.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
/*
oidc is a package for writing clients that integrate with OIDC Providers using
OIDC flows.
diff --git a/oidc/docs_test.go b/oidc/docs_test.go
index 690ceb6..0e50db0 100644
--- a/oidc/docs_test.go
+++ b/oidc/docs_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc_test
import (
@@ -92,7 +95,32 @@ func ExampleNewConfig() {
fmt.Println(pc)
// Output:
- // &{your_client_id [REDACTED: client secret] [openid] http://your_issuer/ [RS256] [http://your_redirect_url/callback] [] }
+ // &{your_client_id [REDACTED: client secret] [openid] http://your_issuer/ [RS256] [http://your_redirect_url/callback] [] }
+}
+
+func ExampleWithProviderConfig() {
+ // Create a new Config
+ pc, err := oidc.NewConfig(
+ "https://your_issuer/",
+ "your_client_id",
+ "your_client_secret",
+ []oidc.Alg{oidc.RS256},
+ []string{"https://your_redirect_url/callback"},
+ oidc.WithProviderConfig(&oidc.ProviderConfig{
+ AuthURL: "https://your_issuer/authorize",
+ TokenURL: "https://your_issuer/token",
+ JWKSURL: "https://your_issuer/.well-known/jwks.json",
+ UserInfoURL: "https://your_issuer/userinfo",
+ }),
+ )
+ if err != nil {
+ // handle error
+ }
+ val, _ := json.Marshal(pc)
+ fmt.Println(string(val))
+
+ // Output:
+ // {"ClientID":"your_client_id","ClientSecret":"[REDACTED: client secret]","Scopes":["openid"],"Issuer":"https://your_issuer/","SupportedSigningAlgs":["RS256"],"AllowedRedirectURLs":["https://your_redirect_url/callback"],"Audiences":null,"ProviderCA":"","ProviderConfig":{"AuthURL":"https://your_issuer/authorize","TokenURL":"https://your_issuer/token","UserInfoURL":"https://your_issuer/userinfo","JWKSURL":"https://your_issuer/.well-known/jwks.json"}}
}
func ExampleNewProvider() {
diff --git a/oidc/error.go b/oidc/error.go
index 73a8add..fe7249e 100644
--- a/oidc/error.go
+++ b/oidc/error.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/examples/cli/README.md b/oidc/examples/cli/README.md
index 10c0b59..d8129c4 100644
--- a/oidc/examples/cli/README.md
+++ b/oidc/examples/cli/README.md
@@ -29,7 +29,7 @@ the max-age specified in seconds.
```
./cli -max-age
```
-### Require environment variables
+### Required environment variables
(required if not using the built-in Test Provider. see note below on how-to use this option)
* `OIDC_CLIENT_ID`: Your Relying Party client id.
diff --git a/oidc/examples/cli/main.go b/oidc/examples/cli/main.go
index d92eb34..0bba9be 100644
--- a/oidc/examples/cli/main.go
+++ b/oidc/examples/cli/main.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
@@ -12,6 +15,7 @@ import (
"net/http"
"os"
"os/signal"
+ "strconv"
"strings"
"time"
@@ -107,7 +111,22 @@ func main() {
}
oidcPort := os.Getenv("OIDC_PORT")
if oidcPort == "" {
- fmt.Fprintf(os.Stderr, "env OIDC_PORT is empty")
+ oidcPort, err = func() (string, error) {
+ addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+ if err != nil {
+ return "", err
+ }
+
+ l, err := net.ListenTCP("tcp", addr)
+ if err != nil {
+ return "", err
+ }
+ defer l.Close()
+ return strconv.Itoa(l.Addr().(*net.TCPAddr).Port), nil
+ }()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "env OIDC_PORT is empty and error finding a free port: %s", err.Error())
+ }
return
}
diff --git a/oidc/examples/cli/responses.go b/oidc/examples/cli/responses.go
index 8ec519f..89658b9 100644
--- a/oidc/examples/cli/responses.go
+++ b/oidc/examples/cli/responses.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
const successHTML = `
diff --git a/oidc/examples/spa/main.go b/oidc/examples/spa/main.go
index ed67bfb..294513d 100644
--- a/oidc/examples/spa/main.go
+++ b/oidc/examples/spa/main.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
diff --git a/oidc/examples/spa/request_cache.go b/oidc/examples/spa/request_cache.go
index 006a2cc..eb58234 100644
--- a/oidc/examples/spa/request_cache.go
+++ b/oidc/examples/spa/request_cache.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
diff --git a/oidc/examples/spa/route_callback.go b/oidc/examples/spa/route_callback.go
index c1b61eb..e2c5522 100644
--- a/oidc/examples/spa/route_callback.go
+++ b/oidc/examples/spa/route_callback.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
diff --git a/oidc/examples/spa/route_login.go b/oidc/examples/spa/route_login.go
index 57671ca..e4c3468 100644
--- a/oidc/examples/spa/route_login.go
+++ b/oidc/examples/spa/route_login.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
diff --git a/oidc/examples/spa/route_success.go b/oidc/examples/spa/route_success.go
index eed234f..f990482 100644
--- a/oidc/examples/spa/route_success.go
+++ b/oidc/examples/spa/route_success.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package main
import (
diff --git a/oidc/id.go b/oidc/id.go
index 83df046..f25951c 100644
--- a/oidc/id.go
+++ b/oidc/id.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/id_test.go b/oidc/id_test.go
index 51ae66b..bc100a1 100644
--- a/oidc/id_test.go
+++ b/oidc/id_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/id_token.go b/oidc/id_token.go
index edd290f..8bd298a 100644
--- a/oidc/id_token.go
+++ b/oidc/id_token.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -8,7 +11,7 @@ import (
"fmt"
"hash"
- "gopkg.in/square/go-jose.v2"
+ "github.com/go-jose/go-jose/v3"
)
// IDToken is an oidc id_token.
diff --git a/oidc/id_token_test.go b/oidc/id_token_test.go
index 4760f6d..4203d68 100644
--- a/oidc/id_token_test.go
+++ b/oidc/id_token_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/internal/base62/base62.go b/oidc/internal/base62/base62.go
index 57a76d4..9f8c20d 100644
--- a/oidc/internal/base62/base62.go
+++ b/oidc/internal/base62/base62.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
// Package base62 provides utilities for working with base62 strings.
// base62 strings will only contain characters: 0-9, a-z, A-Z
package base62
diff --git a/oidc/internal/base62/base62_test.go b/oidc/internal/base62/base62_test.go
index 4cd4902..915d349 100644
--- a/oidc/internal/base62/base62_test.go
+++ b/oidc/internal/base62/base62_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package base62
import (
diff --git a/oidc/internal/strutils/strutils.go b/oidc/internal/strutils/strutils.go
index 67567bb..91ad03a 100644
--- a/oidc/internal/strutils/strutils.go
+++ b/oidc/internal/strutils/strutils.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package strutils
import "strings"
diff --git a/oidc/internal/strutils/strutils_test.go b/oidc/internal/strutils/strutils_test.go
index 0d3af0c..0f7f96e 100644
--- a/oidc/internal/strutils/strutils_test.go
+++ b/oidc/internal/strutils/strutils_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package strutils
import (
diff --git a/oidc/options.go b/oidc/options.go
index 2a42260..af6060c 100644
--- a/oidc/options.go
+++ b/oidc/options.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -66,7 +69,7 @@ func WithScopes(scopes ...string) Option {
// WithAudiences provides an optional list of audiences.
//
-//Valid for: Config and Request
+// Valid for: Config and Request
func WithAudiences(auds ...string) Option {
return func(o interface{}) {
if len(auds) == 0 {
diff --git a/oidc/options_test.go b/oidc/options_test.go
index 38dafa2..7df8f0b 100644
--- a/oidc/options_test.go
+++ b/oidc/options_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/pkce_verifier.go b/oidc/pkce_verifier.go
index 6e211b0..aa31b53 100644
--- a/oidc/pkce_verifier.go
+++ b/oidc/pkce_verifier.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/pkce_verifier_test.go b/oidc/pkce_verifier_test.go
index d202885..a406a89 100644
--- a/oidc/pkce_verifier_test.go
+++ b/oidc/pkce_verifier_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/prompt.go b/oidc/prompt.go
index 8791e90..f2d9fb0 100644
--- a/oidc/prompt.go
+++ b/oidc/prompt.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
// Prompt is a string values that specifies whether the Authorization Server
diff --git a/oidc/provider.go b/oidc/provider.go
index e2097e4..6f559d5 100644
--- a/oidc/provider.go
+++ b/oidc/provider.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -23,16 +26,17 @@ import (
)
// Provider provides integration with an OIDC provider.
-// It's primary capabilities include:
-// * Kicking off a user authentication via either the authorization code flow
-// (with optional PKCE) or implicit flow via the URL from p.AuthURL(...)
//
-// * The authorization code flow (with optional PKCE) by exchanging an auth
-// code for tokens in p.Exchange(...)
+// It's primary capabilities include:
+// * Kicking off a user authentication via either the authorization code flow
+// (with optional PKCE) or implicit flow via the URL from p.AuthURL(...)
+//
+// * The authorization code flow (with optional PKCE) by exchanging an auth
+// code for tokens in p.Exchange(...)
//
-// * Verifying an id_token issued by a provider with p.VerifyIDToken(...)
+// * Verifying an id_token issued by a provider with p.VerifyIDToken(...)
//
-// * Retrieving a user's OAuth claims with p.UserInfo(...)
+// * Retrieving a user's OAuth claims with p.UserInfo(...)
type Provider struct {
config *Config
provider *oidc.Provider
@@ -82,15 +86,32 @@ func NewProvider(c *Config) (*Provider, error) {
return nil, fmt.Errorf("%s: unable to create http client: %w", op, err)
}
- provider, err := oidc.NewProvider(oidcCtx, c.Issuer) // makes http req to issuer for discovery
- if err != nil {
- p.Done() // release the backgroundCtxCancel resources
- // we don't know what's causing the problem, so we won't classify the
- // error with a Kind
- return nil, fmt.Errorf("%s: unable to create provider: %w", op, err)
- }
- p.provider = provider
+ switch {
+ case c.ProviderConfig != nil:
+ convertedAlgs := make([]string, len(c.SupportedSigningAlgs))
+ for _, alg := range c.SupportedSigningAlgs {
+ convertedAlgs = append(convertedAlgs, string(alg))
+ }
+ cfg := oidc.ProviderConfig{
+ IssuerURL: c.Issuer,
+ AuthURL: c.ProviderConfig.AuthURL,
+ JWKSURL: c.ProviderConfig.JWKSURL,
+ TokenURL: c.ProviderConfig.TokenURL,
+ UserInfoURL: c.ProviderConfig.UserInfoURL,
+ Algorithms: convertedAlgs,
+ }
+ p.provider = cfg.NewProvider(oidcCtx)
+ default:
+ provider, err := oidc.NewProvider(oidcCtx, c.Issuer) // makes http req to issuer for discovery
+ if err != nil {
+ p.Done() // release the backgroundCtxCancel resources
+ // we don't know what's causing the problem, so we won't classify the
+ // error with a Kind
+ return nil, fmt.Errorf("%s: unable to create provider: %w", op, err)
+ }
+ p.provider = provider
+ }
return p, nil
}
@@ -324,11 +345,11 @@ func (p *Provider) Exchange(ctx context.Context, oidcRequest Request, authorizat
// responses are not). The WithAudiences option is supported to specify
// optional audiences to verify when the aud claim is present in the response.
//
-// It verifies:
-// * sub (sub) is required and must match
-// * issuer (iss) - if the iss claim is included in returned claims
-// * audiences (aud) - if the aud claim is included in returned claims and
-// WithAudiences option is provided.
+// It verifies:
+// * sub (sub) is required and must match
+// * issuer (iss) - if the iss claim is included in returned claims
+// * audiences (aud) - if the aud claim is included in returned claims and
+// WithAudiences option is provided.
//
// See: https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource, validSubject string, claims interface{}, opt ...Option) error {
@@ -419,23 +440,24 @@ func getUserInfoOpts(opt ...Option) userInfoOptions {
}
// VerifyIDToken will verify the inbound IDToken and return its claims.
-// It verifies:
-// * signature (including if a supported signing algorithm was used)
-// * issuer (iss)
-// * expiration (exp)
-// * issued at (iat) (with a leeway of 1 min)
-// * not before (nbf) (with a leeway of 1 min)
-// * nonce (nonce)
-// * audience (aud) contains all audiences required from the provider's config
-// * when there are multiple audiences (aud), then one of them must equal
-// the client_id
-// * when present, the authorized party (azp) must equal the client id
-// * when there are multiple audiences (aud), then the authorized party (azp)
-// must equal the client id
-// * when there is a single audience (aud) and it is not equal to the client
-// id, then the authorized party (azp) must equal the client id
-// * when max_age was requested, the auth_time claim is verified (with a leeway
-// of 1 min)
+//
+// It verifies:
+// * signature (including if a supported signing algorithm was used)
+// * issuer (iss)
+// * expiration (exp)
+// * issued at (iat) (with a leeway of 1 min)
+// * not before (nbf) (with a leeway of 1 min)
+// * nonce (nonce)
+// * audience (aud) contains all audiences required from the provider's config
+// * when there are multiple audiences (aud), then one of them must equal
+// the client_id
+// * when present, the authorized party (azp) must equal the client id
+// * when there are multiple audiences (aud), then the authorized party (azp)
+// must equal the client id
+// * when there is a single audience (aud) and it is not equal to the client
+// id, then the authorized party (azp) must equal the client id
+// * when max_age was requested, the auth_time claim is verified (with a leeway
+// of 1 min)
//
// See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
func (p *Provider) VerifyIDToken(ctx context.Context, t IDToken, oidcRequest Request, opt ...Option) (map[string]interface{}, error) {
@@ -534,7 +556,7 @@ func (p *Provider) VerifyIDToken(ctx context.Context, t IDToken, oidcRequest Req
}
authTime := time.Unix(int64(atClaim), 0)
if !authTime.Add(leeway).After(authAfter) {
- return nil, fmt.Errorf("%s: auth_time (%s) is beyond max age (%d): %w", op, authTime, secs, ErrExpiredAuthTime)
+ return nil, fmt.Errorf("%s: auth_time (%s) is beyond max age (%d / %s): %w", op, authTime, secs, authAfter, ErrExpiredAuthTime)
}
}
diff --git a/oidc/provider_test.go b/oidc/provider_test.go
index 6556f1f..23781c4 100644
--- a/oidc/provider_test.go
+++ b/oidc/provider_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -42,6 +45,17 @@ func TestNewProvider(t *testing.T) {
name: "valid",
config: testNewConfig(t, clientID, clientSecret, redirect, tp),
},
+ {
+ name: "valid-WithProviderConfig",
+ config: testNewConfig(t, clientID, clientSecret, redirect, tp,
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: fmt.Sprintf("%s/authorize", tp.Addr()),
+ TokenURL: fmt.Sprintf("%s/token", tp.Addr()),
+ JWKSURL: fmt.Sprintf("%s/.well-known/jwks.json", tp.Addr()),
+ UserInfoURL: fmt.Sprintf("%s/userinfo", tp.Addr()),
+ }),
+ ),
+ },
{
name: "nil-config",
config: nil,
@@ -430,6 +444,27 @@ func TestProvider_AuthURL(t *testing.T) {
require.Equalf(tt.wantURL, gotURL, "Provider.AuthURL() = %v, want %v", gotURL, tt.wantURL)
})
}
+ t.Run("WithProviderConfig", func(t *testing.T) {
+ require := require.New(t)
+ p := testNewProvider(t, clientID, clientSecret, redirect, tp,
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: fmt.Sprintf("%s/authorize", tp.Addr()),
+ TokenURL: fmt.Sprintf("%s/token", tp.Addr()),
+ JWKSURL: fmt.Sprintf("%s/.well-known/jwks.json", tp.Addr()),
+ UserInfoURL: fmt.Sprintf("%s/userinfo", tp.Addr()),
+ }))
+ gotURL, err := p.AuthURL(ctx, validRequest)
+ require.NoError(err)
+ wantURL := fmt.Sprintf(
+ "%s/authorize?client_id=%s&nonce=%s&redirect_uri=%s&response_type=code&scope=openid&state=%s",
+ tp.Addr(),
+ clientID,
+ validRequest.Nonce(),
+ redirectEncoded,
+ validRequest.State(),
+ )
+ require.Equalf(wantURL, gotURL, "Provider.AuthURL() = %v, want %v", gotURL, wantURL)
+ })
}
func TestProvider_Exchange(t *testing.T) {
@@ -611,11 +646,39 @@ func TestProvider_Exchange(t *testing.T) {
tp.SetOmitIDTokens(false)
tp.SetExpectedAuthCode("valid-code")
tp.SetExpectedExpiry(-1 * time.Minute)
+ t.Cleanup(func() { tp.SetExpectedExpiry(1 * time.Minute) })
gotTk, err := p.Exchange(ctx, validRequest, validRequest.State(), "valid-code")
require.Error(err)
assert.Truef(errors.Is(err, ErrExpiredToken), "wanted \"%s\" but got \"%s\"", ErrExpiredToken, err)
assert.Empty(gotTk)
})
+ t.Run("WithProviderConfig", func(t *testing.T) {
+ assert, require := assert.New(t), require.New(t)
+
+ p := testNewProvider(t, clientID, clientSecret, redirect, tp,
+ WithProviderConfig(&ProviderConfig{
+ AuthURL: fmt.Sprintf("%s/authorize", tp.Addr()),
+ TokenURL: fmt.Sprintf("%s/token", tp.Addr()),
+ JWKSURL: fmt.Sprintf("%s/.well-known/jwks.json", tp.Addr()),
+ UserInfoURL: fmt.Sprintf("%s/userinfo", tp.Addr()),
+ }))
+ const authCode = "test-code"
+ tp.SetExpectedAuthCode(authCode)
+
+ validRequest, err := NewRequest(10*time.Second, redirect)
+ require.NoError(err)
+
+ // default to the request's nonce...
+ tp.SetExpectedAuthNonce(validRequest.Nonce())
+
+ gotTk, err := p.Exchange(ctx, validRequest, validRequest.State(), authCode)
+ require.NoError(err)
+ require.NotEmptyf(gotTk, "Provider.Exchange() = %v, wanted not nil", gotTk)
+ assert.NotEmptyf(gotTk.IDToken(), "gotTk.IDToken() = %v, wanted not empty", gotTk.IDToken())
+ assert.NotEmptyf(gotTk.AccessToken(), "gotTk.AccessToken() = %v, wanted not empty", gotTk.AccessToken())
+ assert.Truef(gotTk.Valid(), "gotTk.Valid() = %v, wanted true", gotTk.Valid())
+ assert.Truef(!gotTk.IsExpired(), "gotTk.Expired() = %v, wanted false", gotTk.IsExpired())
+ })
}
func TestHTTPClient(t *testing.T) {
diff --git a/oidc/refresh_token.go b/oidc/refresh_token.go
index 878f231..310ad40 100644
--- a/oidc/refresh_token.go
+++ b/oidc/refresh_token.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import "encoding/json"
diff --git a/oidc/refresh_token_test.go b/oidc/refresh_token_test.go
index 55c6b41..d1f00a8 100644
--- a/oidc/refresh_token_test.go
+++ b/oidc/refresh_token_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/request.go b/oidc/request.go
index d537b5d..38a11f0 100644
--- a/oidc/request.go
+++ b/oidc/request.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -204,19 +207,20 @@ type Req struct {
var _ Request = (*Req)(nil)
// NewRequest creates a new Request (*Req).
-// Supports the options:
-// * WithState
-// * WithNonce
-// * WithNow
-// * WithAudiences
-// * WithScopes
-// * WithImplicit
-// * WithPKCE
-// * WithMaxAge
-// * WithPrompts
-// * WithDisplay
-// * WithUILocales
-// * WithClaims
+//
+// Supports the options:
+// * WithState
+// * WithNonce
+// * WithNow
+// * WithAudiences
+// * WithScopes
+// * WithImplicit
+// * WithPKCE
+// * WithMaxAge
+// * WithPrompts
+// * WithDisplay
+// * WithUILocales
+// * WithClaims
func NewRequest(expireIn time.Duration, redirectURL string, opt ...Option) (*Req, error) {
const op = "oidc.NewRequest"
opts := getReqOpts(opt...)
@@ -271,7 +275,7 @@ func NewRequest(expireIn time.Duration, redirectURL string, opt ...Option) (*Req
}
r.expiration = r.now().Add(expireIn)
if opts.withMaxAge != nil {
- opts.withMaxAge.authAfter = r.now().Add(time.Duration(-opts.withMaxAge.seconds) * time.Second)
+ opts.withMaxAge.authAfter = r.now().Add(-1 * time.Duration(opts.withMaxAge.seconds) * time.Second)
r.withMaxAge = opts.withMaxAge
}
return r, nil
@@ -627,7 +631,6 @@ func WithACRValues(values ...string) Option {
// Neither a max or min length is enforced when you use the WithState option.
//
// Option is valid for: Request
-//
func WithState(s string) Option {
return func(o interface{}) {
if o, ok := o.(*reqOptions); ok {
@@ -660,7 +663,6 @@ func WithState(s string) Option {
// Neither a max or min length is enforced when you use the WithNonce option.
//
// Option is valid for: Request
-//
func WithNonce(n string) Option {
return func(o interface{}) {
if o, ok := o.(*reqOptions); ok {
diff --git a/oidc/request_test.go b/oidc/request_test.go
index ef07960..291391f 100644
--- a/oidc/request_test.go
+++ b/oidc/request_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/testing.go b/oidc/testing.go
index d0e017f..841f28e 100644
--- a/oidc/testing.go
+++ b/oidc/testing.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -19,10 +22,10 @@ import (
"testing"
"time"
+ "github.com/go-jose/go-jose/v3"
+ "github.com/go-jose/go-jose/v3/jwt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "gopkg.in/square/go-jose.v2"
- "gopkg.in/square/go-jose.v2/jwt"
)
// TestGenerateKeys will generate a test ECDSA P-256 pub/priv key pair.
@@ -163,7 +166,7 @@ func testDefaultJWT(t *testing.T, privKey crypto.PrivateKey, expireIn time.Durat
// TestProvider's client ID/secret and use the TestProviders signing algorithm
// when building the configuration. This is helpful internally, but
// intentionally not exported.
-func testNewConfig(t *testing.T, clientID, clientSecret, allowedRedirectURL string, tp *TestProvider) *Config {
+func testNewConfig(t *testing.T, clientID, clientSecret, allowedRedirectURL string, tp *TestProvider, opt ...Option) *Config {
const op = "testNewConfig"
t.Helper()
require := require.New(t)
@@ -172,6 +175,8 @@ func testNewConfig(t *testing.T, clientID, clientSecret, allowedRedirectURL stri
require.NotEmptyf(clientSecret, "%s: client secret is empty", op)
require.NotEmptyf(allowedRedirectURL, "%s: redirect URL is empty", op)
+ opts := getConfigOpts(opt...)
+
tp.SetClientCreds(clientID, clientSecret)
_, _, alg, _ := tp.SigningKeys()
c, err := NewConfig(
@@ -182,6 +187,7 @@ func testNewConfig(t *testing.T, clientID, clientSecret, allowedRedirectURL stri
[]string{allowedRedirectURL},
nil,
WithProviderCA(tp.CACert()),
+ WithProviderConfig(opts.withProviderConfig),
)
require.NoError(err)
return c
@@ -190,7 +196,7 @@ func testNewConfig(t *testing.T, clientID, clientSecret, allowedRedirectURL stri
// testNewProvider creates a new Provider. It uses the TestProvider (tp) to properly
// construct the provider's configuration (see testNewConfig). This is helpful internally, but
// intentionally not exported.
-func testNewProvider(t *testing.T, clientID, clientSecret, redirectURL string, tp *TestProvider) *Provider {
+func testNewProvider(t *testing.T, clientID, clientSecret, redirectURL string, tp *TestProvider, opt ...Option) *Provider {
const op = "testNewProvider"
t.Helper()
require := require.New(t)
@@ -198,7 +204,9 @@ func testNewProvider(t *testing.T, clientID, clientSecret, redirectURL string, t
require.NotEmptyf(clientSecret, "%s: client secret is empty", op)
require.NotEmptyf(redirectURL, "%s: redirect URL is empty", op)
- tc := testNewConfig(t, clientID, clientSecret, redirectURL, tp)
+ opts := getConfigOpts(opt...)
+
+ tc := testNewConfig(t, clientID, clientSecret, redirectURL, tp, WithProviderConfig(opts.withProviderConfig))
p, err := NewProvider(tc)
require.NoError(err)
t.Cleanup(p.Done)
diff --git a/oidc/testing_provider.go b/oidc/testing_provider.go
index 1d9fb11..086aa1a 100644
--- a/oidc/testing_provider.go
+++ b/oidc/testing_provider.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
@@ -29,11 +32,12 @@ import (
"sync"
"time"
- "github.com/hashicorp/cap/oidc/internal/strutils"
+ "github.com/go-jose/go-jose/v3"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/require"
- "gopkg.in/square/go-jose.v2"
+
+ "github.com/hashicorp/cap/oidc/internal/strutils"
)
var (
diff --git a/oidc/testing_provider_test.go b/oidc/testing_provider_test.go
index 315178d..40bab95 100644
--- a/oidc/testing_provider_test.go
+++ b/oidc/testing_provider_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/token.go b/oidc/token.go
index a0159b3..b141e7d 100644
--- a/oidc/token.go
+++ b/oidc/token.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/oidc/token_test.go b/oidc/token_test.go
index 07ccee7..f95fc54 100644
--- a/oidc/token_test.go
+++ b/oidc/token_test.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package oidc
import (
diff --git a/util/util.go b/util/util.go
index 610778d..f2b5f03 100644
--- a/util/util.go
+++ b/util/util.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package util
import (
@@ -15,11 +18,21 @@ func IsWSL() (bool, error) {
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
return false, nil
}
- data, err := ioutil.ReadFile("/proc/version")
+ procData, err := ioutil.ReadFile("/proc/version")
if err != nil {
return false, fmt.Errorf("Unable to read /proc/version: %w", err)
}
- return strings.Contains(strings.ToLower(string(data)), "microsoft"), nil
+
+ cgroupData, err := ioutil.ReadFile("/proc/1/cgroup")
+ if err != nil {
+ return false, fmt.Errorf("Unable to read /proc/1/cgroup: %w", err)
+ }
+
+ isDocker := strings.Contains(strings.ToLower(string(cgroupData)), "/docker/")
+ isLxc := strings.Contains(strings.ToLower(string(cgroupData)), "/lxc/")
+ isMsLinux := strings.Contains(strings.ToLower(string(procData)), "microsoft")
+
+ return isMsLinux && !(isDocker || isLxc), nil
}
// OpenURL opens the specified URL in the default browser of the user. Source: