Require refresh tokens for upstream OIDC and save more session data
- Requiring refresh tokens to be returned from upstream OIDC idps - Storing refresh tokens (for oidc) and idp information (for all idps) in custom session data during authentication - Don't pass access=offline all the time
This commit is contained in:
parent
43244b6599
commit
1bd346cbeb
@ -302,6 +302,7 @@ func (c *activeDirectoryWatcherController) validateUpstream(ctx context.Context,
|
|||||||
|
|
||||||
config := &upstreamldap.ProviderConfig{
|
config := &upstreamldap.ProviderConfig{
|
||||||
Name: upstream.Name,
|
Name: upstream.Name,
|
||||||
|
ResourceUID: upstream.UID,
|
||||||
Host: spec.Host,
|
Host: spec.Host,
|
||||||
UserSearch: upstreamldap.UserSearchConfig{
|
UserSearch: upstreamldap.UserSearchConfig{
|
||||||
Base: spec.UserSearch.Base,
|
Base: spec.UserSearch.Base,
|
||||||
|
@ -150,6 +150,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
testNamespace = "test-namespace"
|
testNamespace = "test-namespace"
|
||||||
|
testResourceUID = "test-uid"
|
||||||
testName = "test-name"
|
testName = "test-name"
|
||||||
testSecretName = "test-bind-secret"
|
testSecretName = "test-bind-secret"
|
||||||
testBindUsername = "test-bind-username"
|
testBindUsername = "test-bind-username"
|
||||||
@ -172,7 +173,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
testCABundleBase64Encoded := base64.StdEncoding.EncodeToString(testCABundle)
|
testCABundleBase64Encoded := base64.StdEncoding.EncodeToString(testCABundle)
|
||||||
|
|
||||||
validUpstream := &v1alpha1.ActiveDirectoryIdentityProvider{
|
validUpstream := &v1alpha1.ActiveDirectoryIdentityProvider{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: testName, Namespace: testNamespace, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Name: testName, Namespace: testNamespace, Generation: 1234, UID: testResourceUID},
|
||||||
Spec: v1alpha1.ActiveDirectoryIdentityProviderSpec{
|
Spec: v1alpha1.ActiveDirectoryIdentityProviderSpec{
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded},
|
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded},
|
||||||
@ -202,6 +203,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
|
|
||||||
providerConfigForValidUpstreamWithTLS := &upstreamldap.ProviderConfig{
|
providerConfigForValidUpstreamWithTLS := &upstreamldap.ProviderConfig{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -364,7 +366,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -379,7 +381,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -407,7 +409,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -434,7 +436,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -460,7 +462,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -486,7 +488,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -517,6 +519,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: nil,
|
CABundle: nil,
|
||||||
@ -537,7 +540,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -572,6 +575,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: nil,
|
CABundle: nil,
|
||||||
@ -592,7 +596,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -630,6 +634,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: "ldap.example.com",
|
Host: "ldap.example.com",
|
||||||
ConnectionProtocol: upstreamldap.StartTLS, // successfully fell back to using StartTLS
|
ConnectionProtocol: upstreamldap.StartTLS, // successfully fell back to using StartTLS
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -650,7 +655,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -688,6 +693,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
// even though the connection test failed, still loads into the cache because it is treated like a warning
|
// even though the connection test failed, still loads into the cache because it is treated like a warning
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: "ldap.example.com:5678",
|
Host: "ldap.example.com:5678",
|
||||||
ConnectionProtocol: upstreamldap.TLS, // need to pick TLS or StartTLS to load into the cache when both fail, so choose TLS
|
ConnectionProtocol: upstreamldap.TLS, // need to pick TLS or StartTLS to load into the cache when both fail, so choose TLS
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -709,7 +715,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -745,6 +751,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: nil,
|
CABundle: nil,
|
||||||
@ -765,7 +772,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -779,6 +786,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
upstream.Name = "other-upstream"
|
upstream.Name = "other-upstream"
|
||||||
upstream.Generation = 42
|
upstream.Generation = 42
|
||||||
upstream.Spec.Bind.SecretName = "non-existent-secret"
|
upstream.Spec.Bind.SecretName = "non-existent-secret"
|
||||||
|
upstream.UID = "other-uid"
|
||||||
})},
|
})},
|
||||||
inputSecrets: []runtime.Object{validBindUserSecret("4242")},
|
inputSecrets: []runtime.Object{validBindUserSecret("4242")},
|
||||||
setupMocks: func(conn *mockldapconn.MockConn) {
|
setupMocks: func(conn *mockldapconn.MockConn) {
|
||||||
@ -790,7 +798,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "other-upstream", Generation: 42},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "other-upstream", Generation: 42, UID: "other-uid"},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -807,7 +815,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -831,7 +839,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -872,6 +880,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -892,7 +901,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -928,7 +937,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -966,7 +975,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -995,6 +1004,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1015,7 +1025,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1045,6 +1055,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1065,7 +1076,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1100,7 +1111,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithStartTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithStartTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -1137,7 +1148,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -1175,7 +1186,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -1212,7 +1223,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -1243,6 +1254,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1264,7 +1276,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -1295,6 +1307,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1315,7 +1328,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1350,6 +1363,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1370,7 +1384,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1399,6 +1413,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1419,7 +1434,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1447,7 +1462,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1483,7 +1498,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1525,7 +1540,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1554,7 +1569,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -1594,6 +1609,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -1614,7 +1630,7 @@ func TestActiveDirectoryUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.ActiveDirectoryIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testResourceUID, Generation: 1234},
|
||||||
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
Status: v1alpha1.ActiveDirectoryIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
|
@ -227,6 +227,7 @@ func (c *ldapWatcherController) validateUpstream(ctx context.Context, upstream *
|
|||||||
|
|
||||||
config := &upstreamldap.ProviderConfig{
|
config := &upstreamldap.ProviderConfig{
|
||||||
Name: upstream.Name,
|
Name: upstream.Name,
|
||||||
|
ResourceUID: upstream.UID,
|
||||||
Host: spec.Host,
|
Host: spec.Host,
|
||||||
UserSearch: upstreamldap.UserSearchConfig{
|
UserSearch: upstreamldap.UserSearchConfig{
|
||||||
Base: spec.UserSearch.Base,
|
Base: spec.UserSearch.Base,
|
||||||
|
@ -150,6 +150,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
const (
|
const (
|
||||||
testNamespace = "test-namespace"
|
testNamespace = "test-namespace"
|
||||||
testName = "test-name"
|
testName = "test-name"
|
||||||
|
testResourceUID = "test-resource-uid"
|
||||||
testSecretName = "test-bind-secret"
|
testSecretName = "test-bind-secret"
|
||||||
testBindUsername = "test-bind-username"
|
testBindUsername = "test-bind-username"
|
||||||
testBindPassword = "test-bind-password"
|
testBindPassword = "test-bind-password"
|
||||||
@ -171,7 +172,12 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
testCABundleBase64Encoded := base64.StdEncoding.EncodeToString(testCABundle)
|
testCABundleBase64Encoded := base64.StdEncoding.EncodeToString(testCABundle)
|
||||||
|
|
||||||
validUpstream := &v1alpha1.LDAPIdentityProvider{
|
validUpstream := &v1alpha1.LDAPIdentityProvider{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: testName, Namespace: testNamespace, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testName,
|
||||||
|
Namespace: testNamespace,
|
||||||
|
Generation: 1234,
|
||||||
|
UID: testResourceUID,
|
||||||
|
},
|
||||||
Spec: v1alpha1.LDAPIdentityProviderSpec{
|
Spec: v1alpha1.LDAPIdentityProviderSpec{
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded},
|
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded},
|
||||||
@ -201,6 +207,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
|
|
||||||
providerConfigForValidUpstreamWithTLS := &upstreamldap.ProviderConfig{
|
providerConfigForValidUpstreamWithTLS := &upstreamldap.ProviderConfig{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -299,7 +306,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -320,7 +327,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -348,7 +355,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -375,7 +382,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -401,7 +408,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -427,7 +434,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
wantResultingCache: []*upstreamldap.ProviderConfig{},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -458,6 +465,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: nil,
|
CABundle: nil,
|
||||||
@ -477,7 +485,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -519,6 +527,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: "ldap.example.com",
|
Host: "ldap.example.com",
|
||||||
ConnectionProtocol: upstreamldap.StartTLS, // successfully fell back to using StartTLS
|
ConnectionProtocol: upstreamldap.StartTLS, // successfully fell back to using StartTLS
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -538,7 +547,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -580,6 +589,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
// even though the connection test failed, still loads into the cache because it is treated like a warning
|
// even though the connection test failed, still loads into the cache because it is treated like a warning
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: "ldap.example.com:5678",
|
Host: "ldap.example.com:5678",
|
||||||
ConnectionProtocol: upstreamldap.TLS, // need to pick TLS or StartTLS to load into the cache when both fail, so choose TLS
|
ConnectionProtocol: upstreamldap.TLS, // need to pick TLS or StartTLS to load into the cache when both fail, so choose TLS
|
||||||
CABundle: testCABundle,
|
CABundle: testCABundle,
|
||||||
@ -600,7 +610,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -635,6 +645,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{
|
wantResultingCache: []*upstreamldap.ProviderConfig{
|
||||||
{
|
{
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
ResourceUID: testResourceUID,
|
||||||
Host: testHost,
|
Host: testHost,
|
||||||
ConnectionProtocol: upstreamldap.TLS,
|
ConnectionProtocol: upstreamldap.TLS,
|
||||||
CABundle: nil,
|
CABundle: nil,
|
||||||
@ -654,7 +665,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -674,6 +685,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
upstream.Name = "other-upstream"
|
upstream.Name = "other-upstream"
|
||||||
upstream.Generation = 42
|
upstream.Generation = 42
|
||||||
upstream.Spec.Bind.SecretName = "non-existent-secret"
|
upstream.Spec.Bind.SecretName = "non-existent-secret"
|
||||||
|
upstream.UID = "other-uid"
|
||||||
})},
|
})},
|
||||||
inputSecrets: []runtime.Object{validBindUserSecret("4242")},
|
inputSecrets: []runtime.Object{validBindUserSecret("4242")},
|
||||||
setupMocks: func(conn *mockldapconn.MockConn) {
|
setupMocks: func(conn *mockldapconn.MockConn) {
|
||||||
@ -685,7 +697,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "other-upstream", Generation: 42},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "other-upstream", Generation: 42, UID: "other-uid"},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -702,7 +714,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -729,7 +741,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
wantErr: controllerlib.ErrSyntheticRequeue.Error(),
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Error",
|
Phase: "Error",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -771,7 +783,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -805,7 +817,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithStartTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithStartTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -841,7 +853,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -877,7 +889,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -917,7 +929,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
@ -954,7 +966,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
wantResultingCache: []*upstreamldap.ProviderConfig{providerConfigForValidUpstreamWithTLS},
|
||||||
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.LDAPIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testResourceUID},
|
||||||
Status: v1alpha1.LDAPIdentityProviderStatus{
|
Status: v1alpha1.LDAPIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: allConditionsTrue(1234, "4242"),
|
Conditions: allConditionsTrue(1234, "4242"),
|
||||||
|
@ -175,6 +175,8 @@ func (c *oidcWatcherController) validateUpstream(ctx controllerlib.Context, upst
|
|||||||
UsernameClaim: upstream.Spec.Claims.Username,
|
UsernameClaim: upstream.Spec.Claims.Username,
|
||||||
GroupsClaim: upstream.Spec.Claims.Groups,
|
GroupsClaim: upstream.Spec.Claims.Groups,
|
||||||
AllowPasswordGrant: upstream.Spec.AuthorizationConfig.AllowPasswordGrant,
|
AllowPasswordGrant: upstream.Spec.AuthorizationConfig.AllowPasswordGrant,
|
||||||
|
AdditionalAuthcodeParams: map[string]string{"prompt": "consent"},
|
||||||
|
ResourceUID: upstream.UID,
|
||||||
}
|
}
|
||||||
conditions := []*v1alpha1.Condition{
|
conditions := []*v1alpha1.Condition{
|
||||||
c.validateSecret(upstream, &result),
|
c.validateSecret(upstream, &result),
|
||||||
@ -374,6 +376,7 @@ func computeScopes(additionalScopes []string) []string {
|
|||||||
// First compute the unique set of scopes, including "openid" (de-duplicate).
|
// First compute the unique set of scopes, including "openid" (de-duplicate).
|
||||||
set := make(map[string]bool, len(additionalScopes)+1)
|
set := make(map[string]bool, len(additionalScopes)+1)
|
||||||
set["openid"] = true
|
set["openid"] = true
|
||||||
|
set["offline_access"] = true
|
||||||
for _, s := range additionalScopes {
|
for _, s := range additionalScopes {
|
||||||
set[s] = true
|
set[s] = true
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
|
|
||||||
@ -123,12 +124,14 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) {
|
|||||||
testName = "test-name"
|
testName = "test-name"
|
||||||
testSecretName = "test-client-secret"
|
testSecretName = "test-client-secret"
|
||||||
testAdditionalScopes = []string{"scope1", "scope2", "scope3"}
|
testAdditionalScopes = []string{"scope1", "scope2", "scope3"}
|
||||||
testExpectedScopes = []string{"openid", "scope1", "scope2", "scope3"}
|
testExpectedScopes = []string{"offline_access", "openid", "scope1", "scope2", "scope3"}
|
||||||
|
testExpectedAdditionalParams = map[string]string{"prompt": "consent"}
|
||||||
testClientID = "test-oidc-client-id"
|
testClientID = "test-oidc-client-id"
|
||||||
testClientSecret = "test-oidc-client-secret"
|
testClientSecret = "test-oidc-client-secret"
|
||||||
testValidSecretData = map[string][]byte{"clientID": []byte(testClientID), "clientSecret": []byte(testClientSecret)}
|
testValidSecretData = map[string][]byte{"clientID": []byte(testClientID), "clientSecret": []byte(testClientSecret)}
|
||||||
testGroupsClaim = "test-groups-claim"
|
testGroupsClaim = "test-groups-claim"
|
||||||
testUsernameClaim = "test-username-claim"
|
testUsernameClaim = "test-username-claim"
|
||||||
|
testUID = types.UID("test-uid")
|
||||||
)
|
)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -561,13 +564,13 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
{
|
{
|
||||||
name: "upstream with error becomes valid",
|
name: "upstream with error becomes valid",
|
||||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-name"},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "test-name", UID: testUID},
|
||||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||||
Issuer: testIssuerURL,
|
Issuer: testIssuerURL,
|
||||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||||
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
Client: v1alpha1.OIDCClient{SecretName: testSecretName},
|
||||||
AuthorizationConfig: v1alpha1.OIDCAuthorizationConfig{
|
AuthorizationConfig: v1alpha1.OIDCAuthorizationConfig{
|
||||||
AdditionalScopes: append(testAdditionalScopes, "xyz", "openid"),
|
AdditionalScopes: append(testAdditionalScopes, "xyz", "openid", "offline_access"),
|
||||||
AllowPasswordGrant: true,
|
AllowPasswordGrant: true,
|
||||||
},
|
},
|
||||||
Claims: v1alpha1.OIDCClaims{Groups: testGroupsClaim, Username: testUsernameClaim},
|
Claims: v1alpha1.OIDCClaims{Groups: testGroupsClaim, Username: testUsernameClaim},
|
||||||
@ -598,10 +601,12 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
UsernameClaim: testUsernameClaim,
|
UsernameClaim: testUsernameClaim,
|
||||||
GroupsClaim: testGroupsClaim,
|
GroupsClaim: testGroupsClaim,
|
||||||
AllowPasswordGrant: true,
|
AllowPasswordGrant: true,
|
||||||
|
AdditionalAuthcodeParams: testExpectedAdditionalParams,
|
||||||
|
ResourceUID: testUID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, UID: testUID},
|
||||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -614,7 +619,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
{
|
{
|
||||||
name: "existing valid upstream",
|
name: "existing valid upstream",
|
||||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testUID},
|
||||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||||
Issuer: testIssuerURL,
|
Issuer: testIssuerURL,
|
||||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||||
@ -651,10 +656,12 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
UsernameClaim: testUsernameClaim,
|
UsernameClaim: testUsernameClaim,
|
||||||
GroupsClaim: testGroupsClaim,
|
GroupsClaim: testGroupsClaim,
|
||||||
AllowPasswordGrant: false,
|
AllowPasswordGrant: false,
|
||||||
|
AdditionalAuthcodeParams: testExpectedAdditionalParams,
|
||||||
|
ResourceUID: testUID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testUID},
|
||||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -667,7 +674,7 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
{
|
{
|
||||||
name: "existing valid upstream with trailing slash",
|
name: "existing valid upstream with trailing slash",
|
||||||
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
inputUpstreams: []runtime.Object{&v1alpha1.OIDCIdentityProvider{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testUID},
|
||||||
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
Spec: v1alpha1.OIDCIdentityProviderSpec{
|
||||||
Issuer: testIssuerURL + "/ends-with-slash/",
|
Issuer: testIssuerURL + "/ends-with-slash/",
|
||||||
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testIssuerCABase64},
|
||||||
@ -701,10 +708,12 @@ Get "` + testIssuerURL + `/valid-url-that-is-really-really-long-nananananananana
|
|||||||
UsernameClaim: testUsernameClaim,
|
UsernameClaim: testUsernameClaim,
|
||||||
GroupsClaim: testGroupsClaim,
|
GroupsClaim: testGroupsClaim,
|
||||||
AllowPasswordGrant: false,
|
AllowPasswordGrant: false,
|
||||||
|
AdditionalAuthcodeParams: testExpectedAdditionalParams,
|
||||||
|
ResourceUID: testUID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
wantResultingUpstreams: []v1alpha1.OIDCIdentityProvider{{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234},
|
ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: testName, Generation: 1234, UID: testUID},
|
||||||
Status: v1alpha1.OIDCIdentityProviderStatus{
|
Status: v1alpha1.OIDCIdentityProviderStatus{
|
||||||
Phase: "Ready",
|
Phase: "Ready",
|
||||||
Conditions: []v1alpha1.Condition{
|
Conditions: []v1alpha1.Condition{
|
||||||
@ -860,6 +869,8 @@ oidc: issuer did not match the issuer returned by provider, expected "` + testIs
|
|||||||
require.Equal(t, tt.wantResultingCache[i].GetUsernameClaim(), actualIDP.GetUsernameClaim())
|
require.Equal(t, tt.wantResultingCache[i].GetUsernameClaim(), actualIDP.GetUsernameClaim())
|
||||||
require.Equal(t, tt.wantResultingCache[i].GetGroupsClaim(), actualIDP.GetGroupsClaim())
|
require.Equal(t, tt.wantResultingCache[i].GetGroupsClaim(), actualIDP.GetGroupsClaim())
|
||||||
require.Equal(t, tt.wantResultingCache[i].AllowsPasswordGrant(), actualIDP.AllowsPasswordGrant())
|
require.Equal(t, tt.wantResultingCache[i].AllowsPasswordGrant(), actualIDP.AllowsPasswordGrant())
|
||||||
|
require.Equal(t, tt.wantResultingCache[i].GetAdditionalAuthcodeParams(), actualIDP.GetAdditionalAuthcodeParams())
|
||||||
|
require.Equal(t, tt.wantResultingCache[i].GetResourceUID(), actualIDP.GetResourceUID())
|
||||||
require.ElementsMatch(t, tt.wantResultingCache[i].GetScopes(), actualIDP.GetScopes())
|
require.ElementsMatch(t, tt.wantResultingCache[i].GetScopes(), actualIDP.GetScopes())
|
||||||
|
|
||||||
// We always want to use the proxy from env on these clients, so although the following assertions
|
// We always want to use the proxy from env on these clients, so although the following assertions
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/clock"
|
"k8s.io/apimachinery/pkg/util/clock"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
@ -343,6 +344,9 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
|
|||||||
func(s *fosite.TokenType, c fuzz.Continue) {
|
func(s *fosite.TokenType, c fuzz.Continue) {
|
||||||
*s = fosite.TokenType(randString(c))
|
*s = fosite.TokenType(randString(c))
|
||||||
},
|
},
|
||||||
|
func(s *types.UID, c fuzz.Continue) {
|
||||||
|
*s = types.UID(randString(c))
|
||||||
|
},
|
||||||
// handle string type alias
|
// handle string type alias
|
||||||
func(s *fosite.Arguments, c fuzz.Continue) {
|
func(s *fosite.Arguments, c fuzz.Continue) {
|
||||||
n := c.Intn(3) + 1 // 1 to 3 items
|
n := c.Intn(3) + 1 // 1 to 3 items
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
oidctypes "go.pinniped.dev/pkg/oidcclient/oidctypes"
|
oidctypes "go.pinniped.dev/pkg/oidcclient/oidctypes"
|
||||||
pkce "go.pinniped.dev/pkg/oidcclient/pkce"
|
pkce "go.pinniped.dev/pkg/oidcclient/pkce"
|
||||||
oauth2 "golang.org/x/oauth2"
|
oauth2 "golang.org/x/oauth2"
|
||||||
|
types "k8s.io/apimachinery/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockUpstreamOIDCIdentityProviderI is a mock of UpstreamOIDCIdentityProviderI interface.
|
// MockUpstreamOIDCIdentityProviderI is a mock of UpstreamOIDCIdentityProviderI interface.
|
||||||
@ -72,6 +73,20 @@ func (mr *MockUpstreamOIDCIdentityProviderIMockRecorder) ExchangeAuthcodeAndVali
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExchangeAuthcodeAndValidateTokens", reflect.TypeOf((*MockUpstreamOIDCIdentityProviderI)(nil).ExchangeAuthcodeAndValidateTokens), arg0, arg1, arg2, arg3, arg4)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExchangeAuthcodeAndValidateTokens", reflect.TypeOf((*MockUpstreamOIDCIdentityProviderI)(nil).ExchangeAuthcodeAndValidateTokens), arg0, arg1, arg2, arg3, arg4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAdditionalAuthcodeParams mocks base method.
|
||||||
|
func (m *MockUpstreamOIDCIdentityProviderI) GetAdditionalAuthcodeParams() map[string]string {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetAdditionalAuthcodeParams")
|
||||||
|
ret0, _ := ret[0].(map[string]string)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAdditionalAuthcodeParams indicates an expected call of GetAdditionalAuthcodeParams.
|
||||||
|
func (mr *MockUpstreamOIDCIdentityProviderIMockRecorder) GetAdditionalAuthcodeParams() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAdditionalAuthcodeParams", reflect.TypeOf((*MockUpstreamOIDCIdentityProviderI)(nil).GetAdditionalAuthcodeParams))
|
||||||
|
}
|
||||||
|
|
||||||
// GetAuthorizationURL mocks base method.
|
// GetAuthorizationURL mocks base method.
|
||||||
func (m *MockUpstreamOIDCIdentityProviderI) GetAuthorizationURL() *url.URL {
|
func (m *MockUpstreamOIDCIdentityProviderI) GetAuthorizationURL() *url.URL {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -128,6 +143,20 @@ func (mr *MockUpstreamOIDCIdentityProviderIMockRecorder) GetName() *gomock.Call
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetName", reflect.TypeOf((*MockUpstreamOIDCIdentityProviderI)(nil).GetName))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetName", reflect.TypeOf((*MockUpstreamOIDCIdentityProviderI)(nil).GetName))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetResourceUID mocks base method.
|
||||||
|
func (m *MockUpstreamOIDCIdentityProviderI) GetResourceUID() types.UID {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetResourceUID")
|
||||||
|
ret0, _ := ret[0].(types.UID)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResourceUID indicates an expected call of GetResourceUID.
|
||||||
|
func (mr *MockUpstreamOIDCIdentityProviderIMockRecorder) GetResourceUID() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResourceUID", reflect.TypeOf((*MockUpstreamOIDCIdentityProviderI)(nil).GetResourceUID))
|
||||||
|
}
|
||||||
|
|
||||||
// GetScopes mocks base method.
|
// GetScopes mocks base method.
|
||||||
func (m *MockUpstreamOIDCIdentityProviderI) GetScopes() []string {
|
func (m *MockUpstreamOIDCIdentityProviderI) GetScopes() []string {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -30,7 +30,10 @@ import (
|
|||||||
"go.pinniped.dev/pkg/oidcclient/pkce"
|
"go.pinniped.dev/pkg/oidcclient/pkce"
|
||||||
)
|
)
|
||||||
|
|
||||||
const promptParamNone = "none"
|
const (
|
||||||
|
promptParamName = "prompt"
|
||||||
|
promptParamNone = "none"
|
||||||
|
)
|
||||||
|
|
||||||
func NewHandler(
|
func NewHandler(
|
||||||
downstreamIssuer string,
|
downstreamIssuer string,
|
||||||
@ -51,13 +54,13 @@ func NewHandler(
|
|||||||
return httperr.Newf(http.StatusMethodNotAllowed, "%s (try GET or POST)", r.Method)
|
return httperr.Newf(http.StatusMethodNotAllowed, "%s (try GET or POST)", r.Method)
|
||||||
}
|
}
|
||||||
|
|
||||||
oidcUpstream, ldapUpstream, err := chooseUpstreamIDP(idpLister)
|
oidcUpstream, ldapUpstream, idpType, err := chooseUpstreamIDP(idpLister)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.WarningErr("authorize upstream config", err)
|
plog.WarningErr("authorize upstream config", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if oidcUpstream != nil {
|
if idpType == psession.ProviderTypeOIDC {
|
||||||
if len(r.Header.Values(supervisoroidc.AuthorizeUsernameHeaderName)) > 0 {
|
if len(r.Header.Values(supervisoroidc.AuthorizeUsernameHeaderName)) > 0 {
|
||||||
// The client set a username header, so they are trying to log in with a username/password.
|
// The client set a username header, so they are trying to log in with a username/password.
|
||||||
return handleAuthRequestForOIDCUpstreamPasswordGrant(r, w, oauthHelperWithStorage, oidcUpstream)
|
return handleAuthRequestForOIDCUpstreamPasswordGrant(r, w, oauthHelperWithStorage, oidcUpstream)
|
||||||
@ -74,6 +77,7 @@ func NewHandler(
|
|||||||
return handleAuthRequestForLDAPUpstream(r, w,
|
return handleAuthRequestForLDAPUpstream(r, w,
|
||||||
oauthHelperWithStorage,
|
oauthHelperWithStorage,
|
||||||
ldapUpstream,
|
ldapUpstream,
|
||||||
|
idpType,
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -83,6 +87,7 @@ func handleAuthRequestForLDAPUpstream(
|
|||||||
w http.ResponseWriter,
|
w http.ResponseWriter,
|
||||||
oauthHelper fosite.OAuth2Provider,
|
oauthHelper fosite.OAuth2Provider,
|
||||||
ldapUpstream provider.UpstreamLDAPIdentityProviderI,
|
ldapUpstream provider.UpstreamLDAPIdentityProviderI,
|
||||||
|
idpType psession.ProviderType,
|
||||||
) error {
|
) error {
|
||||||
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper)
|
authorizeRequester, created := newAuthorizeRequest(r, w, oauthHelper)
|
||||||
if !created {
|
if !created {
|
||||||
@ -108,7 +113,14 @@ func handleAuthRequestForLDAPUpstream(
|
|||||||
username = authenticateResponse.User.GetName()
|
username = authenticateResponse.User.GetName()
|
||||||
groups := authenticateResponse.User.GetGroups()
|
groups := authenticateResponse.User.GetGroups()
|
||||||
|
|
||||||
return makeDownstreamSessionAndReturnAuthcodeRedirect(r, w, oauthHelper, authorizeRequester, subject, username, groups)
|
customSessionData := &psession.CustomSessionData{
|
||||||
|
ProviderUID: ldapUpstream.GetResourceUID(),
|
||||||
|
ProviderName: ldapUpstream.GetName(),
|
||||||
|
ProviderType: idpType,
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeDownstreamSessionAndReturnAuthcodeRedirect(r, w,
|
||||||
|
oauthHelper, authorizeRequester, subject, username, groups, customSessionData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
||||||
@ -147,6 +159,15 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
|||||||
fosite.ErrAccessDenied.WithDebug(err.Error())) // WithDebug hides the error from the client
|
fosite.ErrAccessDenied.WithDebug(err.Error())) // WithDebug hides the error from the client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if token.RefreshToken == nil || token.RefreshToken.Token == "" {
|
||||||
|
plog.Warning("refresh token not returned by upstream provider during password grant",
|
||||||
|
"upstreamName", oidcUpstream.GetName(),
|
||||||
|
"scopes", oidcUpstream.GetScopes())
|
||||||
|
return writeAuthorizeError(w, oauthHelper, authorizeRequester,
|
||||||
|
fosite.ErrAccessDenied.WithHint(
|
||||||
|
"Refresh token not returned by upstream provider during password grant."))
|
||||||
|
}
|
||||||
|
|
||||||
subject, username, groups, err := downstreamsession.GetDownstreamIdentityFromUpstreamIDToken(oidcUpstream, token.IDToken.Claims)
|
subject, username, groups, err := downstreamsession.GetDownstreamIdentityFromUpstreamIDToken(oidcUpstream, token.IDToken.Claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Return a user-friendly error for this case which is entirely within our control.
|
// Return a user-friendly error for this case which is entirely within our control.
|
||||||
@ -155,7 +176,15 @@ func handleAuthRequestForOIDCUpstreamPasswordGrant(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeDownstreamSessionAndReturnAuthcodeRedirect(r, w, oauthHelper, authorizeRequester, subject, username, groups)
|
customSessionData := &psession.CustomSessionData{
|
||||||
|
ProviderUID: oidcUpstream.GetResourceUID(),
|
||||||
|
ProviderName: oidcUpstream.GetName(),
|
||||||
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
|
OIDC: &psession.OIDCSessionData{
|
||||||
|
UpstreamRefreshToken: token.RefreshToken.Token,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return makeDownstreamSessionAndReturnAuthcodeRedirect(r, w, oauthHelper, authorizeRequester, subject, username, groups, customSessionData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
||||||
@ -223,17 +252,20 @@ func handleAuthRequestForOIDCUpstreamAuthcodeGrant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
authCodeOptions := []oauth2.AuthCodeOption{
|
authCodeOptions := []oauth2.AuthCodeOption{
|
||||||
oauth2.AccessTypeOffline,
|
|
||||||
nonceValue.Param(),
|
nonceValue.Param(),
|
||||||
pkceValue.Challenge(),
|
pkceValue.Challenge(),
|
||||||
pkceValue.Method(),
|
pkceValue.Method(),
|
||||||
}
|
}
|
||||||
|
|
||||||
promptParam := r.Form.Get("prompt")
|
promptParam := r.Form.Get(promptParamName)
|
||||||
if promptParam == promptParamNone && oidc.ScopeWasRequested(authorizeRequester, coreosoidc.ScopeOpenID) {
|
if promptParam == promptParamNone && oidc.ScopeWasRequested(authorizeRequester, coreosoidc.ScopeOpenID) {
|
||||||
return writeAuthorizeError(w, oauthHelper, authorizeRequester, fosite.ErrLoginRequired)
|
return writeAuthorizeError(w, oauthHelper, authorizeRequester, fosite.ErrLoginRequired)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for key, val := range oidcUpstream.GetAdditionalAuthcodeParams() {
|
||||||
|
authCodeOptions = append(authCodeOptions, oauth2.SetAuthURLParam(key, val))
|
||||||
|
}
|
||||||
|
|
||||||
if csrfFromCookie == "" {
|
if csrfFromCookie == "" {
|
||||||
// We did not receive an incoming CSRF cookie, so write a new one.
|
// We did not receive an incoming CSRF cookie, so write a new one.
|
||||||
err := addCSRFSetCookieHeader(w, csrfValue, cookieCodec)
|
err := addCSRFSetCookieHeader(w, csrfValue, cookieCodec)
|
||||||
@ -280,8 +312,9 @@ func makeDownstreamSessionAndReturnAuthcodeRedirect(
|
|||||||
subject string,
|
subject string,
|
||||||
username string,
|
username string,
|
||||||
groups []string,
|
groups []string,
|
||||||
|
customSessionData *psession.CustomSessionData,
|
||||||
) error {
|
) error {
|
||||||
openIDSession := downstreamsession.MakeDownstreamSession(subject, username, groups)
|
openIDSession := downstreamsession.MakeDownstreamSession(subject, username, groups, customSessionData)
|
||||||
|
|
||||||
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -340,13 +373,13 @@ func readCSRFCookie(r *http.Request, codec oidc.Decoder) csrftoken.CSRFToken {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Select either an OIDC, an LDAP or an AD IDP, or return an error.
|
// Select either an OIDC, an LDAP or an AD IDP, or return an error.
|
||||||
func chooseUpstreamIDP(idpLister oidc.UpstreamIdentityProvidersLister) (provider.UpstreamOIDCIdentityProviderI, provider.UpstreamLDAPIdentityProviderI, error) {
|
func chooseUpstreamIDP(idpLister oidc.UpstreamIdentityProvidersLister) (provider.UpstreamOIDCIdentityProviderI, provider.UpstreamLDAPIdentityProviderI, psession.ProviderType, error) {
|
||||||
oidcUpstreams := idpLister.GetOIDCIdentityProviders()
|
oidcUpstreams := idpLister.GetOIDCIdentityProviders()
|
||||||
ldapUpstreams := idpLister.GetLDAPIdentityProviders()
|
ldapUpstreams := idpLister.GetLDAPIdentityProviders()
|
||||||
adUpstreams := idpLister.GetActiveDirectoryIdentityProviders()
|
adUpstreams := idpLister.GetActiveDirectoryIdentityProviders()
|
||||||
switch {
|
switch {
|
||||||
case len(oidcUpstreams)+len(ldapUpstreams)+len(adUpstreams) == 0:
|
case len(oidcUpstreams)+len(ldapUpstreams)+len(adUpstreams) == 0:
|
||||||
return nil, nil, httperr.New(
|
return nil, nil, "", httperr.New(
|
||||||
http.StatusUnprocessableEntity,
|
http.StatusUnprocessableEntity,
|
||||||
"No upstream providers are configured",
|
"No upstream providers are configured",
|
||||||
)
|
)
|
||||||
@ -362,16 +395,16 @@ func chooseUpstreamIDP(idpLister oidc.UpstreamIdentityProvidersLister) (provider
|
|||||||
upstreamIDPNames = append(upstreamIDPNames, idp.GetName())
|
upstreamIDPNames = append(upstreamIDPNames, idp.GetName())
|
||||||
}
|
}
|
||||||
plog.Warning("Too many upstream providers are configured (found: %s)", upstreamIDPNames)
|
plog.Warning("Too many upstream providers are configured (found: %s)", upstreamIDPNames)
|
||||||
return nil, nil, httperr.New(
|
return nil, nil, "", httperr.New(
|
||||||
http.StatusUnprocessableEntity,
|
http.StatusUnprocessableEntity,
|
||||||
"Too many upstream providers are configured (support for multiple upstreams is not yet implemented)",
|
"Too many upstream providers are configured (support for multiple upstreams is not yet implemented)",
|
||||||
)
|
)
|
||||||
case len(oidcUpstreams) == 1:
|
case len(oidcUpstreams) == 1:
|
||||||
return oidcUpstreams[0], nil, nil
|
return oidcUpstreams[0], nil, psession.ProviderTypeOIDC, nil
|
||||||
case len(adUpstreams) == 1:
|
case len(adUpstreams) == 1:
|
||||||
return nil, adUpstreams[0], nil
|
return nil, adUpstreams[0], psession.ProviderTypeActiveDirectory, nil
|
||||||
default:
|
default:
|
||||||
return nil, ldapUpstreams[0], nil
|
return nil, ldapUpstreams[0], psession.ProviderTypeLDAP, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"go.pinniped.dev/internal/oidc/csrftoken"
|
"go.pinniped.dev/internal/oidc/csrftoken"
|
||||||
"go.pinniped.dev/internal/oidc/jwks"
|
"go.pinniped.dev/internal/oidc/jwks"
|
||||||
"go.pinniped.dev/internal/oidc/provider"
|
"go.pinniped.dev/internal/oidc/provider"
|
||||||
|
"go.pinniped.dev/internal/psession"
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
"go.pinniped.dev/internal/testutil/oidctestutil"
|
"go.pinniped.dev/internal/testutil/oidctestutil"
|
||||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||||
@ -39,7 +40,13 @@ import (
|
|||||||
func TestAuthorizationEndpoint(t *testing.T) {
|
func TestAuthorizationEndpoint(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
oidcUpstreamName = "some-oidc-idp"
|
oidcUpstreamName = "some-oidc-idp"
|
||||||
|
oidcUpstreamResourceUID = "oidc-resource-uid"
|
||||||
oidcPasswordGrantUpstreamName = "some-password-granting-oidc-idp"
|
oidcPasswordGrantUpstreamName = "some-password-granting-oidc-idp"
|
||||||
|
oidcPasswordGrantUpstreamResourceUID = "some-password-granting-resource-uid"
|
||||||
|
ldapUpstreamName = "some-ldap-idp"
|
||||||
|
ldapUpstreamResourceUID = "ldap-resource-uid"
|
||||||
|
activeDirectoryUpstreamName = "some-active-directory-idp"
|
||||||
|
activeDirectoryUpstreamResourceUID = "active-directory-resource-uid"
|
||||||
|
|
||||||
oidcUpstreamIssuer = "https://my-upstream-issuer.com"
|
oidcUpstreamIssuer = "https://my-upstream-issuer.com"
|
||||||
oidcUpstreamSubject = "abc123-some guid" // has a space character which should get escaped in URL
|
oidcUpstreamSubject = "abc123-some guid" // has a space character which should get escaped in URL
|
||||||
@ -48,6 +55,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
oidcUpstreamPassword = "test-oidc-pinniped-password" //nolint: gosec
|
oidcUpstreamPassword = "test-oidc-pinniped-password" //nolint: gosec
|
||||||
oidcUpstreamUsernameClaim = "the-user-claim"
|
oidcUpstreamUsernameClaim = "the-user-claim"
|
||||||
oidcUpstreamGroupsClaim = "the-groups-claim"
|
oidcUpstreamGroupsClaim = "the-groups-claim"
|
||||||
|
oidcPasswordGrantUpstreamRefreshToken = "some-opaque-token" //nolint: gosec
|
||||||
|
|
||||||
downstreamIssuer = "https://my-downstream-issuer.com/some-path"
|
downstreamIssuer = "https://my-downstream-issuer.com/some-path"
|
||||||
downstreamRedirectURI = "http://127.0.0.1/callback"
|
downstreamRedirectURI = "http://127.0.0.1/callback"
|
||||||
@ -146,6 +154,12 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
"state": happyState,
|
"state": happyState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fositeAccessDeniedWithMissingRefreshTokenErrorQuery = map[string]string{
|
||||||
|
"error": "access_denied",
|
||||||
|
"error_description": "The resource owner or authorization server denied the request. Refresh token not returned by upstream provider during password grant.",
|
||||||
|
"state": happyState,
|
||||||
|
}
|
||||||
|
|
||||||
fositeAccessDeniedWithPasswordGrantDisallowedHintErrorQuery = map[string]string{
|
fositeAccessDeniedWithPasswordGrantDisallowedHintErrorQuery = map[string]string{
|
||||||
"error": "access_denied",
|
"error": "access_denied",
|
||||||
"error_description": "The resource owner or authorization server denied the request. Resource owner password credentials grant is not allowed for this upstream provider according to its configuration.",
|
"error_description": "The resource owner or authorization server denied the request. Resource owner password credentials grant is not allowed for this upstream provider according to its configuration.",
|
||||||
@ -208,20 +222,22 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
upstreamAuthURL, err := url.Parse("https://some-upstream-idp:8443/auth")
|
upstreamAuthURL, err := url.Parse("https://some-upstream-idp:8443/auth")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
upstreamOIDCIdentityProvider := func() *oidctestutil.TestUpstreamOIDCIdentityProvider {
|
upstreamOIDCIdentityProviderBuilder := func() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
||||||
WithName(oidcUpstreamName).
|
WithName(oidcUpstreamName).
|
||||||
|
WithResourceUID(oidcUpstreamResourceUID).
|
||||||
WithClientID("some-client-id").
|
WithClientID("some-client-id").
|
||||||
WithAuthorizationURL(*upstreamAuthURL).
|
WithAuthorizationURL(*upstreamAuthURL).
|
||||||
WithScopes([]string{"scope1", "scope2"}). // the scopes to request when starting the upstream authorization flow
|
WithScopes([]string{"scope1", "scope2"}). // the scopes to request when starting the upstream authorization flow
|
||||||
WithAllowPasswordGrant(false).
|
WithAllowPasswordGrant(false).
|
||||||
WithPasswordGrantError(errors.New("should not have used password grant on this instance")).
|
WithAdditionalAuthcodeParams(map[string]string{}).
|
||||||
Build()
|
WithPasswordGrantError(errors.New("should not have used password grant on this instance"))
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordGrantUpstreamOIDCIdentityProviderBuilder := func() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
passwordGrantUpstreamOIDCIdentityProviderBuilder := func() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
||||||
WithName(oidcPasswordGrantUpstreamName).
|
WithName(oidcPasswordGrantUpstreamName).
|
||||||
|
WithResourceUID(oidcPasswordGrantUpstreamResourceUID).
|
||||||
WithClientID("some-client-id").
|
WithClientID("some-client-id").
|
||||||
WithAuthorizationURL(*upstreamAuthURL).
|
WithAuthorizationURL(*upstreamAuthURL).
|
||||||
WithScopes([]string{"scope1", "scope2"}). // the scopes to request when starting the upstream authorization flow
|
WithScopes([]string{"scope1", "scope2"}). // the scopes to request when starting the upstream authorization flow
|
||||||
@ -234,6 +250,8 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
WithIDTokenClaim(oidcUpstreamGroupsClaim, oidcUpstreamGroupMembership).
|
WithIDTokenClaim(oidcUpstreamGroupsClaim, oidcUpstreamGroupMembership).
|
||||||
WithIDTokenClaim("other-claim", "should be ignored").
|
WithIDTokenClaim("other-claim", "should be ignored").
|
||||||
WithAllowPasswordGrant(true).
|
WithAllowPasswordGrant(true).
|
||||||
|
WithRefreshToken(oidcPasswordGrantUpstreamRefreshToken).
|
||||||
|
WithAdditionalAuthcodeParams(map[string]string{"should-be-ignored": "doesn't apply to password grant"}).
|
||||||
WithUpstreamAuthcodeExchangeError(errors.New("should not have tried to exchange upstream authcode on this instance"))
|
WithUpstreamAuthcodeExchangeError(errors.New("should not have tried to exchange upstream authcode on this instance"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,10 +272,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
parsedUpstreamLDAPURL, err := url.Parse(upstreamLDAPURL)
|
parsedUpstreamLDAPURL, err := url.Parse(upstreamLDAPURL)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
upstreamLDAPIdentityProvider := oidctestutil.TestUpstreamLDAPIdentityProvider{
|
ldapAuthenticateFunc := func(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
|
||||||
Name: "some-ldap-idp",
|
|
||||||
URL: parsedUpstreamLDAPURL,
|
|
||||||
AuthenticateFunc: func(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
|
|
||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
return nil, false, fmt.Errorf("should not have passed empty username or password to the authenticator")
|
return nil, false, fmt.Errorf("should not have passed empty username or password to the authenticator")
|
||||||
}
|
}
|
||||||
@ -271,11 +286,25 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
}, true, nil
|
}, true, nil
|
||||||
}
|
}
|
||||||
return nil, false, nil
|
return nil, false, nil
|
||||||
},
|
}
|
||||||
|
|
||||||
|
upstreamLDAPIdentityProvider := oidctestutil.TestUpstreamLDAPIdentityProvider{
|
||||||
|
Name: ldapUpstreamName,
|
||||||
|
ResourceUID: ldapUpstreamResourceUID,
|
||||||
|
URL: parsedUpstreamLDAPURL,
|
||||||
|
AuthenticateFunc: ldapAuthenticateFunc,
|
||||||
|
}
|
||||||
|
|
||||||
|
upstreamActiveDirectoryIdentityProvider := oidctestutil.TestUpstreamLDAPIdentityProvider{
|
||||||
|
Name: activeDirectoryUpstreamName,
|
||||||
|
ResourceUID: activeDirectoryUpstreamResourceUID,
|
||||||
|
URL: parsedUpstreamLDAPURL,
|
||||||
|
AuthenticateFunc: ldapAuthenticateFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
erroringUpstreamLDAPIdentityProvider := oidctestutil.TestUpstreamLDAPIdentityProvider{
|
erroringUpstreamLDAPIdentityProvider := oidctestutil.TestUpstreamLDAPIdentityProvider{
|
||||||
Name: "some-ldap-idp",
|
Name: ldapUpstreamName,
|
||||||
|
ResourceUID: ldapUpstreamResourceUID,
|
||||||
AuthenticateFunc: func(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
|
AuthenticateFunc: func(ctx context.Context, username, password string) (*authenticator.Response, bool, error) {
|
||||||
return nil, false, fmt.Errorf("some ldap upstream auth error")
|
return nil, false, fmt.Errorf("some ldap upstream auth error")
|
||||||
},
|
},
|
||||||
@ -387,10 +416,9 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
return encoded
|
return encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedRedirectLocationForUpstreamOIDC := func(expectedUpstreamState string, expectedPrompt string) string {
|
expectedRedirectLocationForUpstreamOIDC := func(expectedUpstreamState string, expectedAdditionalParams map[string]string) string {
|
||||||
query := map[string]string{
|
query := map[string]string{
|
||||||
"response_type": "code",
|
"response_type": "code",
|
||||||
"access_type": "offline",
|
|
||||||
"scope": "scope1 scope2",
|
"scope": "scope1 scope2",
|
||||||
"client_id": "some-client-id",
|
"client_id": "some-client-id",
|
||||||
"state": expectedUpstreamState,
|
"state": expectedUpstreamState,
|
||||||
@ -399,12 +427,35 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
"code_challenge_method": downstreamPKCEChallengeMethod,
|
"code_challenge_method": downstreamPKCEChallengeMethod,
|
||||||
"redirect_uri": downstreamIssuer + "/callback",
|
"redirect_uri": downstreamIssuer + "/callback",
|
||||||
}
|
}
|
||||||
if expectedPrompt != "" {
|
for key, val := range expectedAdditionalParams {
|
||||||
query["prompt"] = expectedPrompt
|
query[key] = val
|
||||||
}
|
}
|
||||||
return urlWithQuery(upstreamAuthURL.String(), query)
|
return urlWithQuery(upstreamAuthURL.String(), query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedHappyActiveDirectoryUpstreamCustomSession := &psession.CustomSessionData{
|
||||||
|
ProviderUID: activeDirectoryUpstreamResourceUID,
|
||||||
|
ProviderName: activeDirectoryUpstreamName,
|
||||||
|
ProviderType: psession.ProviderTypeActiveDirectory,
|
||||||
|
OIDC: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedHappyLDAPUpstreamCustomSession := &psession.CustomSessionData{
|
||||||
|
ProviderUID: ldapUpstreamResourceUID,
|
||||||
|
ProviderName: ldapUpstreamName,
|
||||||
|
ProviderType: psession.ProviderTypeLDAP,
|
||||||
|
OIDC: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedHappyOIDCPasswordGrantCustomSession := &psession.CustomSessionData{
|
||||||
|
ProviderUID: oidcPasswordGrantUpstreamResourceUID,
|
||||||
|
ProviderName: oidcPasswordGrantUpstreamName,
|
||||||
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
|
OIDC: &psession.OIDCSessionData{
|
||||||
|
UpstreamRefreshToken: oidcPasswordGrantUpstreamRefreshToken,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Note that fosite puts the granted scopes as a param in the redirect URI even though the spec doesn't seem to require it
|
// Note that fosite puts the granted scopes as a param in the redirect URI even though the spec doesn't seem to require it
|
||||||
happyAuthcodeDownstreamRedirectLocationRegexp := downstreamRedirectURI + `\?code=([^&]+)&scope=openid&state=` + happyState
|
happyAuthcodeDownstreamRedirectLocationRegexp := downstreamRedirectURI + `\?code=([^&]+)&scope=openid&state=` + happyState
|
||||||
|
|
||||||
@ -452,11 +503,12 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce string
|
wantDownstreamNonce string
|
||||||
wantUnnecessaryStoredRecords int
|
wantUnnecessaryStoredRecords int
|
||||||
wantPasswordGrantCall *expectedPasswordGrant
|
wantPasswordGrantCall *expectedPasswordGrant
|
||||||
|
wantDownstreamCustomSessionData *psession.CustomSessionData
|
||||||
}
|
}
|
||||||
tests := []testCase{
|
tests := []testCase{
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow happy path using GET without a CSRF cookie",
|
name: "OIDC upstream browser flow happy path using GET without a CSRF cookie",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -467,7 +519,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantStatus: http.StatusFound,
|
wantStatus: http.StatusFound,
|
||||||
wantContentType: htmlContentType,
|
wantContentType: htmlContentType,
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), ""),
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -491,6 +543,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "LDAP upstream happy path using GET",
|
name: "LDAP upstream happy path using GET",
|
||||||
@ -511,10 +564,11 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ActiveDirectory upstream happy path using GET",
|
name: "ActiveDirectory upstream happy path using GET",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
||||||
@ -531,10 +585,11 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyActiveDirectoryUpstreamCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow happy path using GET with a CSRF cookie",
|
name: "OIDC upstream browser flow happy path using GET with a CSRF cookie",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -545,13 +600,13 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
csrfCookie: "__Host-pinniped-csrf=" + encodedIncomingCookieCSRFValue + " ",
|
csrfCookie: "__Host-pinniped-csrf=" + encodedIncomingCookieCSRFValue + " ",
|
||||||
wantStatus: http.StatusFound,
|
wantStatus: http.StatusFound,
|
||||||
wantContentType: htmlContentType,
|
wantContentType: htmlContentType,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, incomingCookieCSRFValue, ""), ""),
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, incomingCookieCSRFValue, ""), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow happy path using POST",
|
name: "OIDC upstream browser flow happy path using POST",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -565,7 +620,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantContentType: "",
|
wantContentType: "",
|
||||||
wantBodyString: "",
|
wantBodyString: "",
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), ""),
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -590,6 +645,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "LDAP upstream happy path using POST",
|
name: "LDAP upstream happy path using POST",
|
||||||
@ -612,10 +668,11 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Active Directory upstream happy path using POST",
|
name: "Active Directory upstream happy path using POST",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodPost,
|
method: http.MethodPost,
|
||||||
path: "/some/path",
|
path: "/some/path",
|
||||||
contentType: "application/x-www-form-urlencoded",
|
contentType: "application/x-www-form-urlencoded",
|
||||||
@ -634,10 +691,11 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyActiveDirectoryUpstreamCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow happy path with prompt param other than none that gets ignored",
|
name: "OIDC upstream browser flow happy path with prompt param other than none that gets ignored",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -651,12 +709,31 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantContentType: htmlContentType,
|
wantContentType: htmlContentType,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{"prompt": "login"}, "", ""), ""),
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{"prompt": "login"}, "", ""), nil),
|
||||||
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OIDC upstream browser flow happy path with extra params that get passed through",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().WithAdditionalAuthcodeParams(map[string]string{"prompt": "consent", "abc": "123", "def": "456"}).Build()),
|
||||||
|
generateCSRF: happyCSRFGenerator,
|
||||||
|
generatePKCE: happyPKCEGenerator,
|
||||||
|
generateNonce: happyNonceGenerator,
|
||||||
|
stateEncoder: happyStateEncoder,
|
||||||
|
cookieEncoder: happyCookieEncoder,
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: modifiedHappyGetRequestPath(map[string]string{"prompt": "login"}),
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
body: encodeQuery(happyGetRequestQueryMap),
|
||||||
|
wantStatus: http.StatusFound,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBodyStringWithLocationInHref: true,
|
||||||
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{"prompt": "login"}, "", ""), map[string]string{"prompt": "consent", "abc": "123", "def": "456"}),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow with prompt param none throws an error because we want to independently decide the upstream prompt param",
|
name: "OIDC upstream browser flow with prompt param none throws an error because we want to independently decide the upstream prompt param",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -673,7 +750,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow with error while decoding CSRF cookie just generates a new cookie and succeeds as usual",
|
name: "OIDC upstream browser flow with error while decoding CSRF cookie just generates a new cookie and succeeds as usual",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -686,13 +763,13 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantContentType: htmlContentType,
|
wantContentType: htmlContentType,
|
||||||
// Generated a new CSRF cookie and set it in the response.
|
// Generated a new CSRF cookie and set it in the response.
|
||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), ""),
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(nil, "", ""), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow happy path when downstream redirect uri matches what is configured for client except for the port number",
|
name: "OIDC upstream browser flow happy path when downstream redirect uri matches what is configured for client except for the port number",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -707,7 +784,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{
|
||||||
"redirect_uri": downstreamRedirectURIWithDifferentPort, // not the same port number that is registered for the client
|
"redirect_uri": downstreamRedirectURIWithDifferentPort, // not the same port number that is registered for the client
|
||||||
}, "", ""), ""),
|
}, "", ""), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -733,6 +810,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "LDAP upstream happy path when downstream redirect uri matches what is configured for client except for the port number",
|
name: "LDAP upstream happy path when downstream redirect uri matches what is configured for client except for the port number",
|
||||||
@ -755,10 +833,11 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream browser flow happy path when downstream requested scopes include offline_access",
|
name: "OIDC upstream browser flow happy path when downstream requested scopes include offline_access",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -771,7 +850,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(map[string]string{
|
||||||
"scope": "openid offline_access",
|
"scope": "openid offline_access",
|
||||||
}, "", ""), ""),
|
}, "", ""), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -834,7 +913,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wrong upstream password for Active Directory authentication",
|
name: "wrong upstream password for Active Directory authentication",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
||||||
@ -858,7 +937,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wrong upstream username for Active Directory authentication",
|
name: "wrong upstream username for Active Directory authentication",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
customUsernameHeader: pointer.StringPtr("wrong-username"),
|
customUsernameHeader: pointer.StringPtr("wrong-username"),
|
||||||
@ -882,7 +961,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing upstream username on request for Active Directory authentication",
|
name: "missing upstream username on request for Active Directory authentication",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
customUsernameHeader: nil, // do not send header
|
customUsernameHeader: nil, // do not send header
|
||||||
@ -906,7 +985,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing upstream password on request for Active Directory authentication",
|
name: "missing upstream password on request for Active Directory authentication",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
||||||
@ -916,6 +995,32 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeAccessDeniedWithMissingUsernamePasswordHintErrorQuery),
|
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeAccessDeniedWithMissingUsernamePasswordHintErrorQuery),
|
||||||
wantBodyString: "",
|
wantBodyString: "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "return an error when upstream IDP did not return a refresh token",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(passwordGrantUpstreamOIDCIdentityProviderBuilder().WithoutRefreshToken().Build()),
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: happyGetRequestPath,
|
||||||
|
customUsernameHeader: pointer.StringPtr(oidcUpstreamUsername),
|
||||||
|
customPasswordHeader: pointer.StringPtr(oidcUpstreamPassword),
|
||||||
|
wantPasswordGrantCall: happyUpstreamPasswordGrantMockExpectation,
|
||||||
|
wantStatus: http.StatusFound,
|
||||||
|
wantContentType: "application/json; charset=utf-8",
|
||||||
|
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeAccessDeniedWithMissingRefreshTokenErrorQuery),
|
||||||
|
wantBodyString: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "return an error when upstream IDP did not return a refresh token",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(passwordGrantUpstreamOIDCIdentityProviderBuilder().WithEmptyRefreshToken().Build()),
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: happyGetRequestPath,
|
||||||
|
customUsernameHeader: pointer.StringPtr(oidcUpstreamUsername),
|
||||||
|
customPasswordHeader: pointer.StringPtr(oidcUpstreamPassword),
|
||||||
|
wantPasswordGrantCall: happyUpstreamPasswordGrantMockExpectation,
|
||||||
|
wantStatus: http.StatusFound,
|
||||||
|
wantContentType: "application/json; charset=utf-8",
|
||||||
|
wantLocationHeader: urlWithQuery(downstreamRedirectURI, fositeAccessDeniedWithMissingRefreshTokenErrorQuery),
|
||||||
|
wantBodyString: "",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "missing upstream password on request for OIDC password grant authentication",
|
name: "missing upstream password on request for OIDC password grant authentication",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(passwordGrantUpstreamOIDCIdentityProviderBuilder().Build()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(passwordGrantUpstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
@ -930,7 +1035,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "using the custom username header on request for OIDC password grant authentication when OIDCIdentityProvider does not allow password grants",
|
name: "using the custom username header on request for OIDC password grant authentication when OIDCIdentityProvider does not allow password grants",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
customUsernameHeader: pointer.StringPtr(oidcUpstreamUsername),
|
customUsernameHeader: pointer.StringPtr(oidcUpstreamUsername),
|
||||||
@ -942,7 +1047,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream redirect uri does not match what is configured for client when using OIDC upstream browser flow",
|
name: "downstream redirect uri does not match what is configured for client when using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -984,7 +1089,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream redirect uri does not match what is configured for client when using active directory upstream",
|
name: "downstream redirect uri does not match what is configured for client when using active directory upstream",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: modifiedHappyGetRequestPath(map[string]string{
|
path: modifiedHappyGetRequestPath(map[string]string{
|
||||||
"redirect_uri": "http://127.0.0.1/does-not-match-what-is-configured-for-pinniped-cli-client",
|
"redirect_uri": "http://127.0.0.1/does-not-match-what-is-configured-for-pinniped-cli-client",
|
||||||
@ -997,7 +1102,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream client does not exist when using OIDC upstream browser flow",
|
name: "downstream client does not exist when using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1031,7 +1136,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream client does not exist when using active directory upstream",
|
name: "downstream client does not exist when using active directory upstream",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: modifiedHappyGetRequestPath(map[string]string{"client_id": "invalid-client"}),
|
path: modifiedHappyGetRequestPath(map[string]string{"client_id": "invalid-client"}),
|
||||||
wantStatus: http.StatusUnauthorized,
|
wantStatus: http.StatusUnauthorized,
|
||||||
@ -1040,7 +1145,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "response type is unsupported when using OIDC upstream browser flow",
|
name: "response type is unsupported when using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1077,7 +1182,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "response type is unsupported when using active directory upstream",
|
name: "response type is unsupported when using active directory upstream",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: modifiedHappyGetRequestPath(map[string]string{"response_type": "unsupported"}),
|
path: modifiedHappyGetRequestPath(map[string]string{"response_type": "unsupported"}),
|
||||||
wantStatus: http.StatusFound,
|
wantStatus: http.StatusFound,
|
||||||
@ -1087,7 +1192,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream scopes do not match what is configured for client using OIDC upstream browser flow",
|
name: "downstream scopes do not match what is configured for client using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1126,7 +1231,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream scopes do not match what is configured for client using Active Directory upstream",
|
name: "downstream scopes do not match what is configured for client using Active Directory upstream",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: modifiedHappyGetRequestPath(map[string]string{"scope": "openid tuna"}),
|
path: modifiedHappyGetRequestPath(map[string]string{"scope": "openid tuna"}),
|
||||||
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
customUsernameHeader: pointer.StringPtr(happyLDAPUsername),
|
||||||
@ -1138,7 +1243,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing response type in request using OIDC upstream browser flow",
|
name: "missing response type in request using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1175,7 +1280,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing response type in request using Active Directory upstream",
|
name: "missing response type in request using Active Directory upstream",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamLDAPIdentityProvider),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider),
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: modifiedHappyGetRequestPath(map[string]string{"response_type": ""}),
|
path: modifiedHappyGetRequestPath(map[string]string{"response_type": ""}),
|
||||||
wantStatus: http.StatusFound,
|
wantStatus: http.StatusFound,
|
||||||
@ -1185,7 +1290,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing client id in request using OIDC upstream browser flow",
|
name: "missing client id in request using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1219,7 +1324,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing PKCE code_challenge in request using OIDC upstream browser flow", // See https://tools.ietf.org/html/rfc7636#section-4.4.1
|
name: "missing PKCE code_challenge in request using OIDC upstream browser flow", // See https://tools.ietf.org/html/rfc7636#section-4.4.1
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1261,7 +1366,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid value for PKCE code_challenge_method in request using OIDC upstream browser flow", // https://tools.ietf.org/html/rfc7636#section-4.3
|
name: "invalid value for PKCE code_challenge_method in request using OIDC upstream browser flow", // https://tools.ietf.org/html/rfc7636#section-4.3
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1303,7 +1408,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when PKCE code_challenge_method in request is `plain` using OIDC upstream browser flow", // https://tools.ietf.org/html/rfc7636#section-4.3
|
name: "when PKCE code_challenge_method in request is `plain` using OIDC upstream browser flow", // https://tools.ietf.org/html/rfc7636#section-4.3
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1345,7 +1450,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "missing PKCE code_challenge_method in request using OIDC upstream browser flow", // See https://tools.ietf.org/html/rfc7636#section-4.4.1
|
name: "missing PKCE code_challenge_method in request using OIDC upstream browser flow", // See https://tools.ietf.org/html/rfc7636#section-4.4.1
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1389,7 +1494,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
// This is just one of the many OIDC validations run by fosite. This test is to ensure that we are running
|
// This is just one of the many OIDC validations run by fosite. This test is to ensure that we are running
|
||||||
// through that part of the fosite library when using an OIDC upstream browser flow.
|
// through that part of the fosite library when using an OIDC upstream browser flow.
|
||||||
name: "prompt param is not allowed to have none and another legal value at the same time using OIDC upstream browser flow",
|
name: "prompt param is not allowed to have none and another legal value at the same time using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1435,7 +1540,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "happy path: downstream OIDC validations are skipped when the openid scope was not requested using OIDC upstream browser flow",
|
name: "happy path: downstream OIDC validations are skipped when the openid scope was not requested using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1449,7 +1554,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantCSRFValueInCookieHeader: happyCSRF,
|
wantCSRFValueInCookieHeader: happyCSRF,
|
||||||
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(
|
wantLocationHeader: expectedRedirectLocationForUpstreamOIDC(expectedUpstreamStateParam(
|
||||||
map[string]string{"prompt": "none login", "scope": "email"}, "", "",
|
map[string]string{"prompt": "none login", "scope": "email"}, "", "",
|
||||||
), ""),
|
), nil),
|
||||||
wantUpstreamStateParamInLocationHeader: true,
|
wantUpstreamStateParamInLocationHeader: true,
|
||||||
wantBodyStringWithLocationInHref: true,
|
wantBodyStringWithLocationInHref: true,
|
||||||
},
|
},
|
||||||
@ -1474,6 +1579,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "happy path: downstream OIDC validations are skipped when the openid scope was not requested using LDAP upstream",
|
name: "happy path: downstream OIDC validations are skipped when the openid scope was not requested using LDAP upstream",
|
||||||
@ -1495,6 +1601,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyLDAPUpstreamCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP provides no username or group claim configuration, so we use default username claim and skip groups",
|
name: "OIDC upstream password grant: upstream IDP provides no username or group claim configuration, so we use default username claim and skip groups",
|
||||||
@ -1518,6 +1625,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is missing",
|
name: "OIDC upstream password grant: upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is missing",
|
||||||
@ -1543,6 +1651,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is present with true value",
|
name: "OIDC upstream password grant: upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is present with true value",
|
||||||
@ -1569,6 +1678,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP configures username claim as anything other than special claim `email` and `email_verified` upstream claim is present with false value",
|
name: "OIDC upstream password grant: upstream IDP configures username claim as anything other than special claim `email` and `email_verified` upstream claim is present with false value",
|
||||||
@ -1596,6 +1706,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is present with illegal value",
|
name: "OIDC upstream password grant: upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is present with illegal value",
|
||||||
@ -1655,6 +1766,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP's configured groups claim in the ID token has a non-array value",
|
name: "OIDC upstream password grant: upstream IDP's configured groups claim in the ID token has a non-array value",
|
||||||
@ -1679,6 +1791,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream IDP's configured groups claim in the ID token is a slice of interfaces",
|
name: "OIDC upstream password grant: upstream IDP's configured groups claim in the ID token is a slice of interfaces",
|
||||||
@ -1703,6 +1816,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream ID token does not contain requested username claim",
|
name: "OIDC upstream password grant: upstream ID token does not contain requested username claim",
|
||||||
@ -1741,6 +1855,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: expectedHappyOIDCPasswordGrantCustomSession,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OIDC upstream password grant: upstream ID token contains username claim with weird format",
|
name: "OIDC upstream password grant: upstream ID token contains username claim with weird format",
|
||||||
@ -1909,7 +2024,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "downstream state does not have enough entropy using OIDC upstream browser flow",
|
name: "downstream state does not have enough entropy using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1948,7 +2063,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error while encoding upstream state param using OIDC upstream browser flow",
|
name: "error while encoding upstream state param using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1962,7 +2077,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error while encoding CSRF cookie value for new cookie using OIDC upstream browser flow",
|
name: "error while encoding CSRF cookie value for new cookie using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1976,7 +2091,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error while generating CSRF token using OIDC upstream browser flow",
|
name: "error while generating CSRF token using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: sadCSRFGenerator,
|
generateCSRF: sadCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -1990,7 +2105,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error while generating nonce using OIDC upstream browser flow",
|
name: "error while generating nonce using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: happyPKCEGenerator,
|
generatePKCE: happyPKCEGenerator,
|
||||||
generateNonce: sadNonceGenerator,
|
generateNonce: sadNonceGenerator,
|
||||||
@ -2004,7 +2119,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "error while generating PKCE using OIDC upstream browser flow",
|
name: "error while generating PKCE using OIDC upstream browser flow",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
generateCSRF: happyCSRFGenerator,
|
generateCSRF: happyCSRFGenerator,
|
||||||
generatePKCE: sadPKCEGenerator,
|
generatePKCE: sadPKCEGenerator,
|
||||||
generateNonce: happyNonceGenerator,
|
generateNonce: happyNonceGenerator,
|
||||||
@ -2027,7 +2142,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "too many upstream providers are configured: multiple OIDC",
|
name: "too many upstream providers are configured: multiple OIDC",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider(), upstreamOIDCIdentityProvider()), // more than one not allowed
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build(), upstreamOIDCIdentityProviderBuilder().Build()), // more than one not allowed
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
wantStatus: http.StatusUnprocessableEntity,
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
@ -2054,7 +2169,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "too many upstream providers are configured: both OIDC and LDAP",
|
name: "too many upstream providers are configured: both OIDC and LDAP",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()).WithLDAP(&upstreamLDAPIdentityProvider), // more than one not allowed
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()).WithLDAP(&upstreamLDAPIdentityProvider), // more than one not allowed
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
wantStatus: http.StatusUnprocessableEntity,
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
@ -2063,7 +2178,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "too many upstream providers are configured: OIDC, LDAP and AD",
|
name: "too many upstream providers are configured: OIDC, LDAP and AD",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()).WithLDAP(&upstreamLDAPIdentityProvider).WithActiveDirectory(&upstreamLDAPIdentityProvider), // more than one not allowed
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()).WithLDAP(&upstreamLDAPIdentityProvider).WithActiveDirectory(&upstreamActiveDirectoryIdentityProvider), // more than one not allowed
|
||||||
method: http.MethodGet,
|
method: http.MethodGet,
|
||||||
path: happyGetRequestPath,
|
path: happyGetRequestPath,
|
||||||
wantStatus: http.StatusUnprocessableEntity,
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
@ -2072,7 +2187,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PUT is a bad method",
|
name: "PUT is a bad method",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
method: http.MethodPut,
|
method: http.MethodPut,
|
||||||
path: "/some/path",
|
path: "/some/path",
|
||||||
wantStatus: http.StatusMethodNotAllowed,
|
wantStatus: http.StatusMethodNotAllowed,
|
||||||
@ -2081,7 +2196,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PATCH is a bad method",
|
name: "PATCH is a bad method",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
method: http.MethodPatch,
|
method: http.MethodPatch,
|
||||||
path: "/some/path",
|
path: "/some/path",
|
||||||
wantStatus: http.StatusMethodNotAllowed,
|
wantStatus: http.StatusMethodNotAllowed,
|
||||||
@ -2090,7 +2205,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DELETE is a bad method",
|
name: "DELETE is a bad method",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProvider()),
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(upstreamOIDCIdentityProviderBuilder().Build()),
|
||||||
method: http.MethodDelete,
|
method: http.MethodDelete,
|
||||||
path: "/some/path",
|
path: "/some/path",
|
||||||
wantStatus: http.StatusMethodNotAllowed,
|
wantStatus: http.StatusMethodNotAllowed,
|
||||||
@ -2166,6 +2281,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
test.wantDownstreamNonce,
|
test.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
downstreamClientID,
|
||||||
test.wantDownstreamRedirectURI,
|
test.wantDownstreamRedirectURI,
|
||||||
|
test.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
require.Empty(t, rsp.Header().Values("Location"))
|
require.Empty(t, rsp.Header().Values("Location"))
|
||||||
@ -2239,6 +2355,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
WithClientID("some-other-new-client-id").
|
WithClientID("some-other-new-client-id").
|
||||||
WithAuthorizationURL(*upstreamAuthURL).
|
WithAuthorizationURL(*upstreamAuthURL).
|
||||||
WithScopes([]string{"some-other-new-scope1", "some-other-new-scope2"}).
|
WithScopes([]string{"some-other-new-scope1", "some-other-new-scope2"}).
|
||||||
|
WithAdditionalAuthcodeParams(map[string]string{"prompt": "consent", "abc": "123"}).
|
||||||
Build()
|
Build()
|
||||||
idpLister.SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI{provider.UpstreamOIDCIdentityProviderI(newProviderSettings)})
|
idpLister.SetOIDCIdentityProviders([]provider.UpstreamOIDCIdentityProviderI{provider.UpstreamOIDCIdentityProviderI(newProviderSettings)})
|
||||||
|
|
||||||
@ -2246,7 +2363,8 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
test.wantLocationHeader = urlWithQuery(upstreamAuthURL.String(),
|
test.wantLocationHeader = urlWithQuery(upstreamAuthURL.String(),
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"response_type": "code",
|
"response_type": "code",
|
||||||
"access_type": "offline",
|
"prompt": "consent",
|
||||||
|
"abc": "123",
|
||||||
"scope": "some-other-new-scope1 some-other-new-scope2", // updated expectation
|
"scope": "some-other-new-scope1 some-other-new-scope2", // updated expectation
|
||||||
"client_id": "some-other-new-client-id", // updated expectation
|
"client_id": "some-other-new-client-id", // updated expectation
|
||||||
"state": expectedUpstreamStateParam(
|
"state": expectedUpstreamStateParam(
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"go.pinniped.dev/internal/oidc/provider"
|
"go.pinniped.dev/internal/oidc/provider"
|
||||||
"go.pinniped.dev/internal/oidc/provider/formposthtml"
|
"go.pinniped.dev/internal/oidc/provider/formposthtml"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/plog"
|
||||||
|
"go.pinniped.dev/internal/psession"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewHandler(
|
func NewHandler(
|
||||||
@ -68,12 +69,27 @@ func NewHandler(
|
|||||||
return httperr.New(http.StatusBadGateway, "error exchanging and validating upstream tokens")
|
return httperr.New(http.StatusBadGateway, "error exchanging and validating upstream tokens")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if token.RefreshToken == nil || token.RefreshToken.Token == "" {
|
||||||
|
plog.Warning("refresh token not returned by upstream provider during authcode exchange",
|
||||||
|
"upstreamName", upstreamIDPConfig.GetName(),
|
||||||
|
"scopes", upstreamIDPConfig.GetScopes(),
|
||||||
|
"additionalParams", upstreamIDPConfig.GetAdditionalAuthcodeParams())
|
||||||
|
return httperr.New(http.StatusUnprocessableEntity, "refresh token not returned by upstream provider during authcode exchange")
|
||||||
|
}
|
||||||
|
|
||||||
subject, username, groups, err := downstreamsession.GetDownstreamIdentityFromUpstreamIDToken(upstreamIDPConfig, token.IDToken.Claims)
|
subject, username, groups, err := downstreamsession.GetDownstreamIdentityFromUpstreamIDToken(upstreamIDPConfig, token.IDToken.Claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperr.Wrap(http.StatusUnprocessableEntity, err.Error(), err)
|
return httperr.Wrap(http.StatusUnprocessableEntity, err.Error(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
openIDSession := downstreamsession.MakeDownstreamSession(subject, username, groups)
|
openIDSession := downstreamsession.MakeDownstreamSession(subject, username, groups, &psession.CustomSessionData{
|
||||||
|
ProviderUID: upstreamIDPConfig.GetResourceUID(),
|
||||||
|
ProviderName: upstreamIDPConfig.GetName(),
|
||||||
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
|
OIDC: &psession.OIDCSessionData{
|
||||||
|
UpstreamRefreshToken: token.RefreshToken.Token,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
authorizeResponder, err := oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, openIDSession)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
|
|
||||||
"go.pinniped.dev/internal/oidc"
|
"go.pinniped.dev/internal/oidc"
|
||||||
"go.pinniped.dev/internal/oidc/jwks"
|
"go.pinniped.dev/internal/oidc/jwks"
|
||||||
|
"go.pinniped.dev/internal/psession"
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
"go.pinniped.dev/internal/testutil/oidctestutil"
|
"go.pinniped.dev/internal/testutil/oidctestutil"
|
||||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||||
@ -26,8 +27,10 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
happyUpstreamIDPName = "upstream-idp-name"
|
happyUpstreamIDPName = "upstream-idp-name"
|
||||||
|
happyUpstreamIDPResourceUID = "upstream-uid"
|
||||||
|
|
||||||
oidcUpstreamIssuer = "https://my-upstream-issuer.com"
|
oidcUpstreamIssuer = "https://my-upstream-issuer.com"
|
||||||
|
oidcUpstreamRefreshToken = "test-refresh-token"
|
||||||
oidcUpstreamSubject = "abc123-some guid" // has a space character which should get escaped in URL
|
oidcUpstreamSubject = "abc123-some guid" // has a space character which should get escaped in URL
|
||||||
oidcUpstreamSubjectQueryEscaped = "abc123-some+guid"
|
oidcUpstreamSubjectQueryEscaped = "abc123-some+guid"
|
||||||
oidcUpstreamUsername = "test-pinniped-username"
|
oidcUpstreamUsername = "test-pinniped-username"
|
||||||
@ -70,6 +73,12 @@ var (
|
|||||||
"redirect_uri": []string{downstreamRedirectURI},
|
"redirect_uri": []string{downstreamRedirectURI},
|
||||||
}
|
}
|
||||||
happyDownstreamRequestParams = happyDownstreamRequestParamsQuery.Encode()
|
happyDownstreamRequestParams = happyDownstreamRequestParamsQuery.Encode()
|
||||||
|
happyDownstreamCustomSessionData = &psession.CustomSessionData{
|
||||||
|
ProviderUID: happyUpstreamIDPResourceUID,
|
||||||
|
ProviderName: happyUpstreamIDPName,
|
||||||
|
ProviderType: psession.ProviderTypeOIDC,
|
||||||
|
OIDC: &psession.OIDCSessionData{UpstreamRefreshToken: oidcUpstreamRefreshToken},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCallbackEndpoint(t *testing.T) {
|
func TestCallbackEndpoint(t *testing.T) {
|
||||||
@ -130,6 +139,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce string
|
wantDownstreamNonce string
|
||||||
wantDownstreamPKCEChallenge string
|
wantDownstreamPKCEChallenge string
|
||||||
wantDownstreamPKCEChallengeMethod string
|
wantDownstreamPKCEChallengeMethod string
|
||||||
|
wantDownstreamCustomSessionData *psession.CustomSessionData
|
||||||
|
|
||||||
wantAuthcodeExchangeCall *expectedAuthcodeExchange
|
wantAuthcodeExchangeCall *expectedAuthcodeExchange
|
||||||
}{
|
}{
|
||||||
@ -157,6 +167,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -179,6 +190,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -203,6 +215,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -227,6 +240,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -253,6 +267,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -280,6 +295,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -302,6 +318,34 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "return an error when upstream IDP did not return a refresh token",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().WithoutRefreshToken().Build()),
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: newRequestPath().WithState(happyState).String(),
|
||||||
|
csrfCookie: happyCSRFCookie,
|
||||||
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBody: "Unprocessable Entity: refresh token not returned by upstream provider during authcode exchange\n",
|
||||||
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "return an error when upstream IDP returned an empty refresh token",
|
||||||
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(happyUpstream().WithEmptyRefreshToken().Build()),
|
||||||
|
method: http.MethodGet,
|
||||||
|
path: newRequestPath().WithState(happyState).String(),
|
||||||
|
csrfCookie: happyCSRFCookie,
|
||||||
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
|
wantContentType: htmlContentType,
|
||||||
|
wantBody: "Unprocessable Entity: refresh token not returned by upstream provider during authcode exchange\n",
|
||||||
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is present with false value",
|
name: "upstream IDP configures username claim as special claim `email` and `email_verified` upstream claim is present with false value",
|
||||||
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(
|
idps: oidctestutil.NewUpstreamIDPListerBuilder().WithOIDC(
|
||||||
@ -339,6 +383,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -363,6 +408,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -387,6 +433,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -537,6 +584,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -563,6 +611,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -660,6 +709,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
wantDownstreamNonce: downstreamNonce,
|
wantDownstreamNonce: downstreamNonce,
|
||||||
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
wantDownstreamPKCEChallenge: downstreamPKCEChallenge,
|
||||||
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
wantDownstreamPKCEChallengeMethod: downstreamPKCEChallengeMethod,
|
||||||
|
wantDownstreamCustomSessionData: happyDownstreamCustomSessionData,
|
||||||
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
wantAuthcodeExchangeCall: &expectedAuthcodeExchange{
|
||||||
performedByUpstreamName: happyUpstreamIDPName,
|
performedByUpstreamName: happyUpstreamIDPName,
|
||||||
args: happyExchangeAndValidateTokensArgs,
|
args: happyExchangeAndValidateTokensArgs,
|
||||||
@ -907,6 +957,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
test.wantDownstreamNonce,
|
test.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
downstreamClientID,
|
||||||
downstreamRedirectURI,
|
downstreamRedirectURI,
|
||||||
|
test.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Otherwise, expect an empty response body.
|
// Otherwise, expect an empty response body.
|
||||||
@ -933,6 +984,7 @@ func TestCallbackEndpoint(t *testing.T) {
|
|||||||
test.wantDownstreamNonce,
|
test.wantDownstreamNonce,
|
||||||
downstreamClientID,
|
downstreamClientID,
|
||||||
downstreamRedirectURI,
|
downstreamRedirectURI,
|
||||||
|
test.wantDownstreamCustomSessionData,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1036,6 +1088,7 @@ func (b *upstreamStateParamBuilder) WithStateVersion(version string) *upstreamSt
|
|||||||
func happyUpstream() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
func happyUpstream() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
return oidctestutil.NewTestUpstreamOIDCIdentityProviderBuilder().
|
||||||
WithName(happyUpstreamIDPName).
|
WithName(happyUpstreamIDPName).
|
||||||
|
WithResourceUID(happyUpstreamIDPResourceUID).
|
||||||
WithClientID("some-client-id").
|
WithClientID("some-client-id").
|
||||||
WithScopes([]string{"scope1", "scope2"}).
|
WithScopes([]string{"scope1", "scope2"}).
|
||||||
WithUsernameClaim(oidcUpstreamUsernameClaim).
|
WithUsernameClaim(oidcUpstreamUsernameClaim).
|
||||||
@ -1046,6 +1099,7 @@ func happyUpstream() *oidctestutil.TestUpstreamOIDCIdentityProviderBuilder {
|
|||||||
WithIDTokenClaim(oidcUpstreamGroupsClaim, oidcUpstreamGroupMembership).
|
WithIDTokenClaim(oidcUpstreamGroupsClaim, oidcUpstreamGroupMembership).
|
||||||
WithIDTokenClaim("other-claim", "should be ignored").
|
WithIDTokenClaim("other-claim", "should be ignored").
|
||||||
WithAllowPasswordGrant(false).
|
WithAllowPasswordGrant(false).
|
||||||
|
WithRefreshToken(oidcUpstreamRefreshToken).
|
||||||
WithPasswordGrantError(errors.New("the callback endpoint should not use password grants"))
|
WithPasswordGrantError(errors.New("the callback endpoint should not use password grants"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// MakeDownstreamSession creates a downstream OIDC session.
|
// MakeDownstreamSession creates a downstream OIDC session.
|
||||||
func MakeDownstreamSession(subject string, username string, groups []string) *psession.PinnipedSession {
|
func MakeDownstreamSession(subject string, username string, groups []string, custom *psession.CustomSessionData) *psession.PinnipedSession {
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
openIDSession := &psession.PinnipedSession{
|
openIDSession := &psession.PinnipedSession{
|
||||||
Fosite: &openid.DefaultSession{
|
Fosite: &openid.DefaultSession{
|
||||||
@ -46,6 +46,7 @@ func MakeDownstreamSession(subject string, username string, groups []string) *ps
|
|||||||
AuthTime: now,
|
AuthTime: now,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Custom: custom,
|
||||||
}
|
}
|
||||||
if groups == nil {
|
if groups == nil {
|
||||||
groups = []string{}
|
groups = []string{}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"go.pinniped.dev/internal/authenticators"
|
"go.pinniped.dev/internal/authenticators"
|
||||||
"go.pinniped.dev/pkg/oidcclient/nonce"
|
"go.pinniped.dev/pkg/oidcclient/nonce"
|
||||||
@ -24,6 +25,9 @@ type UpstreamOIDCIdentityProviderI interface {
|
|||||||
// GetClientID returns the OAuth client ID registered with the upstream provider to be used in the authorization code flow.
|
// GetClientID returns the OAuth client ID registered with the upstream provider to be used in the authorization code flow.
|
||||||
GetClientID() string
|
GetClientID() string
|
||||||
|
|
||||||
|
// GetResourceUID returns the Kubernetes resource ID
|
||||||
|
GetResourceUID() types.UID
|
||||||
|
|
||||||
// GetAuthorizationURL returns the Authorization Endpoint fetched from discovery.
|
// GetAuthorizationURL returns the Authorization Endpoint fetched from discovery.
|
||||||
GetAuthorizationURL() *url.URL
|
GetAuthorizationURL() *url.URL
|
||||||
|
|
||||||
@ -42,6 +46,9 @@ type UpstreamOIDCIdentityProviderI interface {
|
|||||||
// flow with this upstream provider. When false, it should not be allowed.
|
// flow with this upstream provider. When false, it should not be allowed.
|
||||||
AllowsPasswordGrant() bool
|
AllowsPasswordGrant() bool
|
||||||
|
|
||||||
|
// GetAdditionalAuthcodeParams returns additional params to be sent on authcode requests.
|
||||||
|
GetAdditionalAuthcodeParams() map[string]string
|
||||||
|
|
||||||
// PasswordCredentialsGrantAndValidateTokens performs upstream OIDC resource owner password credentials grant and
|
// PasswordCredentialsGrantAndValidateTokens performs upstream OIDC resource owner password credentials grant and
|
||||||
// token validation. Returns the validated raw tokens as well as the parsed claims of the ID token.
|
// token validation. Returns the validated raw tokens as well as the parsed claims of the ID token.
|
||||||
PasswordCredentialsGrantAndValidateTokens(ctx context.Context, username, password string) (*oidctypes.Token, error)
|
PasswordCredentialsGrantAndValidateTokens(ctx context.Context, username, password string) (*oidctypes.Token, error)
|
||||||
@ -68,6 +75,9 @@ type UpstreamLDAPIdentityProviderI interface {
|
|||||||
// identifier by being combined with the user's UID, since user UIDs are only unique within one provider.
|
// identifier by being combined with the user's UID, since user UIDs are only unique within one provider.
|
||||||
GetURL() *url.URL
|
GetURL() *url.URL
|
||||||
|
|
||||||
|
// GetResourceUID returns the Kubernetes resource ID
|
||||||
|
GetResourceUID() types.UID
|
||||||
|
|
||||||
// UserAuthenticator adds an interface method for performing user authentication against the upstream LDAP provider.
|
// UserAuthenticator adds an interface method for performing user authentication against the upstream LDAP provider.
|
||||||
authenticators.UserAuthenticator
|
authenticators.UserAuthenticator
|
||||||
}
|
}
|
||||||
|
@ -264,6 +264,7 @@ func TestManager(t *testing.T) {
|
|||||||
"groups": "test-group1",
|
"groups": "test-group1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RefreshToken: &oidctypes.RefreshToken{Token: "some-opaque-token"},
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
}).Build()
|
}).Build()
|
||||||
|
@ -1374,7 +1374,7 @@ func simulateAuthEndpointHavingAlreadyRun(t *testing.T, authRequest *http.Reques
|
|||||||
Subject: "", // not used, note that callback_handler.go does not set this
|
Subject: "", // not used, note that callback_handler.go does not set this
|
||||||
Username: "", // not used, note that callback_handler.go does not set this
|
Username: "", // not used, note that callback_handler.go does not set this
|
||||||
},
|
},
|
||||||
Custom: &psession.PinnipedSessionData{
|
Custom: &psession.CustomSessionData{
|
||||||
OIDC: &psession.OIDCSessionData{
|
OIDC: &psession.OIDCSessionData{
|
||||||
UpstreamRefreshToken: "starting-fake-refresh-token",
|
UpstreamRefreshToken: "starting-fake-refresh-token",
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/ory/fosite"
|
"github.com/ory/fosite"
|
||||||
"github.com/ory/fosite/handler/openid"
|
"github.com/ory/fosite/handler/openid"
|
||||||
"github.com/ory/fosite/token/jwt"
|
"github.com/ory/fosite/token/jwt"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PinnipedSession is a session container which includes the fosite standard stuff plus custom Pinniped stuff.
|
// PinnipedSession is a session container which includes the fosite standard stuff plus custom Pinniped stuff.
|
||||||
@ -18,20 +19,20 @@ type PinnipedSession struct {
|
|||||||
Fosite *openid.DefaultSession `json:"fosite,omitempty"`
|
Fosite *openid.DefaultSession `json:"fosite,omitempty"`
|
||||||
|
|
||||||
// Custom Pinniped extensions to the session data.
|
// Custom Pinniped extensions to the session data.
|
||||||
Custom *PinnipedSessionData `json:"custom,omitempty"`
|
Custom *CustomSessionData `json:"custom,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ openid.Session = &PinnipedSession{}
|
var _ openid.Session = &PinnipedSession{}
|
||||||
|
|
||||||
// PinnipedSessionData is the custom session data needed by Pinniped. It should be treated as a union type,
|
// CustomSessionData is the custom session data needed by Pinniped. It should be treated as a union type,
|
||||||
// where the value of ProviderType decides which other fields to use.
|
// where the value of ProviderType decides which other fields to use.
|
||||||
type PinnipedSessionData struct {
|
type CustomSessionData struct {
|
||||||
// The Kubernetes resource UID of the identity provider CRD for the upstream IDP used to start this session.
|
// The Kubernetes resource UID of the identity provider CRD for the upstream IDP used to start this session.
|
||||||
// This should be validated again upon downstream refresh to make sure that we are not refreshing against
|
// This should be validated again upon downstream refresh to make sure that we are not refreshing against
|
||||||
// a different identity provider CRD which just happens to have the same name.
|
// a different identity provider CRD which just happens to have the same name.
|
||||||
// This implies that when a user deletes an identity provider CRD, then the sessions that were started
|
// This implies that when a user deletes an identity provider CRD, then the sessions that were started
|
||||||
// using that identity provider will not be able to perform any more downstream refreshes.
|
// using that identity provider will not be able to perform any more downstream refreshes.
|
||||||
ProviderUID string `json:"providerUID"`
|
ProviderUID types.UID `json:"providerUID"`
|
||||||
|
|
||||||
// The Kubernetes resource name of the identity provider CRD for the upstream IDP used to start this session.
|
// The Kubernetes resource name of the identity provider CRD for the upstream IDP used to start this session.
|
||||||
// Used during a downstream refresh to decide which upstream to refresh.
|
// Used during a downstream refresh to decide which upstream to refresh.
|
||||||
@ -40,12 +41,20 @@ type PinnipedSessionData struct {
|
|||||||
|
|
||||||
// The type of the identity provider for the upstream IDP used to start this session.
|
// The type of the identity provider for the upstream IDP used to start this session.
|
||||||
// Used during a downstream refresh to decide which upstream to refresh.
|
// Used during a downstream refresh to decide which upstream to refresh.
|
||||||
ProviderType string `json:"providerType"`
|
ProviderType ProviderType `json:"providerType"`
|
||||||
|
|
||||||
// Only used when ProviderType == "oidc".
|
// Only used when ProviderType == "oidc".
|
||||||
OIDC *OIDCSessionData `json:"oidc,omitempty"`
|
OIDC *OIDCSessionData `json:"oidc,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProviderType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProviderTypeOIDC ProviderType = "oidc"
|
||||||
|
ProviderTypeLDAP ProviderType = "ldap"
|
||||||
|
ProviderTypeActiveDirectory ProviderType = "activedirectory"
|
||||||
|
)
|
||||||
|
|
||||||
// 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"`
|
||||||
@ -58,7 +67,7 @@ func NewPinnipedSession() *PinnipedSession {
|
|||||||
Claims: &jwt.IDTokenClaims{},
|
Claims: &jwt.IDTokenClaims{},
|
||||||
Headers: &jwt.Headers{},
|
Headers: &jwt.Headers{},
|
||||||
},
|
},
|
||||||
Custom: &PinnipedSessionData{},
|
Custom: &CustomSessionData{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
@ -59,12 +60,17 @@ type PasswordCredentialsGrantAndValidateTokensArgs struct {
|
|||||||
|
|
||||||
type TestUpstreamLDAPIdentityProvider struct {
|
type TestUpstreamLDAPIdentityProvider struct {
|
||||||
Name string
|
Name string
|
||||||
|
ResourceUID types.UID
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
AuthenticateFunc func(ctx context.Context, username, password string) (*authenticator.Response, bool, error)
|
AuthenticateFunc func(ctx context.Context, username, password string) (*authenticator.Response, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ provider.UpstreamLDAPIdentityProviderI = &TestUpstreamLDAPIdentityProvider{}
|
var _ provider.UpstreamLDAPIdentityProviderI = &TestUpstreamLDAPIdentityProvider{}
|
||||||
|
|
||||||
|
func (u *TestUpstreamLDAPIdentityProvider) GetResourceUID() types.UID {
|
||||||
|
return u.ResourceUID
|
||||||
|
}
|
||||||
|
|
||||||
func (u *TestUpstreamLDAPIdentityProvider) GetName() string {
|
func (u *TestUpstreamLDAPIdentityProvider) GetName() string {
|
||||||
return u.Name
|
return u.Name
|
||||||
}
|
}
|
||||||
@ -80,10 +86,12 @@ func (u *TestUpstreamLDAPIdentityProvider) GetURL() *url.URL {
|
|||||||
type TestUpstreamOIDCIdentityProvider struct {
|
type TestUpstreamOIDCIdentityProvider struct {
|
||||||
Name string
|
Name string
|
||||||
ClientID string
|
ClientID string
|
||||||
|
ResourceUID types.UID
|
||||||
AuthorizationURL url.URL
|
AuthorizationURL url.URL
|
||||||
UsernameClaim string
|
UsernameClaim string
|
||||||
GroupsClaim string
|
GroupsClaim string
|
||||||
Scopes []string
|
Scopes []string
|
||||||
|
AdditionalAuthcodeParams map[string]string
|
||||||
AllowPasswordGrant bool
|
AllowPasswordGrant bool
|
||||||
|
|
||||||
ExchangeAuthcodeAndValidateTokensFunc func(
|
ExchangeAuthcodeAndValidateTokensFunc func(
|
||||||
@ -105,6 +113,16 @@ type TestUpstreamOIDCIdentityProvider struct {
|
|||||||
passwordCredentialsGrantAndValidateTokensArgs []*PasswordCredentialsGrantAndValidateTokensArgs
|
passwordCredentialsGrantAndValidateTokensArgs []*PasswordCredentialsGrantAndValidateTokensArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ provider.UpstreamOIDCIdentityProviderI = &TestUpstreamOIDCIdentityProvider{}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProvider) GetResourceUID() types.UID {
|
||||||
|
return u.ResourceUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProvider) GetAdditionalAuthcodeParams() map[string]string {
|
||||||
|
return u.AdditionalAuthcodeParams
|
||||||
|
}
|
||||||
|
|
||||||
func (u *TestUpstreamOIDCIdentityProvider) GetName() string {
|
func (u *TestUpstreamOIDCIdentityProvider) GetName() string {
|
||||||
return u.Name
|
return u.Name
|
||||||
}
|
}
|
||||||
@ -304,12 +322,15 @@ func NewUpstreamIDPListerBuilder() *UpstreamIDPListerBuilder {
|
|||||||
|
|
||||||
type TestUpstreamOIDCIdentityProviderBuilder struct {
|
type TestUpstreamOIDCIdentityProviderBuilder struct {
|
||||||
name string
|
name string
|
||||||
|
resourceUID types.UID
|
||||||
clientID string
|
clientID string
|
||||||
scopes []string
|
scopes []string
|
||||||
idToken map[string]interface{}
|
idToken map[string]interface{}
|
||||||
|
refreshToken *oidctypes.RefreshToken
|
||||||
usernameClaim string
|
usernameClaim string
|
||||||
groupsClaim string
|
groupsClaim string
|
||||||
authorizationURL url.URL
|
authorizationURL url.URL
|
||||||
|
additionalAuthcodeParams map[string]string
|
||||||
allowPasswordGrant bool
|
allowPasswordGrant bool
|
||||||
authcodeExchangeErr error
|
authcodeExchangeErr error
|
||||||
passwordGrantErr error
|
passwordGrantErr error
|
||||||
@ -320,6 +341,11 @@ func (u *TestUpstreamOIDCIdentityProviderBuilder) WithName(value string) *TestUp
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithResourceUID(value types.UID) *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
|
u.resourceUID = value
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithClientID(value string) *TestUpstreamOIDCIdentityProviderBuilder {
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithClientID(value string) *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
u.clientID = value
|
u.clientID = value
|
||||||
return u
|
return u
|
||||||
@ -373,6 +399,26 @@ func (u *TestUpstreamOIDCIdentityProviderBuilder) WithoutIDTokenClaim(claim stri
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithAdditionalAuthcodeParams(params map[string]string) *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
|
u.additionalAuthcodeParams = params
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithRefreshToken(token string) *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
|
u.refreshToken = &oidctypes.RefreshToken{Token: token}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithEmptyRefreshToken() *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
|
u.refreshToken = &oidctypes.RefreshToken{Token: ""}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithoutRefreshToken() *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
|
u.refreshToken = nil
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithUpstreamAuthcodeExchangeError(err error) *TestUpstreamOIDCIdentityProviderBuilder {
|
func (u *TestUpstreamOIDCIdentityProviderBuilder) WithUpstreamAuthcodeExchangeError(err error) *TestUpstreamOIDCIdentityProviderBuilder {
|
||||||
u.authcodeExchangeErr = err
|
u.authcodeExchangeErr = err
|
||||||
return u
|
return u
|
||||||
@ -387,22 +433,24 @@ func (u *TestUpstreamOIDCIdentityProviderBuilder) Build() *TestUpstreamOIDCIdent
|
|||||||
return &TestUpstreamOIDCIdentityProvider{
|
return &TestUpstreamOIDCIdentityProvider{
|
||||||
Name: u.name,
|
Name: u.name,
|
||||||
ClientID: u.clientID,
|
ClientID: u.clientID,
|
||||||
|
ResourceUID: u.resourceUID,
|
||||||
UsernameClaim: u.usernameClaim,
|
UsernameClaim: u.usernameClaim,
|
||||||
GroupsClaim: u.groupsClaim,
|
GroupsClaim: u.groupsClaim,
|
||||||
Scopes: u.scopes,
|
Scopes: u.scopes,
|
||||||
AllowPasswordGrant: u.allowPasswordGrant,
|
AllowPasswordGrant: u.allowPasswordGrant,
|
||||||
AuthorizationURL: u.authorizationURL,
|
AuthorizationURL: u.authorizationURL,
|
||||||
|
AdditionalAuthcodeParams: u.additionalAuthcodeParams,
|
||||||
ExchangeAuthcodeAndValidateTokensFunc: func(ctx context.Context, authcode string, pkceCodeVerifier pkce.Code, expectedIDTokenNonce nonce.Nonce) (*oidctypes.Token, error) {
|
ExchangeAuthcodeAndValidateTokensFunc: func(ctx context.Context, authcode string, pkceCodeVerifier pkce.Code, expectedIDTokenNonce nonce.Nonce) (*oidctypes.Token, error) {
|
||||||
if u.authcodeExchangeErr != nil {
|
if u.authcodeExchangeErr != nil {
|
||||||
return nil, u.authcodeExchangeErr
|
return nil, u.authcodeExchangeErr
|
||||||
}
|
}
|
||||||
return &oidctypes.Token{IDToken: &oidctypes.IDToken{Claims: u.idToken}}, nil
|
return &oidctypes.Token{IDToken: &oidctypes.IDToken{Claims: u.idToken}, RefreshToken: u.refreshToken}, nil
|
||||||
},
|
},
|
||||||
PasswordCredentialsGrantAndValidateTokensFunc: func(ctx context.Context, username, password string) (*oidctypes.Token, error) {
|
PasswordCredentialsGrantAndValidateTokensFunc: func(ctx context.Context, username, password string) (*oidctypes.Token, error) {
|
||||||
if u.passwordGrantErr != nil {
|
if u.passwordGrantErr != nil {
|
||||||
return nil, u.passwordGrantErr
|
return nil, u.passwordGrantErr
|
||||||
}
|
}
|
||||||
return &oidctypes.Token{IDToken: &oidctypes.IDToken{Claims: u.idToken}}, nil
|
return &oidctypes.Token{IDToken: &oidctypes.IDToken{Claims: u.idToken}, RefreshToken: u.refreshToken}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,6 +527,7 @@ func RequireAuthCodeRegexpMatch(
|
|||||||
wantDownstreamNonce string,
|
wantDownstreamNonce string,
|
||||||
wantDownstreamClientID string,
|
wantDownstreamClientID string,
|
||||||
wantDownstreamRedirectURI string,
|
wantDownstreamRedirectURI string,
|
||||||
|
wantCustomSessionData *psession.CustomSessionData,
|
||||||
) {
|
) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -513,6 +562,7 @@ func RequireAuthCodeRegexpMatch(
|
|||||||
wantDownstreamRequestedScopes,
|
wantDownstreamRequestedScopes,
|
||||||
wantDownstreamClientID,
|
wantDownstreamClientID,
|
||||||
wantDownstreamRedirectURI,
|
wantDownstreamRedirectURI,
|
||||||
|
wantCustomSessionData,
|
||||||
)
|
)
|
||||||
|
|
||||||
// One PKCE should have been stored.
|
// One PKCE should have been stored.
|
||||||
@ -563,6 +613,7 @@ func validateAuthcodeStorage(
|
|||||||
wantDownstreamRequestedScopes []string,
|
wantDownstreamRequestedScopes []string,
|
||||||
wantDownstreamClientID string,
|
wantDownstreamClientID string,
|
||||||
wantDownstreamRedirectURI string,
|
wantDownstreamRedirectURI string,
|
||||||
|
wantCustomSessionData *psession.CustomSessionData,
|
||||||
) (*fosite.Request, *psession.PinnipedSession) {
|
) (*fosite.Request, *psession.PinnipedSession) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -634,6 +685,9 @@ func validateAuthcodeStorage(
|
|||||||
require.Empty(t, actualClaims.AuthenticationContextClassReference)
|
require.Empty(t, actualClaims.AuthenticationContextClassReference)
|
||||||
require.Empty(t, actualClaims.AuthenticationMethodsReference)
|
require.Empty(t, actualClaims.AuthenticationMethodsReference)
|
||||||
|
|
||||||
|
// Check that the custom Pinniped session data matches.
|
||||||
|
require.Equal(t, wantCustomSessionData, storedSessionFromAuthcode.Custom)
|
||||||
|
|
||||||
return storedRequestFromAuthcode, storedSessionFromAuthcode
|
return storedRequestFromAuthcode, storedSessionFromAuthcode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ func NewFakePinnipedSession() *psession.PinnipedSession {
|
|||||||
Username: "snorlax",
|
Username: "snorlax",
|
||||||
Subject: "panda",
|
Subject: "panda",
|
||||||
},
|
},
|
||||||
Custom: &psession.PinnipedSessionData{
|
Custom: &psession.CustomSessionData{
|
||||||
ProviderUID: "fake-provider-uid",
|
ProviderUID: "fake-provider-uid",
|
||||||
ProviderType: "fake-provider-type",
|
ProviderType: "fake-provider-type",
|
||||||
ProviderName: "fake-provider-name",
|
ProviderName: "fake-provider-name",
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-ldap/ldap/v3"
|
"github.com/go-ldap/ldap/v3"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/utils/trace"
|
"k8s.io/utils/trace"
|
||||||
@ -82,6 +83,9 @@ type ProviderConfig struct {
|
|||||||
// Name is the unique name of this upstream LDAP IDP.
|
// Name is the unique name of this upstream LDAP IDP.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
// ResourceUID is the Kubernetes resource UID of this identity provider.
|
||||||
|
ResourceUID types.UID
|
||||||
|
|
||||||
// Host is the hostname or "hostname:port" of the LDAP server. When the port is not specified,
|
// Host is the hostname or "hostname:port" of the LDAP server. When the port is not specified,
|
||||||
// the default LDAP port will be used.
|
// the default LDAP port will be used.
|
||||||
Host string
|
Host string
|
||||||
@ -265,6 +269,10 @@ func (p *Provider) GetName() string {
|
|||||||
return p.c.Name
|
return p.c.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) GetResourceUID() types.UID {
|
||||||
|
return p.c.ResourceUID
|
||||||
|
}
|
||||||
|
|
||||||
// Return a URL which uniquely identifies this LDAP provider, e.g. "ldaps://host.example.com:1234?base=user-search-base".
|
// Return a URL which uniquely identifies this LDAP provider, e.g. "ldaps://host.example.com:1234?base=user-search-base".
|
||||||
// This URL is not used for connecting to the provider, but rather is used for creating a globally unique user
|
// This URL is not used for connecting to the provider, but rather is used for creating a globally unique user
|
||||||
// identifier by being combined with the user's UID, since user UIDs are only unique within one provider.
|
// identifier by being combined with the user's UID, since user UIDs are only unique within one provider.
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
coreosoidc "github.com/coreos/go-oidc/v3/oidc"
|
coreosoidc "github.com/coreos/go-oidc/v3/oidc"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
|
||||||
"go.pinniped.dev/internal/httputil/httperr"
|
"go.pinniped.dev/internal/httputil/httperr"
|
||||||
@ -32,11 +33,13 @@ func New(config *oauth2.Config, provider *coreosoidc.Provider, client *http.Clie
|
|||||||
// ProviderConfig holds the active configuration of an upstream OIDC provider.
|
// ProviderConfig holds the active configuration of an upstream OIDC provider.
|
||||||
type ProviderConfig struct {
|
type ProviderConfig struct {
|
||||||
Name string
|
Name string
|
||||||
|
ResourceUID types.UID
|
||||||
UsernameClaim string
|
UsernameClaim string
|
||||||
GroupsClaim string
|
GroupsClaim string
|
||||||
Config *oauth2.Config
|
Config *oauth2.Config
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
AllowPasswordGrant bool
|
AllowPasswordGrant bool
|
||||||
|
AdditionalAuthcodeParams map[string]string
|
||||||
Provider interface {
|
Provider interface {
|
||||||
Verifier(*coreosoidc.Config) *coreosoidc.IDTokenVerifier
|
Verifier(*coreosoidc.Config) *coreosoidc.IDTokenVerifier
|
||||||
Claims(v interface{}) error
|
Claims(v interface{}) error
|
||||||
@ -44,6 +47,14 @@ type ProviderConfig struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProviderConfig) GetResourceUID() types.UID {
|
||||||
|
return p.ResourceUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProviderConfig) GetAdditionalAuthcodeParams() map[string]string {
|
||||||
|
return p.AdditionalAuthcodeParams
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ProviderConfig) GetName() string {
|
func (p *ProviderConfig) GetName() string {
|
||||||
return p.Name
|
return p.Name
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user