WIP on active directory integration test
This commit is contained in:
parent
8fb35c6569
commit
3b8edb84a5
@ -386,7 +386,7 @@ func TestE2EFullIntegration(t *testing.T) {
|
|||||||
t.Skip("LDAP integration test requires connectivity to an LDAP server")
|
t.Skip("LDAP integration test requires connectivity to an LDAP server")
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedUsername := env.SupervisorUpstreamLDAP.TestUserMailAttributeValue
|
expectedUsername := env.SupervisorUpstreamLDAP.TestUsernameAttributeValue
|
||||||
expectedGroups := env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs
|
expectedGroups := env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs
|
||||||
|
|
||||||
// Create a ClusterRoleBinding to give our test user from the upstream read-only access to the cluster.
|
// Create a ClusterRoleBinding to give our test user from the upstream read-only access to the cluster.
|
||||||
@ -422,7 +422,7 @@ func TestE2EFullIntegration(t *testing.T) {
|
|||||||
Base: env.SupervisorUpstreamLDAP.UserSearchBase,
|
Base: env.SupervisorUpstreamLDAP.UserSearchBase,
|
||||||
Filter: "",
|
Filter: "",
|
||||||
Attributes: idpv1alpha1.LDAPIdentityProviderUserSearchAttributes{
|
Attributes: idpv1alpha1.LDAPIdentityProviderUserSearchAttributes{
|
||||||
Username: env.SupervisorUpstreamLDAP.TestUserMailAttributeName,
|
Username: env.SupervisorUpstreamLDAP.TestUsernameAttributeName,
|
||||||
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
|
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -128,7 +128,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
Base: env.SupervisorUpstreamLDAP.UserSearchBase,
|
Base: env.SupervisorUpstreamLDAP.UserSearchBase,
|
||||||
Filter: "",
|
Filter: "",
|
||||||
Attributes: idpv1alpha1.LDAPIdentityProviderUserSearchAttributes{
|
Attributes: idpv1alpha1.LDAPIdentityProviderUserSearchAttributes{
|
||||||
Username: env.SupervisorUpstreamLDAP.TestUserMailAttributeName,
|
Username: env.SupervisorUpstreamLDAP.TestUsernameAttributeName,
|
||||||
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
|
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -150,7 +150,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
requestAuthorization: func(t *testing.T, downstreamAuthorizeURL, _ string, httpClient *http.Client) {
|
requestAuthorization: func(t *testing.T, downstreamAuthorizeURL, _ string, httpClient *http.Client) {
|
||||||
requestAuthorizationUsingLDAPIdentityProvider(t,
|
requestAuthorizationUsingLDAPIdentityProvider(t,
|
||||||
downstreamAuthorizeURL,
|
downstreamAuthorizeURL,
|
||||||
env.SupervisorUpstreamLDAP.TestUserMailAttributeValue, // username to present to server during login
|
env.SupervisorUpstreamLDAP.TestUsernameAttributeValue, // username to present to server during login
|
||||||
env.SupervisorUpstreamLDAP.TestUserPassword, // password to present to server during login
|
env.SupervisorUpstreamLDAP.TestUserPassword, // password to present to server during login
|
||||||
httpClient,
|
httpClient,
|
||||||
)
|
)
|
||||||
@ -162,7 +162,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
"&sub=" + base64.RawURLEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeValue)),
|
"&sub=" + base64.RawURLEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeValue)),
|
||||||
),
|
),
|
||||||
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
|
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
|
||||||
wantDownstreamIDTokenUsernameToMatch: regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUserMailAttributeValue),
|
wantDownstreamIDTokenUsernameToMatch: regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUsernameAttributeValue),
|
||||||
wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs,
|
wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -232,6 +232,56 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "activedirectory with all default options",
|
name: "activedirectory with all default options",
|
||||||
|
maybeSkip: func(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
if len(env.ToolsNamespace) == 0 && !env.HasCapability(testlib.CanReachInternetLDAPPorts) {
|
||||||
|
t.Skip("LDAP integration test requires connectivity to an LDAP server")
|
||||||
|
}
|
||||||
|
if env.SupervisorUpstreamActiveDirectory.Host == "" {
|
||||||
|
t.Skip("Active Directory hostname not specified")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createIDP: func(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
secret := testlib.CreateTestSecret(t, env.SupervisorNamespace, "ad-service-account", v1.SecretTypeBasicAuth,
|
||||||
|
map[string]string{
|
||||||
|
v1.BasicAuthUsernameKey: env.SupervisorUpstreamActiveDirectory.BindUsername,
|
||||||
|
v1.BasicAuthPasswordKey: env.SupervisorUpstreamActiveDirectory.BindPassword,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
adIDP := testlib.CreateTestActiveDirectoryIdentityProvider(t, idpv1alpha1.ActiveDirectoryIdentityProviderSpec{
|
||||||
|
Host: env.SupervisorUpstreamLDAP.Host,
|
||||||
|
TLS: &idpv1alpha1.TLSSpec{
|
||||||
|
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamActiveDirectory.CABundle)),
|
||||||
|
},
|
||||||
|
Bind: idpv1alpha1.ActiveDirectoryIdentityProviderBind{
|
||||||
|
SecretName: secret.Name,
|
||||||
|
},
|
||||||
|
}, idpv1alpha1.ActiveDirectoryPhaseReady)
|
||||||
|
expectedMsg := fmt.Sprintf(
|
||||||
|
`successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`,
|
||||||
|
env.SupervisorUpstreamActiveDirectory.Host, env.SupervisorUpstreamActiveDirectory.BindUsername,
|
||||||
|
secret.Name, secret.ResourceVersion,
|
||||||
|
)
|
||||||
|
requireSuccessfulActiveDirectoryIdentityProviderConditions(t, adIDP, expectedMsg) // TODO refactor to be same as LDAP func
|
||||||
|
},
|
||||||
|
requestAuthorization: func(t *testing.T, downstreamAuthorizeURL, _ string, httpClient *http.Client) {
|
||||||
|
requestAuthorizationUsingLDAPIdentityProvider(t,
|
||||||
|
downstreamAuthorizeURL,
|
||||||
|
env.SupervisorUpstreamActiveDirectory.TestUsernameAttributeName, // username to present to server during login
|
||||||
|
env.SupervisorUpstreamActiveDirectory.TestUserPassword, // password to present to server during login
|
||||||
|
httpClient,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// the ID token Subject should be the Host URL plus the value pulled from the requested UserSearch.Attributes.UID attribute
|
||||||
|
wantDownstreamIDTokenSubjectToMatch: regexp.QuoteMeta(
|
||||||
|
"ldaps://" + env.SupervisorUpstreamActiveDirectory.Host +
|
||||||
|
"?base=" + url.QueryEscape(env.SupervisorUpstreamActiveDirectory.UserSearchBase) +
|
||||||
|
"&sub=" + base64.RawURLEncoding.EncodeToString([]byte(env.SupervisorUpstreamActiveDirectory.TestUserUniqueIDAttributeValue)),
|
||||||
|
),
|
||||||
|
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
|
||||||
|
wantDownstreamIDTokenUsernameToMatch: regexp.QuoteMeta(env.SupervisorUpstreamActiveDirectory.TestUserDN),
|
||||||
|
wantDownstreamIDTokenGroups: env.SupervisorUpstreamActiveDirectory.TestUserDirectGroupsCNs,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
@ -274,6 +324,30 @@ func requireSuccessfulLDAPIdentityProviderConditions(t *testing.T, ldapIDP *idpv
|
|||||||
{"LDAPConnectionValid", "True", "Success"},
|
{"LDAPConnectionValid", "True", "Success"},
|
||||||
}, conditionsSummary)
|
}, conditionsSummary)
|
||||||
}
|
}
|
||||||
|
func requireSuccessfulActiveDirectoryIdentityProviderConditions(t *testing.T, adIDP *idpv1alpha1.ActiveDirectoryIdentityProvider, expectedActiveDirectoryConnectionValidMessage string) {
|
||||||
|
require.Len(t, adIDP.Status.Conditions, 3)
|
||||||
|
|
||||||
|
conditionsSummary := [][]string{}
|
||||||
|
for _, condition := range adIDP.Status.Conditions {
|
||||||
|
conditionsSummary = append(conditionsSummary, []string{condition.Type, string(condition.Status), condition.Reason})
|
||||||
|
t.Logf("Saw ActiveDirectoryIdentityProvider Status.Condition Type=%s Status=%s Reason=%s Message=%s",
|
||||||
|
condition.Type, string(condition.Status), condition.Reason, condition.Message)
|
||||||
|
switch condition.Type {
|
||||||
|
case "BindSecretValid":
|
||||||
|
require.Equal(t, "loaded bind secret", condition.Message)
|
||||||
|
case "TLSConfigurationValid":
|
||||||
|
require.Equal(t, "loaded TLS configuration", condition.Message)
|
||||||
|
case "LDAPConnectionValid":
|
||||||
|
require.Equal(t, expectedActiveDirectoryConnectionValidMessage, condition.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require.ElementsMatch(t, [][]string{
|
||||||
|
{"BindSecretValid", "True", "Success"},
|
||||||
|
{"TLSConfigurationValid", "True", "Success"},
|
||||||
|
{"LDAPConnectionValid", "True", "Success"},
|
||||||
|
}, conditionsSummary)
|
||||||
|
}
|
||||||
|
|
||||||
func testSupervisorLogin(
|
func testSupervisorLogin(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
|
@ -434,6 +434,47 @@ func CreateTestLDAPIdentityProvider(t *testing.T, spec idpv1alpha1.LDAPIdentityP
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateTestActiveDirectoryIdentityProvider(t *testing.T, spec idpv1alpha1.ActiveDirectoryIdentityProviderSpec, expectedPhase idpv1alpha1.ActiveDirectoryIdentityProviderPhase) *idpv1alpha1.ActiveDirectoryIdentityProvider {
|
||||||
|
t.Helper()
|
||||||
|
env := IntegrationEnv(t)
|
||||||
|
client := NewSupervisorClientset(t)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Create the LDAPIdentityProvider using GenerateName to get a random name.
|
||||||
|
upstreams := client.IDPV1alpha1().ActiveDirectoryIdentityProviders(env.SupervisorNamespace)
|
||||||
|
|
||||||
|
created, err := upstreams.Create(ctx, &idpv1alpha1.ActiveDirectoryIdentityProvider{
|
||||||
|
ObjectMeta: testObjectMeta(t, "upstream-ad-idp"),
|
||||||
|
Spec: spec,
|
||||||
|
}, metav1.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Always clean this up after this point.
|
||||||
|
t.Cleanup(func() {
|
||||||
|
t.Logf("cleaning up test ActiveDirectoryIdentityProvider %s/%s", created.Namespace, created.Name)
|
||||||
|
err := upstreams.Delete(context.Background(), created.Name, metav1.DeleteOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
t.Logf("created test ActiveDirectoryIdentityProvider %s", created.Name)
|
||||||
|
|
||||||
|
// Wait for the LDAPIdentityProvider to enter the expected phase (or time out).
|
||||||
|
var result *idpv1alpha1.ActiveDirectoryIdentityProvider
|
||||||
|
RequireEventuallyf(t,
|
||||||
|
func(requireEventually *require.Assertions) {
|
||||||
|
var err error
|
||||||
|
result, err = upstreams.Get(ctx, created.Name, metav1.GetOptions{})
|
||||||
|
requireEventually.NoErrorf(err, "error while getting ActiveDirectoryIdentityProvider %s/%s", created.Namespace, created.Name)
|
||||||
|
requireEventually.Equalf(expectedPhase, result.Status.Phase, "ActiveDirectoryIdentityProvider is not in phase %s: %v", expectedPhase, Sdump(result))
|
||||||
|
},
|
||||||
|
2*time.Minute, // it takes 1 minute for a failed LDAP TLS connection test to timeout before it tries using StartTLS, so wait longer than that
|
||||||
|
1*time.Second,
|
||||||
|
"expected the ActiveDirectoryIdentityProvider to go into phase %s",
|
||||||
|
expectedPhase,
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func CreateTestClusterRoleBinding(t *testing.T, subject rbacv1.Subject, roleRef rbacv1.RoleRef) *rbacv1.ClusterRoleBinding {
|
func CreateTestClusterRoleBinding(t *testing.T, subject rbacv1.Subject, roleRef rbacv1.RoleRef) *rbacv1.ClusterRoleBinding {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
client := NewKubernetesClientset(t)
|
client := NewKubernetesClientset(t)
|
||||||
|
@ -61,9 +61,10 @@ type TestEnv struct {
|
|||||||
ExpectedGroups []string `json:"expectedGroups"`
|
ExpectedGroups []string `json:"expectedGroups"`
|
||||||
} `json:"testUser"`
|
} `json:"testUser"`
|
||||||
|
|
||||||
CLIUpstreamOIDC TestOIDCUpstream `json:"cliOIDCUpstream"`
|
CLIUpstreamOIDC TestOIDCUpstream `json:"cliOIDCUpstream"`
|
||||||
SupervisorUpstreamOIDC TestOIDCUpstream `json:"supervisorOIDCUpstream"`
|
SupervisorUpstreamOIDC TestOIDCUpstream `json:"supervisorOIDCUpstream"`
|
||||||
SupervisorUpstreamLDAP TestLDAPUpstream `json:"supervisorLDAPUpstream"`
|
SupervisorUpstreamLDAP TestLDAPUpstream `json:"supervisorLDAPUpstream"`
|
||||||
|
SupervisorUpstreamActiveDirectory TestLDAPUpstream `json:"supervisorActiveDirectoryUpstream"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestOIDCUpstream struct {
|
type TestOIDCUpstream struct {
|
||||||
@ -91,8 +92,8 @@ type TestLDAPUpstream struct {
|
|||||||
TestUserDN string `json:"testUserDN"`
|
TestUserDN string `json:"testUserDN"`
|
||||||
TestUserCN string `json:"testUserCN"`
|
TestUserCN string `json:"testUserCN"`
|
||||||
TestUserPassword string `json:"testUserPassword"`
|
TestUserPassword string `json:"testUserPassword"`
|
||||||
TestUserMailAttributeName string `json:"testUserMailAttributeName"`
|
TestUsernameAttributeName string `json:"testUserMailAttributeName"`
|
||||||
TestUserMailAttributeValue string `json:"testUserMailAttributeValue"`
|
TestUsernameAttributeValue string `json:"testUserMailAttributeValue"`
|
||||||
TestUserUniqueIDAttributeName string `json:"testUserUniqueIDAttributeName"`
|
TestUserUniqueIDAttributeName string `json:"testUserUniqueIDAttributeName"`
|
||||||
TestUserUniqueIDAttributeValue string `json:"testUserUniqueIDAttributeValue"`
|
TestUserUniqueIDAttributeValue string `json:"testUserUniqueIDAttributeValue"`
|
||||||
TestUserDirectGroupsCNs []string `json:"testUserDirectGroupsCNs"`
|
TestUserDirectGroupsCNs []string `json:"testUserDirectGroupsCNs"`
|
||||||
@ -260,13 +261,25 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
|
|||||||
TestUserCN: needEnv(t, "PINNIPED_TEST_LDAP_USER_CN"),
|
TestUserCN: needEnv(t, "PINNIPED_TEST_LDAP_USER_CN"),
|
||||||
TestUserUniqueIDAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_NAME"),
|
TestUserUniqueIDAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_NAME"),
|
||||||
TestUserUniqueIDAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_VALUE"),
|
TestUserUniqueIDAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_VALUE"),
|
||||||
TestUserMailAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_NAME"),
|
TestUsernameAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_NAME"),
|
||||||
TestUserMailAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_VALUE"),
|
TestUsernameAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_VALUE"),
|
||||||
TestUserDirectGroupsCNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_CN"), ";")),
|
TestUserDirectGroupsCNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_CN"), ";")),
|
||||||
TestUserDirectGroupsDNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_DN"), ";")),
|
TestUserDirectGroupsDNs: filterEmpty(strings.Split(needEnv(t, "PINNIPED_TEST_LDAP_EXPECTED_DIRECT_GROUPS_DN"), ";")),
|
||||||
TestUserPassword: needEnv(t, "PINNIPED_TEST_LDAP_USER_PASSWORD"),
|
TestUserPassword: needEnv(t, "PINNIPED_TEST_LDAP_USER_PASSWORD"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.SupervisorUpstreamActiveDirectory = TestLDAPUpstream{
|
||||||
|
Host: wantEnv("PINNIPED_TEST_AD_HOST", ""),
|
||||||
|
CABundle: base64Decoded(t, os.Getenv("PINNIPED_TEST_AD_LDAPS_CA_BUNDLE")),
|
||||||
|
BindUsername: wantEnv("PINNIPED_TEST_AD_BIND_ACCOUNT_USERNAME", ""),
|
||||||
|
BindPassword: wantEnv("PINNIPED_TEST_AD_BIND_ACCOUNT_PASSWORD", ""),
|
||||||
|
TestUserPassword: wantEnv("PINNIPED_TEST_AD_USER_PASSWORD", ""),
|
||||||
|
TestUserUniqueIDAttributeName: wantEnv("PINNIPED_TEST_AD_USER_UNIQUE_ID_ATTRIBUTE_NAME", ""),
|
||||||
|
TestUserUniqueIDAttributeValue: wantEnv("PINNIPED_TEST_AD_USER_UNIQUE_ID_ATTRIBUTE_VALUE", ""),
|
||||||
|
TestUsernameAttributeName: wantEnv("PINNIPED_TEST_AD_USERNAME_ATTRIBUTE_NAME", ""),
|
||||||
|
TestUsernameAttributeValue: wantEnv("PINNIPED_TEST_AD_USERNAME_ATTRIBUTE_VALUE", ""),
|
||||||
|
}
|
||||||
|
|
||||||
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsCNs)
|
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsCNs)
|
||||||
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs)
|
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user