Addressing PR feedback
store issuer and subject in storage for refresh Clean up some constants Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
parent
f2d2144932
commit
2958461970
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package oidcupstreamwatcher implements a controller which watches OIDCIdentityProviders.
|
// Package oidcupstreamwatcher implements a controller which watches OIDCIdentityProviders.
|
||||||
@ -499,7 +499,7 @@ func validateHTTPSURL(maybeHTTPSURL, endpointType, reason string) (*url.URL, *v1
|
|||||||
Type: typeOIDCDiscoverySucceeded,
|
Type: typeOIDCDiscoverySucceeded,
|
||||||
Status: v1alpha1.ConditionFalse,
|
Status: v1alpha1.ConditionFalse,
|
||||||
Reason: reason,
|
Reason: reason,
|
||||||
Message: fmt.Sprintf(`%s URL scheme must be "https", not %q`, endpointType, parsedURL.Scheme),
|
Message: fmt.Sprintf(`%s URL '%s' must have "https" scheme, not %q`, endpointType, maybeHTTPSURL, parsedURL.Scheme),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(parsedURL.Query()) != 0 || parsedURL.Fragment != "" {
|
if len(parsedURL.Query()) != 0 || parsedURL.Fragment != "" {
|
||||||
@ -507,7 +507,7 @@ func validateHTTPSURL(maybeHTTPSURL, endpointType, reason string) (*url.URL, *v1
|
|||||||
Type: typeOIDCDiscoverySucceeded,
|
Type: typeOIDCDiscoverySucceeded,
|
||||||
Status: v1alpha1.ConditionFalse,
|
Status: v1alpha1.ConditionFalse,
|
||||||
Reason: reason,
|
Reason: reason,
|
||||||
Message: fmt.Sprintf(`%s URL cannot contain query or fragment component`, endpointType),
|
Message: fmt.Sprintf(`%s URL '%s' cannot contain query or fragment component`, endpointType, maybeHTTPSURL),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parsedURL, nil
|
return parsedURL, nil
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package oidcupstreamwatcher
|
package oidcupstreamwatcher
|
||||||
@ -457,9 +457,9 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="issuer URL scheme must be \"https\", not \"http\"" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="issuer URL '` + strings.Replace(testIssuerURL, "https", "http", 1) + `' must have \"https\" scheme, not \"http\"" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="issuer URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="issuer URL '` + strings.Replace(testIssuerURL, "https", "http", 1) + `' must have \"https\" scheme, not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -480,7 +480,7 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "Unreachable",
|
Reason: "Unreachable",
|
||||||
Message: `issuer URL scheme must be "https", not "http"`,
|
Message: `issuer URL '` + strings.Replace(testIssuerURL, "https", "http", 1) + `' must have "https" scheme, not "http"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -503,9 +503,9 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="issuer URL cannot contain query or fragment component" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="issuer URL '` + testIssuerURL + "?sub=foo" + `' cannot contain query or fragment component" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="issuer URL cannot contain query or fragment component" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="issuer URL '` + testIssuerURL + "?sub=foo" + `' cannot contain query or fragment component" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -526,7 +526,7 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "Unreachable",
|
Reason: "Unreachable",
|
||||||
Message: `issuer URL cannot contain query or fragment component`,
|
Message: `issuer URL '` + testIssuerURL + "?sub=foo" + `' cannot contain query or fragment component`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -549,9 +549,9 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="issuer URL cannot contain query or fragment component" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="issuer URL '` + testIssuerURL + "#fragment" + `' cannot contain query or fragment component" "reason"="Unreachable" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="issuer URL cannot contain query or fragment component" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="issuer URL '` + testIssuerURL + "#fragment" + `' cannot contain query or fragment component" "name"="test-name" "namespace"="test-namespace" "reason"="Unreachable" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -572,7 +572,7 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "Unreachable",
|
Reason: "Unreachable",
|
||||||
Message: `issuer URL cannot contain query or fragment component`,
|
Message: `issuer URL '` + testIssuerURL + "#fragment" + `' cannot contain query or fragment component`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -739,9 +739,9 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="authorization endpoint URL 'http://example.com/authorize' must have \"https\" scheme, not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="authorization endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="authorization endpoint URL 'http://example.com/authorize' must have \"https\" scheme, not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -762,7 +762,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "InvalidResponse",
|
Reason: "InvalidResponse",
|
||||||
Message: `authorization endpoint URL scheme must be "https", not "http"`,
|
Message: `authorization endpoint URL 'http://example.com/authorize' must have "https" scheme, not "http"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -786,9 +786,9 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="revocation endpoint URL scheme must be \"https\", not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="revocation endpoint URL 'http://example.com/revoke' must have \"https\" scheme, not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="revocation endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="revocation endpoint URL 'http://example.com/revoke' must have \"https\" scheme, not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -809,7 +809,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "InvalidResponse",
|
Reason: "InvalidResponse",
|
||||||
Message: `revocation endpoint URL scheme must be "https", not "http"`,
|
Message: `revocation endpoint URL 'http://example.com/revoke' must have "https" scheme, not "http"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -833,9 +833,9 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="token endpoint URL scheme must be \"https\", not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="token endpoint URL 'http://example.com/token' must have \"https\" scheme, not \"http\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="token endpoint URL scheme must be \"https\", not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="token endpoint URL 'http://example.com/token' must have \"https\" scheme, not \"http\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -856,7 +856,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "InvalidResponse",
|
Reason: "InvalidResponse",
|
||||||
Message: `token endpoint URL scheme must be "https", not "http"`,
|
Message: `token endpoint URL 'http://example.com/token' must have "https" scheme, not "http"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -880,9 +880,9 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="token endpoint URL scheme must be \"https\", not \"\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="token endpoint URL '' must have \"https\" scheme, not \"\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="token endpoint URL scheme must be \"https\", not \"\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="token endpoint URL '' must have \"https\" scheme, not \"\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -903,7 +903,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "InvalidResponse",
|
Reason: "InvalidResponse",
|
||||||
Message: `token endpoint URL scheme must be "https", not ""`,
|
Message: `token endpoint URL '' must have "https" scheme, not ""`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -927,9 +927,9 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantLogs: []string{
|
wantLogs: []string{
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="loaded client credentials" "reason"="Success" "status"="True" "type"="ClientCredentialsValid"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="authorization endpoint URL scheme must be \"https\", not \"\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="authorization endpoint URL '' must have \"https\" scheme, not \"\"" "reason"="InvalidResponse" "status"="False" "type"="OIDCDiscoverySucceeded"`,
|
||||||
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
`oidc-upstream-observer "level"=0 "msg"="updated condition" "name"="test-name" "namespace"="test-namespace" "message"="additionalAuthorizeParameters parameter names are allowed" "reason"="Success" "status"="True" "type"="AdditionalAuthorizeParametersValid"`,
|
||||||
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="authorization endpoint URL scheme must be \"https\", not \"\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
`oidc-upstream-observer "msg"="found failing condition" "error"="OIDCIdentityProvider has a failing condition" "message"="authorization endpoint URL '' must have \"https\" scheme, not \"\"" "name"="test-name" "namespace"="test-namespace" "reason"="InvalidResponse" "type"="OIDCDiscoverySucceeded"`,
|
||||||
},
|
},
|
||||||
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
wantResultingCache: []*oidctestutil.TestUpstreamOIDCIdentityProvider{},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
@ -950,7 +950,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
Status: "False",
|
Status: "False",
|
||||||
LastTransitionTime: now,
|
LastTransitionTime: now,
|
||||||
Reason: "InvalidResponse",
|
Reason: "InvalidResponse",
|
||||||
Message: `authorization endpoint URL scheme must be "https", not ""`,
|
Message: `authorization endpoint URL '' must have "https" scheme, not ""`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package accesstoken
|
package accesstoken
|
||||||
@ -53,7 +53,7 @@ func TestAccessTokenStorage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/access-token",
|
Type: "storage.pinniped.dev/access-token",
|
||||||
@ -122,7 +122,7 @@ func TestAccessTokenStorageRevocation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/access-token",
|
Type: "storage.pinniped.dev/access-token",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package authorizationcode
|
package authorizationcode
|
||||||
@ -370,29 +370,33 @@ const ExpectedAuthorizeCodeSessionJSONFromFuzzing = `{
|
|||||||
"providerName": "ʼn2ƋŢ觛ǂ焺nŐǛ",
|
"providerName": "ʼn2ƋŢ觛ǂ焺nŐǛ",
|
||||||
"providerType": "ɥ闣ʬ橳(ý綃ʃʚƟ覣k眐4",
|
"providerType": "ɥ闣ʬ橳(ý綃ʃʚƟ覣k眐4",
|
||||||
"oidc": {
|
"oidc": {
|
||||||
"upstreamRefreshToken": "tC嵽痊w"
|
"upstreamRefreshToken": "tC嵽痊w",
|
||||||
|
"upstreamSubject": "a紽ǒ|鰽ŋ猊I",
|
||||||
|
"upstreamIssuer": "妬\u003e6鉢緋uƴŤȱʀ"
|
||||||
},
|
},
|
||||||
"ldap": {
|
"ldap": {
|
||||||
"userDN": "Ź榨Q|ôɵt毇妬\u003e6鉢緋",
|
"userDN": "Â?墖\u003cƬb獭潜Ʃ饾k|鬌R蜚蠣",
|
||||||
"extraRefreshAttributes": {
|
"extraRefreshAttributes": {
|
||||||
"ď逳鞪?3)藵睋邔\u0026Ű惫蜀Ģ¡圔": "墀jMʥ",
|
"ȱ藚ɏ¬Ê蒭堜]ȗ韚ʫ": "鷞aŚB碠k9帴ʘ赱"
|
||||||
"ƍ蛊ʚ£:設虝27": "b獭潜Ʃ饾k|鬌R蜚蠣麹概",
|
|
||||||
"藚ɏ¬Ê蒭堜]ȗ韚ʫ": "鷞aŚB碠k9帴ʘ赱"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"activedirectory": {
|
"activedirectory": {
|
||||||
"userDN": "0D餹sêĝɓ",
|
"userDN": "瑹xȢ~1Įx欼笝?úT妼",
|
||||||
"extraRefreshAttributes": {
|
"extraRefreshAttributes": {
|
||||||
"摱ì": "bEǎ儯惝Io"
|
"iYn": "麹Œ颛",
|
||||||
|
"İ\u003e×1飞O+î艔垎0OƉǢIȽ齤士": "ȐĨf跞@)¿,ɭS隑ip偶"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requestedAudience": [
|
"requestedAudience": [
|
||||||
"Ł"
|
"應,Ɣ鬅X¤",
|
||||||
|
"¤.岵骘胲ƤkǦ"
|
||||||
],
|
],
|
||||||
"grantedAudience": [
|
"grantedAudience": [
|
||||||
"r"
|
"鸖I¶媁y衑拁Ȃ",
|
||||||
|
"社Vƅȭǝ*擦28Dž 甍 ć",
|
||||||
|
"bņ抰蛖a³2ʫ承dʬ)ġ,TÀqy_"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"version": "2"
|
"version": "2"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package authorizationcode
|
package authorizationcode
|
||||||
@ -65,7 +65,7 @@ func TestAuthorizationCodeStorage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"active":true,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"active":true,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/authcode",
|
Type: "storage.pinniped.dev/authcode",
|
||||||
@ -84,7 +84,7 @@ func TestAuthorizationCodeStorage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"active":false,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"active":false,"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/authcode",
|
Type: "storage.pinniped.dev/authcode",
|
||||||
@ -389,6 +389,7 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
|
|||||||
validSessionJSONBytes, err := json.MarshalIndent(validSession, "", "\t")
|
validSessionJSONBytes, err := json.MarshalIndent(validSession, "", "\t")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authorizeCodeSessionJSONFromFuzzing := string(validSessionJSONBytes)
|
authorizeCodeSessionJSONFromFuzzing := string(validSessionJSONBytes)
|
||||||
|
t.Log(authorizeCodeSessionJSONFromFuzzing)
|
||||||
|
|
||||||
// the fuzzed session and storage session should have identical JSON
|
// the fuzzed session and storage session should have identical JSON
|
||||||
require.JSONEq(t, authorizeCodeSessionJSONFromFuzzing, authorizeCodeSessionJSONFromStorage)
|
require.JSONEq(t, authorizeCodeSessionJSONFromFuzzing, authorizeCodeSessionJSONFromStorage)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package openidconnect
|
package openidconnect
|
||||||
@ -52,7 +52,7 @@ func TestOpenIdConnectStorage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/oidc",
|
Type: "storage.pinniped.dev/oidc",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package pkce
|
package pkce
|
||||||
@ -52,7 +52,7 @@ func TestPKCEStorage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/pkce",
|
Type: "storage.pinniped.dev/pkce",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package refreshtoken
|
package refreshtoken
|
||||||
@ -52,7 +52,7 @@ func TestRefreshTokenStorage(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/refresh-token",
|
Type: "storage.pinniped.dev/refresh-token",
|
||||||
@ -122,7 +122,7 @@ func TestRefreshTokenStorageRevocation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
"pinniped-storage-data": []byte(`{"request":{"id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client":{"id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form":{"key":["val"]},"session":{"fosite":{"Claims":null,"Headers":null,"ExpiresAt":null,"Username":"snorlax","Subject":"panda"},"custom":{"providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","oidc":{"upstreamRefreshToken":"fake-upstream-refresh-token","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"2"}`),
|
||||||
"pinniped-storage-version": []byte("1"),
|
"pinniped-storage-version": []byte("1"),
|
||||||
},
|
},
|
||||||
Type: "storage.pinniped.dev/refresh-token",
|
Type: "storage.pinniped.dev/refresh-token",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package auth provides a handler for the OIDC authorization endpoint.
|
// Package auth provides a handler for the OIDC authorization endpoint.
|
||||||
@ -191,6 +191,20 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
|||||||
fosite.ErrAccessDenied.WithHintf("Reason: %s.", err.Error()), true,
|
fosite.ErrAccessDenied.WithHintf("Reason: %s.", err.Error()), true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
upstreamSubject, err := downstreamsession.ExtractStringClaimValue(oidc.IDTokenSubjectClaim, oidcUpstream.GetName(), token.IDToken.Claims)
|
||||||
|
if err != nil {
|
||||||
|
// Return a user-friendly error for this case which is entirely within our control.
|
||||||
|
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||||
|
fosite.ErrAccessDenied.WithHintf("Reason: %s.", err.Error()), true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
upstreamIssuer, err := downstreamsession.ExtractStringClaimValue(oidc.IDTokenIssuerClaim, oidcUpstream.GetName(), token.IDToken.Claims)
|
||||||
|
if err != nil {
|
||||||
|
// Return a user-friendly error for this case which is entirely within our control.
|
||||||
|
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||||
|
fosite.ErrAccessDenied.WithHintf("Reason: %s.", err.Error()), true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
customSessionData := &psession.CustomSessionData{
|
customSessionData := &psession.CustomSessionData{
|
||||||
ProviderUID: oidcUpstream.GetResourceUID(),
|
ProviderUID: oidcUpstream.GetResourceUID(),
|
||||||
@ -198,6 +212,8 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
|||||||
ProviderType: psession.ProviderTypeOIDC,
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
OIDC: &psession.OIDCSessionData{
|
OIDC: &psession.OIDCSessionData{
|
||||||
UpstreamRefreshToken: token.RefreshToken.Token,
|
UpstreamRefreshToken: token.RefreshToken.Token,
|
||||||
|
UpstreamIssuer: upstreamIssuer,
|
||||||
|
UpstreamSubject: upstreamSubject,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return makeDownstreamSessionAndReturnAuthcodeRedirect(r, w, oauthHelper, authorizeRequester, subject, username, groups, customSessionData)
|
return makeDownstreamSessionAndReturnAuthcodeRedirect(r, w, oauthHelper, authorizeRequester, subject, username, groups, customSessionData)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package auth
|
package auth
|
||||||
@ -470,6 +470,8 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
ProviderType: psession.ProviderTypeOIDC,
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
OIDC: &psession.OIDCSessionData{
|
OIDC: &psession.OIDCSessionData{
|
||||||
UpstreamRefreshToken: oidcPasswordGrantUpstreamRefreshToken,
|
UpstreamRefreshToken: oidcPasswordGrantUpstreamRefreshToken,
|
||||||
|
UpstreamSubject: oidcUpstreamSubject,
|
||||||
|
UpstreamIssuer: oidcUpstreamIssuer,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package callback provides a handler for the OIDC callback endpoint.
|
// Package callback provides a handler for the OIDC callback endpoint.
|
||||||
@ -83,12 +83,23 @@ func NewHandler(
|
|||||||
return httperr.Wrap(http.StatusUnprocessableEntity, err.Error(), err)
|
return httperr.Wrap(http.StatusUnprocessableEntity, err.Error(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upstreamSubject, err := downstreamsession.ExtractStringClaimValue(oidc.IDTokenSubjectClaim, upstreamIDPConfig.GetName(), token.IDToken.Claims)
|
||||||
|
if err != nil {
|
||||||
|
return httperr.Wrap(http.StatusUnprocessableEntity, err.Error(), err)
|
||||||
|
}
|
||||||
|
upstreamIssuer, err := downstreamsession.ExtractStringClaimValue(oidc.IDTokenIssuerClaim, upstreamIDPConfig.GetName(), token.IDToken.Claims)
|
||||||
|
if err != nil {
|
||||||
|
return httperr.Wrap(http.StatusUnprocessableEntity, err.Error(), err)
|
||||||
|
}
|
||||||
|
|
||||||
openIDSession := downstreamsession.MakeDownstreamSession(subject, username, groups, &psession.CustomSessionData{
|
openIDSession := downstreamsession.MakeDownstreamSession(subject, username, groups, &psession.CustomSessionData{
|
||||||
ProviderUID: upstreamIDPConfig.GetResourceUID(),
|
ProviderUID: upstreamIDPConfig.GetResourceUID(),
|
||||||
ProviderName: upstreamIDPConfig.GetName(),
|
ProviderName: upstreamIDPConfig.GetName(),
|
||||||
ProviderType: psession.ProviderTypeOIDC,
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
OIDC: &psession.OIDCSessionData{
|
OIDC: &psession.OIDCSessionData{
|
||||||
UpstreamRefreshToken: token.RefreshToken.Token,
|
UpstreamRefreshToken: token.RefreshToken.Token,
|
||||||
|
UpstreamSubject: upstreamSubject,
|
||||||
|
UpstreamIssuer: upstreamIssuer,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package callback
|
package callback
|
||||||
@ -77,7 +77,11 @@ var (
|
|||||||
ProviderUID: happyUpstreamIDPResourceUID,
|
ProviderUID: happyUpstreamIDPResourceUID,
|
||||||
ProviderName: happyUpstreamIDPName,
|
ProviderName: happyUpstreamIDPName,
|
||||||
ProviderType: psession.ProviderTypeOIDC,
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
OIDC: &psession.OIDCSessionData{UpstreamRefreshToken: oidcUpstreamRefreshToken},
|
OIDC: &psession.OIDCSessionData{
|
||||||
|
UpstreamRefreshToken: oidcUpstreamRefreshToken,
|
||||||
|
UpstreamIssuer: oidcUpstreamIssuer,
|
||||||
|
UpstreamSubject: oidcUpstreamSubject,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package downstreamsession provides some shared helpers for creating downstream OIDC sessions.
|
// Package downstreamsession provides some shared helpers for creating downstream OIDC sessions.
|
||||||
@ -89,11 +89,11 @@ func getSubjectAndUsernameFromUpstreamIDToken(
|
|||||||
) (string, string, error) {
|
) (string, string, error) {
|
||||||
// The spec says the "sub" claim is only unique per issuer,
|
// The spec says the "sub" claim is only unique per issuer,
|
||||||
// so we will prepend the issuer string to make it globally unique.
|
// so we will prepend the issuer string to make it globally unique.
|
||||||
upstreamIssuer, err := extractStringClaimValue(oidc.IDTokenIssuerClaim, upstreamIDPConfig.GetName(), idTokenClaims)
|
upstreamIssuer, err := ExtractStringClaimValue(oidc.IDTokenIssuerClaim, upstreamIDPConfig.GetName(), idTokenClaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
upstreamSubject, err := extractStringClaimValue(oidc.IDTokenSubjectClaim, upstreamIDPConfig.GetName(), idTokenClaims)
|
upstreamSubject, err := ExtractStringClaimValue(oidc.IDTokenSubjectClaim, upstreamIDPConfig.GetName(), idTokenClaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ func getSubjectAndUsernameFromUpstreamIDToken(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
username, err := extractStringClaimValue(usernameClaimName, upstreamIDPConfig.GetName(), idTokenClaims)
|
username, err := ExtractStringClaimValue(usernameClaimName, upstreamIDPConfig.GetName(), idTokenClaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ func getSubjectAndUsernameFromUpstreamIDToken(
|
|||||||
return subject, username, nil
|
return subject, username, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractStringClaimValue(claimName string, upstreamIDPName string, idTokenClaims map[string]interface{}) (string, error) {
|
func ExtractStringClaimValue(claimName string, upstreamIDPName string, idTokenClaims map[string]interface{}) (string, error) {
|
||||||
value, ok := idTokenClaims[claimName]
|
value, ok := idTokenClaims[claimName]
|
||||||
if !ok {
|
if !ok {
|
||||||
plog.Warning(
|
plog.Warning(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package provider
|
package provider
|
||||||
@ -71,7 +71,7 @@ type UpstreamOIDCIdentityProviderI interface {
|
|||||||
// RevokeRefreshToken will attempt to revoke the given token, if the provider has a revocation endpoint.
|
// RevokeRefreshToken will attempt to revoke the given token, if the provider has a revocation endpoint.
|
||||||
RevokeRefreshToken(ctx context.Context, refreshToken string) error
|
RevokeRefreshToken(ctx context.Context, refreshToken string) error
|
||||||
|
|
||||||
// ValidateToken will validate the ID token. It will also merge the claims from the userinfo endpoint response
|
// ValidateTokenAndMergeWithUserInfo will validate the ID token. It will also merge the claims from the userinfo endpoint response
|
||||||
// into the ID token's claims, if the provider offers the userinfo endpoint. It returns the validated/updated
|
// into the ID token's claims, if the provider offers the userinfo endpoint. It returns the validated/updated
|
||||||
// tokens, or an error.
|
// tokens, or an error.
|
||||||
ValidateTokenAndMergeWithUserInfo(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce, requireIDToken bool) (*oidctypes.Token, error)
|
ValidateTokenAndMergeWithUserInfo(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce, requireIDToken bool) (*oidctypes.Token, error)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package token provides a handler for the OIDC token endpoint.
|
// Package token provides a handler for the OIDC token endpoint.
|
||||||
@ -17,7 +17,6 @@ import (
|
|||||||
"go.pinniped.dev/internal/oidc/provider"
|
"go.pinniped.dev/internal/oidc/provider"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/plog"
|
||||||
"go.pinniped.dev/internal/psession"
|
"go.pinniped.dev/internal/psession"
|
||||||
"go.pinniped.dev/internal/upstreamoidc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -138,29 +137,27 @@ func upstreamOIDCRefresh(ctx context.Context, session *psession.PinnipedSession,
|
|||||||
// if we have any claims at all, we better have a subject, and it better match the previous value.
|
// if we have any claims at all, we better have a subject, and it better match the previous value.
|
||||||
// but it's possible that we don't because both returning a new refresh token on refresh and having a userinfo
|
// but it's possible that we don't because both returning a new refresh token on refresh and having a userinfo
|
||||||
// endpoint are optional.
|
// endpoint are optional.
|
||||||
if len(validatedTokens.IDToken.Claims) != 0 {
|
if len(validatedTokens.IDToken.Claims) != 0 { //nolint:nestif
|
||||||
newSub := claims["sub"]
|
newSub, hasSub := getString(claims, oidc.IDTokenSubjectClaim)
|
||||||
oldDownstreamSubject := session.Fosite.Claims.Subject
|
if !hasSub {
|
||||||
oldIss, oldSub, err := upstreamoidc.ExtractUpstreamSubjectAndIssuerFromDownstream(oldDownstreamSubject)
|
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
||||||
if err != nil {
|
"Upstream refresh failed.").WithWrap(errors.New("subject in upstream refresh not found")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
||||||
return errorsx.WithStack(errUpstreamRefreshError.WithHintf("Upstream refresh failed.").
|
|
||||||
WithWrap(err).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
|
||||||
}
|
}
|
||||||
if oldSub != newSub {
|
if s.OIDC.UpstreamSubject != newSub {
|
||||||
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
||||||
"Upstream refresh failed.").WithWrap(errors.New("subject in upstream refresh does not match previous value")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
"Upstream refresh failed.").WithWrap(errors.New("subject in upstream refresh does not match previous value")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
||||||
}
|
}
|
||||||
usernameClaim := p.GetUsernameClaim()
|
usernameClaim := p.GetUsernameClaim()
|
||||||
newUsername := claims[usernameClaim]
|
newUsername, hasUsername := getString(claims, usernameClaim)
|
||||||
oldUsername := session.Fosite.Claims.Extra["username"]
|
oldUsername := session.Fosite.Claims.Extra[oidc.DownstreamUsernameClaim]
|
||||||
// its possible this won't be returned.
|
// its possible this won't be returned.
|
||||||
// but if it is, verify that it hasn't changed.
|
// but if it is, verify that it hasn't changed.
|
||||||
if newUsername != nil && oldUsername != newUsername {
|
if hasUsername && oldUsername != newUsername {
|
||||||
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
||||||
"Upstream refresh failed.").WithWrap(errors.New("username in upstream refresh does not match previous value")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
"Upstream refresh failed.").WithWrap(errors.New("username in upstream refresh does not match previous value")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
||||||
}
|
}
|
||||||
newIssuer := claims["iss"]
|
newIssuer, hasIssuer := getString(claims, oidc.IDTokenIssuerClaim)
|
||||||
if newIssuer != nil && oldIss != newIssuer {
|
if hasIssuer && s.OIDC.UpstreamIssuer != newIssuer {
|
||||||
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
return errorsx.WithStack(errUpstreamRefreshError.WithHintf(
|
||||||
"Upstream refresh failed.").WithWrap(errors.New("issuer in upstream refresh does not match previous value")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
"Upstream refresh failed.").WithWrap(errors.New("issuer in upstream refresh does not match previous value")).WithDebugf("provider name: %q, provider type: %q", s.ProviderName, s.ProviderType))
|
||||||
}
|
}
|
||||||
@ -178,6 +175,11 @@ func upstreamOIDCRefresh(ctx context.Context, session *psession.PinnipedSession,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getString(m map[string]interface{}, key string) (string, bool) {
|
||||||
|
val, ok := m[key].(string)
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
func findOIDCProviderByNameAndValidateUID(
|
func findOIDCProviderByNameAndValidateUID(
|
||||||
s *psession.CustomSessionData,
|
s *psession.CustomSessionData,
|
||||||
providerCache oidc.UpstreamIdentityProvidersLister,
|
providerCache oidc.UpstreamIdentityProvidersLister,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package token
|
package token
|
||||||
@ -57,6 +57,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
goodIssuer = "https://some-issuer.com"
|
goodIssuer = "https://some-issuer.com"
|
||||||
|
goodUpstreamSubject = "some-subject"
|
||||||
goodClient = "pinniped-cli"
|
goodClient = "pinniped-cli"
|
||||||
goodRedirectURI = "http://127.0.0.1/callback"
|
goodRedirectURI = "http://127.0.0.1/callback"
|
||||||
goodPKCECodeVerifier = "some-pkce-verifier-that-must-be-at-least-43-characters-to-meet-entropy-requirements"
|
goodPKCECodeVerifier = "some-pkce-verifier-that-must-be-at-least-43-characters-to-meet-entropy-requirements"
|
||||||
@ -910,6 +911,8 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
ProviderType: oidcUpstreamType,
|
ProviderType: oidcUpstreamType,
|
||||||
OIDC: &psession.OIDCSessionData{
|
OIDC: &psession.OIDCSessionData{
|
||||||
UpstreamRefreshToken: oidcUpstreamInitialRefreshToken,
|
UpstreamRefreshToken: oidcUpstreamInitialRefreshToken,
|
||||||
|
UpstreamSubject: goodUpstreamSubject,
|
||||||
|
UpstreamIssuer: goodIssuer,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1049,7 +1052,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
||||||
@ -1072,7 +1075,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"some-claim": "some-value",
|
"some-claim": "some-value",
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
"username-claim": goodUsername,
|
"username-claim": goodUsername,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1146,7 +1149,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDTokenWithoutRefreshToken()).Build()),
|
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDTokenWithoutRefreshToken()).Build()),
|
||||||
@ -1168,7 +1171,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
||||||
@ -1193,7 +1196,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
||||||
@ -1229,7 +1232,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
upstreamOIDCIdentityProviderBuilder().WithValidatedTokens(&oidctypes.Token{
|
||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
}).WithRefreshedTokens(refreshedUpstreamTokensWithIDAndRefreshTokens()).Build()),
|
||||||
@ -1681,7 +1684,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"some-claim": "some-value",
|
"some-claim": "some-value",
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
"username-claim": "some-changed-username",
|
"username-claim": "some-changed-username",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1712,7 +1715,7 @@ func TestRefreshGrant(t *testing.T) {
|
|||||||
IDToken: &oidctypes.IDToken{
|
IDToken: &oidctypes.IDToken{
|
||||||
Claims: map[string]interface{}{
|
Claims: map[string]interface{}{
|
||||||
"some-claim": "some-value",
|
"some-claim": "some-value",
|
||||||
"sub": "some-subject",
|
"sub": goodUpstreamSubject,
|
||||||
"iss": "some-changed-issuer",
|
"iss": "some-changed-issuer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package psession
|
package psession
|
||||||
@ -62,6 +62,8 @@ const (
|
|||||||
// OIDCSessionData is the additional data needed by Pinniped when the upstream IDP is an OIDC provider.
|
// OIDCSessionData is the additional data needed by Pinniped when the upstream IDP is an OIDC provider.
|
||||||
type OIDCSessionData struct {
|
type OIDCSessionData struct {
|
||||||
UpstreamRefreshToken string `json:"upstreamRefreshToken"`
|
UpstreamRefreshToken string `json:"upstreamRefreshToken"`
|
||||||
|
UpstreamSubject string `json:"upstreamSubject"`
|
||||||
|
UpstreamIssuer string `json:"upstreamIssuer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAPSessionData is the additional data needed by Pinniped when the upstream IDP is an LDAP provider.
|
// LDAPSessionData is the additional data needed by Pinniped when the upstream IDP is an LDAP provider.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package testutil
|
package testutil
|
||||||
@ -29,6 +29,8 @@ func NewFakePinnipedSession() *psession.PinnipedSession {
|
|||||||
ProviderName: "fake-provider-name",
|
ProviderName: "fake-provider-name",
|
||||||
OIDC: &psession.OIDCSessionData{
|
OIDC: &psession.OIDCSessionData{
|
||||||
UpstreamRefreshToken: "fake-upstream-refresh-token",
|
UpstreamRefreshToken: "fake-upstream-refresh-token",
|
||||||
|
UpstreamSubject: "some-subject",
|
||||||
|
UpstreamIssuer: "some-issuer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// Package upstreamoidc implements an abstraction of upstream OIDC provider interactions.
|
// Package upstreamoidc implements an abstraction of upstream OIDC provider interactions.
|
||||||
@ -7,7 +7,6 @@ package upstreamoidc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -238,53 +237,19 @@ func (p *ProviderConfig) tryRevokeRefreshToken(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExtractUpstreamSubjectAndIssuerFromDownstream(downstreamSubject string) (string, string, error) {
|
|
||||||
if !strings.Contains(downstreamSubject, "?sub=") {
|
|
||||||
return "", "", errors.New("downstream subject did not contain original upstream subject")
|
|
||||||
}
|
|
||||||
split := strings.SplitN(downstreamSubject, "?sub=", 2)
|
|
||||||
iss := split[0]
|
|
||||||
sub := split[1]
|
|
||||||
if iss == "" || sub == "" {
|
|
||||||
return "", "", errors.New("downstream subject was malformed")
|
|
||||||
}
|
|
||||||
return split[0], split[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateTokenAndMergeWithUserInfo will validate the ID token. It will also merge the claims from the userinfo endpoint response,
|
// ValidateTokenAndMergeWithUserInfo will validate the ID token. It will also merge the claims from the userinfo endpoint response,
|
||||||
// if the provider offers the userinfo endpoint.
|
// if the provider offers the userinfo endpoint.
|
||||||
func (p *ProviderConfig) ValidateTokenAndMergeWithUserInfo(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce, requireIDToken bool) (*oidctypes.Token, error) {
|
func (p *ProviderConfig) ValidateTokenAndMergeWithUserInfo(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce, requireIDToken bool) (*oidctypes.Token, error) {
|
||||||
var validatedClaims = make(map[string]interface{})
|
var validatedClaims = make(map[string]interface{})
|
||||||
|
|
||||||
idTok, hasIDTok := tok.Extra("id_token").(string)
|
|
||||||
var idTokenExpiry time.Time
|
var idTokenExpiry time.Time
|
||||||
// if we require the id token, make sure we have it.
|
// if we require the id token, make sure we have it.
|
||||||
// also, if it exists but wasn't required, still make sure it passes these checks.
|
// also, if it exists but wasn't required, still make sure it passes these checks.
|
||||||
// nolint:nestif
|
idTokenExpiry, idTok, err := p.validateIDToken(ctx, tok, expectedIDTokenNonce, validatedClaims, requireIDToken)
|
||||||
if hasIDTok || requireIDToken {
|
|
||||||
if !hasIDTok {
|
|
||||||
return nil, httperr.New(http.StatusBadRequest, "received response missing ID token")
|
|
||||||
}
|
|
||||||
validated, err := p.Provider.Verifier(&coreosoidc.Config{ClientID: p.GetClientID()}).Verify(coreosoidc.ClientContext(ctx, p.Client), idTok)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, httperr.Wrap(http.StatusBadRequest, "received invalid ID token", err)
|
return nil, err
|
||||||
}
|
|
||||||
if validated.AccessTokenHash != "" {
|
|
||||||
if err := validated.VerifyAccessToken(tok.AccessToken); err != nil {
|
|
||||||
return nil, httperr.Wrap(http.StatusBadRequest, "received invalid ID token", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if expectedIDTokenNonce != "" {
|
|
||||||
if err := expectedIDTokenNonce.Validate(validated); err != nil {
|
|
||||||
return nil, httperr.Wrap(http.StatusBadRequest, "received ID token with invalid nonce", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := validated.Claims(&validatedClaims); err != nil {
|
|
||||||
return nil, httperr.Wrap(http.StatusInternalServerError, "could not unmarshal id token claims", err)
|
|
||||||
}
|
|
||||||
maybeLogClaims("claims from ID token", p.Name, validatedClaims)
|
|
||||||
idTokenExpiry = validated.Expiry // keep track of the id token expiry if we have an id token. Otherwise, it'll just be the zero value.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idTokenSubject, _ := validatedClaims[oidc.IDTokenSubjectClaim].(string)
|
idTokenSubject, _ := validatedClaims[oidc.IDTokenSubjectClaim].(string)
|
||||||
|
|
||||||
if len(idTokenSubject) > 0 || !requireIDToken {
|
if len(idTokenSubject) > 0 || !requireIDToken {
|
||||||
@ -310,10 +275,42 @@ func (p *ProviderConfig) ValidateTokenAndMergeWithUserInfo(ctx context.Context,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProviderConfig) validateIDToken(ctx context.Context, tok *oauth2.Token, expectedIDTokenNonce nonce.Nonce, validatedClaims map[string]interface{}, requireIDToken bool) (time.Time, string, error) {
|
||||||
|
idTok, hasIDTok := tok.Extra("id_token").(string)
|
||||||
|
if !hasIDTok && !requireIDToken {
|
||||||
|
return time.Time{}, "", nil // exit early
|
||||||
|
}
|
||||||
|
|
||||||
|
var idTokenExpiry time.Time
|
||||||
|
if !hasIDTok {
|
||||||
|
return time.Time{}, "", httperr.New(http.StatusBadRequest, "received response missing ID token")
|
||||||
|
}
|
||||||
|
validated, err := p.Provider.Verifier(&coreosoidc.Config{ClientID: p.GetClientID()}).Verify(coreosoidc.ClientContext(ctx, p.Client), idTok)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, "", httperr.Wrap(http.StatusBadRequest, "received invalid ID token", err)
|
||||||
|
}
|
||||||
|
if validated.AccessTokenHash != "" {
|
||||||
|
if err := validated.VerifyAccessToken(tok.AccessToken); err != nil {
|
||||||
|
return time.Time{}, "", httperr.Wrap(http.StatusBadRequest, "received invalid ID token", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if expectedIDTokenNonce != "" {
|
||||||
|
if err := expectedIDTokenNonce.Validate(validated); err != nil {
|
||||||
|
return time.Time{}, "", httperr.Wrap(http.StatusBadRequest, "received ID token with invalid nonce", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := validated.Claims(&validatedClaims); err != nil {
|
||||||
|
return time.Time{}, "", httperr.Wrap(http.StatusInternalServerError, "could not unmarshal id token claims", err)
|
||||||
|
}
|
||||||
|
maybeLogClaims("claims from ID token", p.Name, validatedClaims)
|
||||||
|
idTokenExpiry = validated.Expiry // keep track of the id token expiry if we have an id token. Otherwise, it'll just be the zero value.
|
||||||
|
return idTokenExpiry, idTok, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ProviderConfig) maybeFetchUserInfoAndMergeClaims(ctx context.Context, tok *oauth2.Token, claims map[string]interface{}, requireIDToken bool) error {
|
func (p *ProviderConfig) maybeFetchUserInfoAndMergeClaims(ctx context.Context, tok *oauth2.Token, claims map[string]interface{}, requireIDToken bool) error {
|
||||||
idTokenSubject, _ := claims[oidc.IDTokenSubjectClaim].(string)
|
idTokenSubject, _ := claims[oidc.IDTokenSubjectClaim].(string)
|
||||||
|
|
||||||
userInfo, err := p.fetchUserInfo(ctx, tok)
|
userInfo, err := p.maybeFetchUserInfo(ctx, tok)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -356,7 +353,7 @@ func (p *ProviderConfig) maybeFetchUserInfoAndMergeClaims(ctx context.Context, t
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProviderConfig) fetchUserInfo(ctx context.Context, tok *oauth2.Token) (*coreosoidc.UserInfo, error) {
|
func (p *ProviderConfig) maybeFetchUserInfo(ctx context.Context, tok *oauth2.Token) (*coreosoidc.UserInfo, error) {
|
||||||
providerJSON := &struct {
|
providerJSON := &struct {
|
||||||
UserInfoURL string `json:"userinfo_endpoint"`
|
UserInfoURL string `json:"userinfo_endpoint"`
|
||||||
}{}
|
}{}
|
||||||
|
@ -910,63 +910,6 @@ func TestProviderConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ExtractUpstreamSubjectAndIssuerFromDownstream", func(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
downstreamSubject string
|
|
||||||
wantUpstreamSubject string
|
|
||||||
wantUpstreamIssuer string
|
|
||||||
wantErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "happy path",
|
|
||||||
downstreamSubject: "https://some-issuer?sub=some-subject",
|
|
||||||
wantUpstreamSubject: "some-subject",
|
|
||||||
wantUpstreamIssuer: "https://some-issuer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "subject in a subject",
|
|
||||||
downstreamSubject: "https://some-other-issuer?sub=https://some-issuer?sub=some-subject",
|
|
||||||
wantUpstreamSubject: "https://some-issuer?sub=some-subject",
|
|
||||||
wantUpstreamIssuer: "https://some-other-issuer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "sub is empty string",
|
|
||||||
downstreamSubject: "https://some-issuer?sub=",
|
|
||||||
wantErr: "downstream subject was malformed",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "iss is empty string",
|
|
||||||
downstreamSubject: "?sub=some-subject",
|
|
||||||
wantErr: "downstream subject was malformed",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty string",
|
|
||||||
downstreamSubject: "",
|
|
||||||
wantErr: "downstream subject did not contain original upstream subject",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "doesn't contain sub=",
|
|
||||||
downstreamSubject: "something-invalid",
|
|
||||||
wantErr: "downstream subject did not contain original upstream subject",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
tt := tt
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
actualUpstreamIssuer, actualUpstreamSubject, err := ExtractUpstreamSubjectAndIssuerFromDownstream(tt.downstreamSubject)
|
|
||||||
if tt.wantErr != "" {
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Equal(t, tt.wantErr, err.Error())
|
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, tt.wantUpstreamSubject, actualUpstreamSubject)
|
|
||||||
require.Equal(t, tt.wantUpstreamIssuer, actualUpstreamIssuer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ExchangeAuthcodeAndValidateTokens", func(t *testing.T) {
|
t.Run("ExchangeAuthcodeAndValidateTokens", func(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
@ -87,8 +87,8 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
},
|
},
|
||||||
requestAuthorization: requestAuthorizationUsingBrowserAuthcodeFlow,
|
requestAuthorization: requestAuthorizationUsingBrowserAuthcodeFlow,
|
||||||
breakRefreshSessionData: func(t *testing.T, pinnipedSession *psession.PinnipedSession, _, _ string) {
|
breakRefreshSessionData: func(t *testing.T, pinnipedSession *psession.PinnipedSession, _, _ string) {
|
||||||
fositeSessionData := pinnipedSession.Fosite
|
pinnipedSessionData := pinnipedSession.Custom
|
||||||
fositeSessionData.Claims.Subject = "wrong-subject"
|
pinnipedSessionData.OIDC.UpstreamIssuer = "wrong-issuer"
|
||||||
},
|
},
|
||||||
// the ID token Subject should include the upstream user ID after the upstream issuer name
|
// the ID token Subject should include the upstream user ID after the upstream issuer name
|
||||||
wantDownstreamIDTokenSubjectToMatch: "^" + regexp.QuoteMeta(env.SupervisorUpstreamOIDC.Issuer+"?sub=") + ".+",
|
wantDownstreamIDTokenSubjectToMatch: "^" + regexp.QuoteMeta(env.SupervisorUpstreamOIDC.Issuer+"?sub=") + ".+",
|
||||||
|
Loading…
Reference in New Issue
Block a user