mirror of
https://github.com/netbirdio/dex.git
synced 2026-05-22 18:43:53 -07:00
Merge remote-tracking branch 'upstream/master' into advisory-fix-1
Signed-off-by: Bob Callaway <bcallaway@google.com>
This commit is contained in:
@@ -70,7 +70,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
|
||||
# cache-from: type=gha
|
||||
# cache-to: type=gha,mode=max
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@0.6.0
|
||||
uses: aquasecurity/trivy-action@0.7.1
|
||||
with:
|
||||
image-ref: "ghcr.io/dexidp/dex:${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}"
|
||||
format: "sarif"
|
||||
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le
|
||||
# cache-from: type=gha
|
||||
# cache-to: type=gha,mode=max
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
@@ -96,7 +96,7 @@ jobs:
|
||||
org.opencontainers.image.documentation=https://dexidp.io/docs/
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@0.6.0
|
||||
uses: aquasecurity/trivy-action@0.7.1
|
||||
with:
|
||||
image-ref: "ghcr.io/dexidp/dex:${{ steps.tags.outputs.version }}"
|
||||
format: "template"
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
ARG BASE_IMAGE=alpine
|
||||
|
||||
FROM golang:1.18.4-alpine3.15 AS builder
|
||||
FROM golang:1.19.1-alpine3.16 AS builder
|
||||
|
||||
WORKDIR /usr/local/src/dex
|
||||
|
||||
@@ -22,26 +22,26 @@ COPY . .
|
||||
|
||||
RUN make release-binary
|
||||
|
||||
FROM alpine:3.16.1 AS stager
|
||||
FROM alpine:3.16.2 AS stager
|
||||
|
||||
RUN mkdir -p /var/dex
|
||||
RUN mkdir -p /etc/dex
|
||||
COPY config.docker.yaml /etc/dex/
|
||||
|
||||
FROM alpine:3.16.1 AS gomplate
|
||||
FROM alpine:3.16.2 AS gomplate
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
||||
ENV GOMPLATE_VERSION=v3.10.0
|
||||
ENV GOMPLATE_VERSION=v3.11.2
|
||||
|
||||
RUN wget -O /usr/local/bin/gomplate \
|
||||
"https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_${TARGETOS:-linux}-${TARGETARCH:-amd64}${TARGETVARIANT}" \
|
||||
&& chmod +x /usr/local/bin/gomplate
|
||||
|
||||
# For Dependabot to detect base image versions
|
||||
FROM alpine:3.16.1 AS alpine
|
||||
FROM alpine:3.16.2 AS alpine
|
||||
FROM gcr.io/distroless/static:latest AS distroless
|
||||
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ module github.com/dexidp/dex/api/v2
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
google.golang.org/grpc v1.47.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
google.golang.org/grpc v1.49.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
+4
-3
@@ -117,8 +117,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
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=
|
||||
@@ -131,8 +131,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/dexidp/dex/connector"
|
||||
"github.com/dexidp/dex/pkg/log"
|
||||
@@ -69,7 +70,11 @@ func (m *callback) HandleCallback(s connector.Scopes, r *http.Request) (connecto
|
||||
groups := m.groups
|
||||
headerGroup := r.Header.Get(m.groupHeader)
|
||||
if headerGroup != "" {
|
||||
groups = append(groups, headerGroup)
|
||||
splitheaderGroup := strings.Split(headerGroup, ",")
|
||||
for i, v := range splitheaderGroup {
|
||||
splitheaderGroup[i] = strings.TrimSpace(v)
|
||||
}
|
||||
groups = append(splitheaderGroup, groups...)
|
||||
}
|
||||
return connector.Identity{
|
||||
UserID: remoteUser, // TODO: figure out if this is a bad ID value.
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package authproxy
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/dexidp/dex/connector"
|
||||
)
|
||||
|
||||
const (
|
||||
testEmail = "testuser@example.com"
|
||||
testGroup1 = "group1"
|
||||
testGroup2 = "group2"
|
||||
testGroup3 = "group 3"
|
||||
testGroup4 = "group 4"
|
||||
testStaticGroup1 = "static1"
|
||||
testStaticGroup2 = "static 2"
|
||||
)
|
||||
|
||||
var logger = &logrus.Logger{Out: io.Discard, Formatter: &logrus.TextFormatter{}}
|
||||
|
||||
func TestUser(t *testing.T) {
|
||||
config := Config{
|
||||
UserHeader: "X-Remote-User",
|
||||
}
|
||||
conn := callback{userHeader: config.UserHeader, logger: logger, pathSuffix: "/test"}
|
||||
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
expectNil(t, err)
|
||||
req.Header = map[string][]string{
|
||||
"X-Remote-User": {testEmail},
|
||||
}
|
||||
|
||||
ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
|
||||
expectNil(t, err)
|
||||
|
||||
expectEquals(t, ident.UserID, testEmail)
|
||||
expectEquals(t, ident.Email, testEmail)
|
||||
expectEquals(t, len(ident.Groups), 0)
|
||||
}
|
||||
|
||||
func TestSingleGroup(t *testing.T) {
|
||||
config := Config{
|
||||
UserHeader: "X-Remote-User",
|
||||
GroupHeader: "X-Remote-Group",
|
||||
}
|
||||
|
||||
conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, logger: logger, pathSuffix: "/test"}
|
||||
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
expectNil(t, err)
|
||||
req.Header = map[string][]string{
|
||||
"X-Remote-User": {testEmail},
|
||||
"X-Remote-Group": {testGroup1},
|
||||
}
|
||||
|
||||
ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
|
||||
expectNil(t, err)
|
||||
|
||||
expectEquals(t, ident.UserID, testEmail)
|
||||
expectEquals(t, len(ident.Groups), 1)
|
||||
expectEquals(t, ident.Groups[0], testGroup1)
|
||||
}
|
||||
|
||||
func TestMultipleGroup(t *testing.T) {
|
||||
config := Config{
|
||||
UserHeader: "X-Remote-User",
|
||||
GroupHeader: "X-Remote-Group",
|
||||
}
|
||||
|
||||
conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, logger: logger, pathSuffix: "/test"}
|
||||
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
expectNil(t, err)
|
||||
req.Header = map[string][]string{
|
||||
"X-Remote-User": {testEmail},
|
||||
"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
|
||||
}
|
||||
|
||||
ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
|
||||
expectNil(t, err)
|
||||
|
||||
expectEquals(t, ident.UserID, testEmail)
|
||||
expectEquals(t, len(ident.Groups), 4)
|
||||
expectEquals(t, ident.Groups[0], testGroup1)
|
||||
expectEquals(t, ident.Groups[1], testGroup2)
|
||||
expectEquals(t, ident.Groups[2], testGroup3)
|
||||
expectEquals(t, ident.Groups[3], testGroup4)
|
||||
}
|
||||
|
||||
func TestStaticGroup(t *testing.T) {
|
||||
config := Config{
|
||||
UserHeader: "X-Remote-User",
|
||||
GroupHeader: "X-Remote-Group",
|
||||
Groups: []string{"static1", "static 2"},
|
||||
}
|
||||
|
||||
conn := callback{userHeader: config.UserHeader, groupHeader: config.GroupHeader, groups: config.Groups, logger: logger, pathSuffix: "/test"}
|
||||
|
||||
req, err := http.NewRequest("GET", "/", nil)
|
||||
expectNil(t, err)
|
||||
req.Header = map[string][]string{
|
||||
"X-Remote-User": {testEmail},
|
||||
"X-Remote-Group": {testGroup1 + ", " + testGroup2 + ", " + testGroup3 + ", " + testGroup4},
|
||||
}
|
||||
|
||||
ident, err := conn.HandleCallback(connector.Scopes{OfflineAccess: true, Groups: true}, req)
|
||||
expectNil(t, err)
|
||||
|
||||
expectEquals(t, ident.UserID, testEmail)
|
||||
expectEquals(t, len(ident.Groups), 6)
|
||||
expectEquals(t, ident.Groups[0], testGroup1)
|
||||
expectEquals(t, ident.Groups[1], testGroup2)
|
||||
expectEquals(t, ident.Groups[2], testGroup3)
|
||||
expectEquals(t, ident.Groups[3], testGroup4)
|
||||
expectEquals(t, ident.Groups[4], testStaticGroup1)
|
||||
expectEquals(t, ident.Groups[5], testStaticGroup2)
|
||||
}
|
||||
|
||||
func expectNil(t *testing.T, a interface{}) {
|
||||
if a != nil {
|
||||
t.Errorf("Expected %+v to equal nil", a)
|
||||
}
|
||||
}
|
||||
|
||||
func expectEquals(t *testing.T, a interface{}, b interface{}) {
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Errorf("Expected %+v to equal %+v", a, b)
|
||||
}
|
||||
}
|
||||
+27
-27
@@ -71,7 +71,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
|
||||
scopes = append(scopes, "profile", "email")
|
||||
}
|
||||
|
||||
srv, err := createDirectoryService(c.ServiceAccountFilePath, c.AdminEmail)
|
||||
srv, err := createDirectoryService(c.ServiceAccountFilePath, c.AdminEmail, logger)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, fmt.Errorf("could not create directory service: %v", err)
|
||||
@@ -279,37 +279,37 @@ func (c *googleConnector) getGroups(email string, fetchTransitiveGroupMembership
|
||||
return uniqueGroups(userGroups), nil
|
||||
}
|
||||
|
||||
// createDirectoryService loads a google service account credentials file,
|
||||
// sets up super user impersonation and creates an admin client for calling
|
||||
// the google admin api
|
||||
func createDirectoryService(serviceAccountFilePath string, email string) (*admin.Service, error) {
|
||||
if serviceAccountFilePath == "" && email == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if serviceAccountFilePath == "" || email == "" {
|
||||
return nil, fmt.Errorf("directory service requires both serviceAccountFilePath and adminEmail")
|
||||
}
|
||||
jsonCredentials, err := os.ReadFile(serviceAccountFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading credentials from file: %v", err)
|
||||
// createDirectoryService sets up super user impersonation and creates an admin client for calling
|
||||
// the google admin api. If no serviceAccountFilePath is defined, the application default credential
|
||||
// is used.
|
||||
func createDirectoryService(serviceAccountFilePath, email string, logger log.Logger) (*admin.Service, error) {
|
||||
if email == "" {
|
||||
return nil, fmt.Errorf("directory service requires adminEmail")
|
||||
}
|
||||
|
||||
config, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryGroupReadonlyScope)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse client secret file to config: %v", err)
|
||||
}
|
||||
|
||||
// Impersonate an admin. This is mandatory for the admin APIs.
|
||||
config.Subject = email
|
||||
var jsonCredentials []byte
|
||||
var err error
|
||||
|
||||
ctx := context.Background()
|
||||
client := config.Client(ctx)
|
||||
|
||||
srv, err := admin.NewService(ctx, option.WithHTTPClient(client))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create directory service %v", err)
|
||||
if serviceAccountFilePath == "" {
|
||||
logger.Warn("the application default credential is used since the service account file path is not used")
|
||||
credential, err := google.FindDefaultCredentials(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch application default credentials: %w", err)
|
||||
}
|
||||
jsonCredentials = credential.JSON
|
||||
} else {
|
||||
jsonCredentials, err = os.ReadFile(serviceAccountFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading credentials from file: %v", err)
|
||||
}
|
||||
}
|
||||
return srv, nil
|
||||
config, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryGroupReadonlyScope)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse credentials to config: %v", err)
|
||||
}
|
||||
config.Subject = email
|
||||
return admin.NewService(ctx, option.WithHTTPClient(config.Client(ctx)))
|
||||
}
|
||||
|
||||
// uniqueGroups returns the unique groups of a slice
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testSetup(t *testing.T) *httptest.Server {
|
||||
mux := http.NewServeMux()
|
||||
// TODO: mock calls
|
||||
// mux.HandleFunc("/admin/directory/v1/groups", func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.Header().Add("Content-Type", "application/json")
|
||||
// json.NewEncoder(w).Encode(&admin.Groups{
|
||||
// Groups: []*admin.Group{},
|
||||
// })
|
||||
// })
|
||||
return httptest.NewServer(mux)
|
||||
}
|
||||
|
||||
func newConnector(config *Config, serverURL string) (*googleConnector, error) {
|
||||
log := logrus.New()
|
||||
conn, err := config.Open("id", log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
googleConn, ok := conn.(*googleConnector)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to convert to googleConnector")
|
||||
}
|
||||
return googleConn, nil
|
||||
}
|
||||
|
||||
func tempServiceAccountKey() (string, error) {
|
||||
fd, err := os.CreateTemp("", "google_service_account_key")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer fd.Close()
|
||||
err = json.NewEncoder(fd).Encode(map[string]string{
|
||||
"type": "service_account",
|
||||
"project_id": "sample-project",
|
||||
"private_key_id": "sample-key-id",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nsample-key\n-----END PRIVATE KEY-----\n",
|
||||
"client_id": "sample-client-id",
|
||||
"client_x509_cert_url": "localhost",
|
||||
})
|
||||
return fd.Name(), err
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
ts := testSetup(t)
|
||||
defer ts.Close()
|
||||
|
||||
type testCase struct {
|
||||
config *Config
|
||||
expectedErr string
|
||||
|
||||
// string to set in GOOGLE_APPLICATION_CREDENTIALS. As local development environments can
|
||||
// already contain ADC, test cases will be built uppon this setting this env variable
|
||||
adc string
|
||||
}
|
||||
|
||||
serviceAccountFilePath, err := tempServiceAccountKey()
|
||||
assert.Nil(t, err)
|
||||
|
||||
for name, reference := range map[string]testCase{
|
||||
"missing_admin_email": {
|
||||
config: &Config{
|
||||
ClientID: "testClient",
|
||||
ClientSecret: "testSecret",
|
||||
RedirectURI: ts.URL + "/callback",
|
||||
Scopes: []string{"openid", "groups"},
|
||||
},
|
||||
expectedErr: "requires adminEmail",
|
||||
},
|
||||
"service_account_key_not_found": {
|
||||
config: &Config{
|
||||
ClientID: "testClient",
|
||||
ClientSecret: "testSecret",
|
||||
RedirectURI: ts.URL + "/callback",
|
||||
Scopes: []string{"openid", "groups"},
|
||||
AdminEmail: "foo@bar.com",
|
||||
ServiceAccountFilePath: "not_found.json",
|
||||
},
|
||||
expectedErr: "error reading credentials",
|
||||
},
|
||||
"service_account_key_valid": {
|
||||
config: &Config{
|
||||
ClientID: "testClient",
|
||||
ClientSecret: "testSecret",
|
||||
RedirectURI: ts.URL + "/callback",
|
||||
Scopes: []string{"openid", "groups"},
|
||||
AdminEmail: "foo@bar.com",
|
||||
ServiceAccountFilePath: serviceAccountFilePath,
|
||||
},
|
||||
expectedErr: "",
|
||||
},
|
||||
"adc": {
|
||||
config: &Config{
|
||||
ClientID: "testClient",
|
||||
ClientSecret: "testSecret",
|
||||
RedirectURI: ts.URL + "/callback",
|
||||
Scopes: []string{"openid", "groups"},
|
||||
AdminEmail: "foo@bar.com",
|
||||
},
|
||||
adc: serviceAccountFilePath,
|
||||
expectedErr: "",
|
||||
},
|
||||
"adc_priority": {
|
||||
config: &Config{
|
||||
ClientID: "testClient",
|
||||
ClientSecret: "testSecret",
|
||||
RedirectURI: ts.URL + "/callback",
|
||||
Scopes: []string{"openid", "groups"},
|
||||
AdminEmail: "foo@bar.com",
|
||||
ServiceAccountFilePath: serviceAccountFilePath,
|
||||
},
|
||||
adc: "/dev/null",
|
||||
expectedErr: "",
|
||||
},
|
||||
} {
|
||||
reference := reference
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", reference.adc)
|
||||
conn, err := newConnector(reference.config, ts.URL)
|
||||
|
||||
if reference.expectedErr == "" {
|
||||
assert.Nil(err)
|
||||
assert.NotNil(conn)
|
||||
} else {
|
||||
assert.ErrorContains(err, reference.expectedErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ type conn struct {
|
||||
Host string
|
||||
AdminUsername string
|
||||
AdminPassword string
|
||||
client *http.Client
|
||||
Logger log.Logger
|
||||
}
|
||||
|
||||
@@ -35,6 +36,7 @@ type domainKeystone struct {
|
||||
// Config holds the configuration parameters for Keystone connector.
|
||||
// Keystone should expose API v3
|
||||
// An example config:
|
||||
//
|
||||
// connectors:
|
||||
// type: keystone
|
||||
// id: keystone
|
||||
@@ -111,11 +113,12 @@ var (
|
||||
// Open returns an authentication strategy using Keystone.
|
||||
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
|
||||
return &conn{
|
||||
c.Domain,
|
||||
c.Host,
|
||||
c.AdminUsername,
|
||||
c.AdminPassword,
|
||||
logger,
|
||||
Domain: c.Domain,
|
||||
Host: c.Host,
|
||||
AdminUsername: c.AdminUsername,
|
||||
AdminPassword: c.AdminPassword,
|
||||
Logger: logger,
|
||||
client: http.DefaultClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -192,7 +195,6 @@ func (p *conn) Refresh(
|
||||
}
|
||||
|
||||
func (p *conn) getTokenResponse(ctx context.Context, username, pass string) (response *http.Response, err error) {
|
||||
client := &http.Client{}
|
||||
jsonData := loginRequestData{
|
||||
auth: auth{
|
||||
Identity: identity{
|
||||
@@ -221,7 +223,7 @@ func (p *conn) getTokenResponse(ctx context.Context, username, pass string) (res
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
return client.Do(req)
|
||||
return p.client.Do(req)
|
||||
}
|
||||
|
||||
func (p *conn) getAdminToken(ctx context.Context) (string, error) {
|
||||
@@ -243,7 +245,6 @@ func (p *conn) checkIfUserExists(ctx context.Context, userID string, token strin
|
||||
func (p *conn) getUser(ctx context.Context, userID string, token string) (*userResponse, error) {
|
||||
// https://developer.openstack.org/api-ref/identity/v3/#show-user-details
|
||||
userURL := p.Host + "/v3/users/" + userID
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", userURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -251,7 +252,7 @@ func (p *conn) getUser(ctx context.Context, userID string, token string) (*userR
|
||||
|
||||
req.Header.Set("X-Auth-Token", token)
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := client.Do(req)
|
||||
resp, err := p.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -276,7 +277,6 @@ func (p *conn) getUser(ctx context.Context, userID string, token string) (*userR
|
||||
}
|
||||
|
||||
func (p *conn) getUserGroups(ctx context.Context, userID string, token string) ([]string, error) {
|
||||
client := &http.Client{}
|
||||
// https://developer.openstack.org/api-ref/identity/v3/#list-groups-to-which-a-user-belongs
|
||||
groupsURL := p.Host + "/v3/users/" + userID + "/groups"
|
||||
req, err := http.NewRequest("GET", groupsURL, nil)
|
||||
@@ -285,7 +285,7 @@ func (p *conn) getUserGroups(ctx context.Context, userID string, token string) (
|
||||
}
|
||||
req.Header.Set("X-Auth-Token", token)
|
||||
req = req.WithContext(ctx)
|
||||
resp, err := client.Do(req)
|
||||
resp, err := p.client.Do(req)
|
||||
if err != nil {
|
||||
p.Logger.Errorf("keystone: error while fetching user %q groups\n", userID)
|
||||
return nil, err
|
||||
|
||||
@@ -42,8 +42,6 @@ type groupResponse struct {
|
||||
|
||||
func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string) {
|
||||
t.Helper()
|
||||
client := &http.Client{}
|
||||
|
||||
jsonData := loginRequestData{
|
||||
auth: auth{
|
||||
Identity: identity{
|
||||
@@ -70,7 +68,7 @@ func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := client.Do(req)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -93,7 +91,6 @@ func getAdminToken(t *testing.T, adminName, adminPass string) (token, id string)
|
||||
|
||||
func createUser(t *testing.T, token, userName, userEmail, userPass string) string {
|
||||
t.Helper()
|
||||
client := &http.Client{}
|
||||
|
||||
createUserData := map[string]interface{}{
|
||||
"user": map[string]interface{}{
|
||||
@@ -116,7 +113,7 @@ func createUser(t *testing.T, token, userName, userEmail, userPass string) strin
|
||||
}
|
||||
req.Header.Set("X-Auth-Token", token)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
resp, err := client.Do(req)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -139,7 +136,6 @@ func createUser(t *testing.T, token, userName, userEmail, userPass string) strin
|
||||
// delete group or user
|
||||
func deleteResource(t *testing.T, token, id, uri string) {
|
||||
t.Helper()
|
||||
client := &http.Client{}
|
||||
|
||||
deleteURI := uri + id
|
||||
req, err := http.NewRequest("DELETE", deleteURI, nil)
|
||||
@@ -148,7 +144,7 @@ func deleteResource(t *testing.T, token, id, uri string) {
|
||||
}
|
||||
req.Header.Set("X-Auth-Token", token)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
@@ -157,7 +153,6 @@ func deleteResource(t *testing.T, token, id, uri string) {
|
||||
|
||||
func createGroup(t *testing.T, token, description, name string) string {
|
||||
t.Helper()
|
||||
client := &http.Client{}
|
||||
|
||||
createGroupData := map[string]interface{}{
|
||||
"group": map[string]interface{}{
|
||||
@@ -177,7 +172,7 @@ func createGroup(t *testing.T, token, description, name string) string {
|
||||
}
|
||||
req.Header.Set("X-Auth-Token", token)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
resp, err := client.Do(req)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -200,14 +195,13 @@ func createGroup(t *testing.T, token, description, name string) string {
|
||||
func addUserToGroup(t *testing.T, token, groupID, userID string) error {
|
||||
t.Helper()
|
||||
uri := groupsURL + groupID + "/users/" + userID
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("PUT", uri, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("X-Auth-Token", token)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
@@ -219,7 +213,8 @@ func addUserToGroup(t *testing.T, token, groupID, userID string) error {
|
||||
func TestIncorrectCredentialsLogin(t *testing.T) {
|
||||
setupVariables(t)
|
||||
c := conn{
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
client: http.DefaultClient,
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
AdminUsername: adminUser, AdminPassword: adminPass,
|
||||
}
|
||||
s := connector.Scopes{OfflineAccess: true, Groups: true}
|
||||
@@ -296,7 +291,8 @@ func TestValidUserLogin(t *testing.T) {
|
||||
defer deleteResource(t, token, userID, usersURL)
|
||||
|
||||
c := conn{
|
||||
Host: keystoneURL, Domain: tt.input.domain,
|
||||
client: http.DefaultClient,
|
||||
Host: keystoneURL, Domain: tt.input.domain,
|
||||
AdminUsername: adminUser, AdminPassword: adminPass,
|
||||
}
|
||||
s := connector.Scopes{OfflineAccess: true, Groups: true}
|
||||
@@ -333,7 +329,8 @@ func TestUseRefreshToken(t *testing.T) {
|
||||
defer deleteResource(t, token, groupID, groupsURL)
|
||||
|
||||
c := conn{
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
client: http.DefaultClient,
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
AdminUsername: adminUser, AdminPassword: adminPass,
|
||||
}
|
||||
s := connector.Scopes{OfflineAccess: true, Groups: true}
|
||||
@@ -358,7 +355,8 @@ func TestUseRefreshTokenUserDeleted(t *testing.T) {
|
||||
userID := createUser(t, token, testUser, testEmail, testPass)
|
||||
|
||||
c := conn{
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
client: http.DefaultClient,
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
AdminUsername: adminUser, AdminPassword: adminPass,
|
||||
}
|
||||
s := connector.Scopes{OfflineAccess: true, Groups: true}
|
||||
@@ -388,7 +386,8 @@ func TestUseRefreshTokenGroupsChanged(t *testing.T) {
|
||||
defer deleteResource(t, token, userID, usersURL)
|
||||
|
||||
c := conn{
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
client: http.DefaultClient,
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
AdminUsername: adminUser, AdminPassword: adminPass,
|
||||
}
|
||||
s := connector.Scopes{OfflineAccess: true, Groups: true}
|
||||
@@ -424,7 +423,8 @@ func TestNoGroupsInScope(t *testing.T) {
|
||||
defer deleteResource(t, token, userID, usersURL)
|
||||
|
||||
c := conn{
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
client: http.DefaultClient,
|
||||
Host: keystoneURL, Domain: testDomain,
|
||||
AdminUsername: adminUser, AdminPassword: adminPass,
|
||||
}
|
||||
s := connector.Scopes{OfflineAccess: true, Groups: false}
|
||||
|
||||
@@ -58,6 +58,8 @@ type Config struct {
|
||||
// For valid values, see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code.
|
||||
PromptType string `json:"promptType"`
|
||||
DomainHint string `json:"domainHint"`
|
||||
|
||||
Scopes []string `json:"scopes"` // defaults to scopeUser (user.read)
|
||||
}
|
||||
|
||||
// Open returns a strategy for logging in through Microsoft.
|
||||
@@ -77,6 +79,7 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error)
|
||||
emailToLowercase: c.EmailToLowercase,
|
||||
promptType: c.PromptType,
|
||||
domainHint: c.DomainHint,
|
||||
scopes: c.Scopes,
|
||||
}
|
||||
// By default allow logins from both personal and business/school
|
||||
// accounts.
|
||||
@@ -122,6 +125,7 @@ type microsoftConnector struct {
|
||||
emailToLowercase bool
|
||||
promptType string
|
||||
domainHint string
|
||||
scopes []string
|
||||
}
|
||||
|
||||
func (c *microsoftConnector) isOrgTenant() bool {
|
||||
@@ -133,7 +137,12 @@ func (c *microsoftConnector) groupsRequired(groupScope bool) bool {
|
||||
}
|
||||
|
||||
func (c *microsoftConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
|
||||
microsoftScopes := []string{scopeUser}
|
||||
var microsoftScopes []string
|
||||
if len(c.scopes) > 0 {
|
||||
microsoftScopes = c.scopes
|
||||
} else {
|
||||
microsoftScopes = append(microsoftScopes, scopeUser)
|
||||
}
|
||||
if c.groupsRequired(scopes.Groups) {
|
||||
microsoftScopes = append(microsoftScopes, scopeGroups)
|
||||
}
|
||||
|
||||
@@ -351,6 +351,11 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
|
||||
vs, found = claims[groupsKey].([]interface{})
|
||||
}
|
||||
|
||||
// Fallback when claims[groupsKey] is a string instead of an array of strings.
|
||||
if g, b := claims[groupsKey].(string); b {
|
||||
groups = []string{g}
|
||||
}
|
||||
|
||||
if found {
|
||||
for _, v := range vs {
|
||||
if s, ok := v.(string); ok {
|
||||
|
||||
@@ -271,6 +271,22 @@ func TestHandleCallback(t *testing.T) {
|
||||
"cognito:groups": []string{"group3", "group4"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "singularGroupResponseAsString",
|
||||
userIDKey: "", // not configured
|
||||
userNameKey: "", // not configured
|
||||
expectUserID: "subvalue",
|
||||
expectUserName: "namevalue",
|
||||
expectGroups: []string{"group1"},
|
||||
expectedEmailField: "emailvalue",
|
||||
token: map[string]interface{}{
|
||||
"sub": "subvalue",
|
||||
"name": "namevalue",
|
||||
"groups": "group1",
|
||||
"email": "emailvalue",
|
||||
"email_verified": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
|
||||
Generated
+6
-6
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1648297722,
|
||||
"narHash": "sha256-W+qlPsiZd8F3XkzXOzAoR+mpFqzm3ekQkJNa+PIh1BQ=",
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "0f8662f1319ad6abf89b3380dd2722369fc51ade",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -17,11 +17,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1649225869,
|
||||
"narHash": "sha256-u1zLtPmQzhT9mNXyM8Ey9pk7orDrIKdwooeGDEXm5xM=",
|
||||
"lastModified": 1662019588,
|
||||
"narHash": "sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b6966d911da89e5a7301aaef8b4f0a44c77e103c",
|
||||
"rev": "2da64a81275b68fdad38af669afeda43d401e94b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -7,19 +7,21 @@
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
buildDeps = with pkgs; [ git go_1_18 gnumake ];
|
||||
devDeps = with pkgs;
|
||||
buildDeps ++ [
|
||||
golangci-lint
|
||||
gotestsum
|
||||
protobuf
|
||||
protoc-gen-go
|
||||
protoc-gen-go-grpc
|
||||
kind
|
||||
];
|
||||
in
|
||||
{ devShell = pkgs.mkShell { buildInputs = devDeps; }; });
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
buildDeps = with pkgs; [ git go_1_19 gnumake ];
|
||||
devDeps = with pkgs;
|
||||
buildDeps ++ [
|
||||
golangci-lint
|
||||
gotestsum
|
||||
protobuf
|
||||
protoc-gen-go
|
||||
protoc-gen-go-grpc
|
||||
kind
|
||||
];
|
||||
in
|
||||
{ devShell = pkgs.mkShell { buildInputs = devDeps; }; }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
module github.com/dexidp/dex
|
||||
|
||||
go 1.18
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
entgo.io/ent v0.10.1
|
||||
entgo.io/ent v0.11.2
|
||||
github.com/AppsFlyer/go-sundheit v0.5.0
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/coreos/go-oidc/v3 v3.2.0
|
||||
github.com/coreos/go-oidc/v3 v3.4.0
|
||||
github.com/dexidp/dex/api/v2 v2.1.0
|
||||
github.com/felixge/httpsnoop v1.0.3
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0
|
||||
github.com/mattn/go-sqlite3 v1.14.11
|
||||
github.com/mattn/go-sqlite3 v1.14.15
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/russellhaering/goxmldsig v1.2.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/stretchr/testify v1.8.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4
|
||||
go.etcd.io/etcd/client/v3 v3.5.4
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
|
||||
google.golang.org/api v0.86.0
|
||||
google.golang.org/grpc v1.47.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
|
||||
google.golang.org/api v0.97.0
|
||||
google.golang.org/grpc v1.49.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 // indirect
|
||||
ariga.io/atlas v0.5.1-0.20220717122844-8593d7eb1a8e // indirect
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
@@ -52,7 +52,7 @@ require (
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
@@ -72,8 +72,8 @@ require (
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
@@ -83,8 +83,8 @@ require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.17.0 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3 h1:fjG4oFCQEfGrRi0QoxWcH2OO28CE6VYa6DkIr3yDySU=
|
||||
ariga.io/atlas v0.3.7-0.20220303204946-787354f533c3/go.mod h1:yWGf4VPiD4SW83+kAqzD624txN9VKoJC+bpVXr2pKJA=
|
||||
ariga.io/atlas v0.5.1-0.20220717122844-8593d7eb1a8e h1:/r1xGMwmLg4LZ2V3/wWui9TtM3+STh1fp5ExSVRNFZo=
|
||||
ariga.io/atlas v0.5.1-0.20220717122844-8593d7eb1a8e/go.mod h1:ofVetkJqlaWle3mvYmaS2uyFGFcc7dSq436tmxa/Mzk=
|
||||
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=
|
||||
@@ -57,12 +57,12 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
entgo.io/ent v0.10.1 h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=
|
||||
entgo.io/ent v0.10.1/go.mod h1:YPgxeLnoQ/YdpVORRtqjBF+wCy9NX9IR7veTv3Bffus=
|
||||
entgo.io/ent v0.11.2 h1:UM2/BUhF2FfsxPHRxLjQbhqJNaDdVlOwNIAMLs2jyto=
|
||||
entgo.io/ent v0.11.2/go.mod h1:YGHEQnmmIUgtD5b1ICD5vg74dS3npkNnmC5K+0J+IHU=
|
||||
github.com/AppsFlyer/go-sundheit v0.5.0 h1:/VxpyigCfJrq1r97mn9HPiAB2qrhcTFHwNIIDr15CZM=
|
||||
github.com/AppsFlyer/go-sundheit v0.5.0/go.mod h1:2ZM0BnfqT/mljBQO224VbL5XH06TgWuQ6Cn+cTtCpTY=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
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/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
@@ -111,8 +111,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-oidc/v3 v3.2.0 h1:2eR2MGR7thBXSQ2YbODlF0fcmgtliLCfr9iX6RW11fc=
|
||||
github.com/coreos/go-oidc/v3 v3.2.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
|
||||
github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
|
||||
github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
@@ -140,19 +140,21 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
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-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/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-ldap/ldap/v3 v3.4.2 h1:zFZKcXKLqZpFMrMQGHeHWKXbDTdNCmhGY9AK41zPh+8=
|
||||
github.com/go-ldap/ldap/v3 v3.4.2/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
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/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
@@ -298,12 +300,12 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
||||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||
github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
|
||||
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
@@ -333,8 +335,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
|
||||
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@@ -343,14 +346,16 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
@@ -389,6 +394,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
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 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
@@ -431,10 +437,9 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||
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-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/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=
|
||||
@@ -470,8 +475,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -495,7 +500,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
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=
|
||||
@@ -512,14 +516,17 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
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=
|
||||
@@ -540,8 +547,8 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
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=
|
||||
@@ -623,9 +630,9 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -741,8 +748,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
|
||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/api v0.86.0 h1:ZAnyOHQFIuWso1BodVfSaRyffD74T9ERGFa3k1fNk/U=
|
||||
google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||
google.golang.org/api v0.97.0 h1:x/vEL1XDF/2V4xzdNgFPaKHluRESo2aTsL7QzHnBtGQ=
|
||||
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
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=
|
||||
@@ -861,8 +868,9 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
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=
|
||||
@@ -877,8 +885,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -886,7 +895,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
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.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -73,6 +73,17 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
|
||||
clientID := r.Form.Get("client_id")
|
||||
clientSecret := r.Form.Get("client_secret")
|
||||
scopes := strings.Fields(r.Form.Get("scope"))
|
||||
codeChallenge := r.Form.Get("code_challenge")
|
||||
codeChallengeMethod := r.Form.Get("code_challenge_method")
|
||||
|
||||
if codeChallengeMethod == "" {
|
||||
codeChallengeMethod = codeChallengeMethodPlain
|
||||
}
|
||||
if codeChallengeMethod != codeChallengeMethodS256 && codeChallengeMethod != codeChallengeMethodPlain {
|
||||
description := fmt.Sprintf("Unsupported PKCE challenge method (%q).", codeChallengeMethod)
|
||||
s.tokenErrHelper(w, errInvalidRequest, description, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Infof("Received device request for client %v with scopes %v", clientID, scopes)
|
||||
|
||||
@@ -108,6 +119,10 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
|
||||
Expiry: expireTime,
|
||||
LastRequestTime: s.now(),
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
}
|
||||
|
||||
if err := s.storage.CreateDeviceToken(deviceToken); err != nil {
|
||||
@@ -236,6 +251,30 @@ func (s *Server) handleDeviceToken(w http.ResponseWriter, r *http.Request) {
|
||||
s.tokenErrHelper(w, deviceTokenPending, "", http.StatusUnauthorized)
|
||||
}
|
||||
case deviceTokenComplete:
|
||||
codeChallengeFromStorage := deviceToken.PKCE.CodeChallenge
|
||||
providedCodeVerifier := r.Form.Get("code_verifier")
|
||||
|
||||
switch {
|
||||
case providedCodeVerifier != "" && codeChallengeFromStorage != "":
|
||||
calculatedCodeChallenge, err := s.calculateCodeChallenge(providedCodeVerifier, deviceToken.PKCE.CodeChallengeMethod)
|
||||
if err != nil {
|
||||
s.logger.Error(err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if codeChallengeFromStorage != calculatedCodeChallenge {
|
||||
s.tokenErrHelper(w, errInvalidGrant, "Invalid code_verifier.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
case providedCodeVerifier != "":
|
||||
// Received no code_challenge on /auth, but a code_verifier on /token
|
||||
s.tokenErrHelper(w, errInvalidRequest, "No PKCE flow started. Cannot check code_verifier.", http.StatusBadRequest)
|
||||
return
|
||||
case codeChallengeFromStorage != "":
|
||||
// Received PKCE request on /auth, but no code_verifier on /token
|
||||
s.tokenErrHelper(w, errInvalidGrant, "Expecting parameter code_verifier in PKCE flow.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.Write([]byte(deviceToken.Token))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ func TestHandleDeviceCode(t *testing.T) {
|
||||
tests := []struct {
|
||||
testName string
|
||||
clientID string
|
||||
codeChallengeMethod string
|
||||
requestType string
|
||||
scopes []string
|
||||
expectedResponseCode int
|
||||
@@ -71,6 +72,24 @@ func TestHandleDeviceCode(t *testing.T) {
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedContentType: "application/json",
|
||||
},
|
||||
{
|
||||
testName: "New Code with valid PKCE",
|
||||
clientID: "test",
|
||||
requestType: "POST",
|
||||
scopes: []string{"openid", "profile", "email"},
|
||||
codeChallengeMethod: "S256",
|
||||
expectedResponseCode: http.StatusOK,
|
||||
expectedContentType: "application/json",
|
||||
},
|
||||
{
|
||||
testName: "Invalid code challenge method",
|
||||
clientID: "test",
|
||||
requestType: "POST",
|
||||
codeChallengeMethod: "invalid",
|
||||
scopes: []string{"openid", "profile", "email"},
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
expectedContentType: "application/json",
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
@@ -92,6 +111,7 @@ func TestHandleDeviceCode(t *testing.T) {
|
||||
|
||||
data := url.Values{}
|
||||
data.Set("client_id", tc.clientID)
|
||||
data.Set("code_challenge_method", tc.codeChallengeMethod)
|
||||
for _, scope := range tc.scopes {
|
||||
data.Add("scope", scope)
|
||||
}
|
||||
@@ -401,6 +421,13 @@ func TestDeviceTokenResponse(t *testing.T) {
|
||||
|
||||
now := func() time.Time { return t0 }
|
||||
|
||||
// Base PKCE values
|
||||
// base64-urlencoded, sha256 digest of code_verifier
|
||||
codeChallenge := "L7ZqsT_zNwvrH8E7J0CqPHx1wgBaFiaE-fAZcKUUAbc"
|
||||
codeChallengeMethod := "S256"
|
||||
// "random" string between 43 & 128 ASCII characters
|
||||
codeVerifier := "66114650f56cc45dee7ee03c49f048ddf9aa53cbf5b09985832fa4f790ff2604"
|
||||
|
||||
baseDeviceRequest := storage.DeviceRequest{
|
||||
UserCode: "ABCD-WXYZ",
|
||||
DeviceCode: "foo",
|
||||
@@ -415,6 +442,7 @@ func TestDeviceTokenResponse(t *testing.T) {
|
||||
testDeviceToken storage.DeviceToken
|
||||
testGrantType string
|
||||
testDeviceCode string
|
||||
testCodeVerifier string
|
||||
expectedServerResponse string
|
||||
expectedResponseCode int
|
||||
}{
|
||||
@@ -524,6 +552,101 @@ func TestDeviceTokenResponse(t *testing.T) {
|
||||
expectedServerResponse: "{\"access_token\": \"foobar\"}",
|
||||
expectedResponseCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
testName: "Successful Exchange with PKCE",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: codeVerifier,
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: "{\"access_token\": \"foobar\"}",
|
||||
expectedResponseCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
testName: "Test Exchange started with PKCE but without verifier provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidGrant,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
testName: "Test Exchange not started with PKCE but verifier provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: codeVerifier,
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidRequest,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
testName: "Test with PKCE but incorrect verifier provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: codeChallenge,
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: "invalid",
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidGrant,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
testName: "Test with PKCE but incorrect challenge provided",
|
||||
testDeviceToken: storage.DeviceToken{
|
||||
DeviceCode: "foo",
|
||||
Status: deviceTokenComplete,
|
||||
Token: "{\"access_token\": \"foobar\"}",
|
||||
Expiry: now().Add(5 * time.Minute),
|
||||
LastRequestTime: time.Time{},
|
||||
PollIntervalSeconds: 0,
|
||||
PKCE: storage.PKCE{
|
||||
CodeChallenge: "invalid",
|
||||
CodeChallengeMethod: codeChallengeMethod,
|
||||
},
|
||||
},
|
||||
testDeviceCode: "foo",
|
||||
testCodeVerifier: codeVerifier,
|
||||
testDeviceRequest: baseDeviceRequest,
|
||||
expectedServerResponse: errInvalidGrant,
|
||||
expectedResponseCode: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.testName, func(t *testing.T) {
|
||||
@@ -558,6 +681,9 @@ func TestDeviceTokenResponse(t *testing.T) {
|
||||
}
|
||||
data.Set("grant_type", grantType)
|
||||
data.Set("device_code", tc.testDeviceCode)
|
||||
if tc.testCodeVerifier != "" {
|
||||
data.Set("code_verifier", tc.testCodeVerifier)
|
||||
}
|
||||
req, _ := http.NewRequest("POST", u.String(), bytes.NewBufferString(data.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user