Merge branch 'initial_ldap_group_support' into ldap_starttls

This commit is contained in:
Ryan Richard
2021-05-18 16:39:59 -07:00
29 changed files with 1784 additions and 424 deletions
+15 -28
View File
@@ -278,7 +278,7 @@ func TestE2EFullIntegration(t *testing.T) {
// Add an LDAP upstream IDP and try using it to authenticate during kubectl commands.
t.Run("with Supervisor LDAP upstream IDP", func(t *testing.T) {
expectedUsername := env.SupervisorUpstreamLDAP.TestUserMailAttributeValue
expectedGroups := []string{} // LDAP groups are not implemented yet
expectedGroups := env.SupervisorUpstreamLDAP.TestUserDirectGroupsCNs
// Create a ClusterRoleBinding to give our test user from the upstream read-only access to the cluster.
library.CreateTestClusterRoleBinding(t,
@@ -317,6 +317,13 @@ func TestE2EFullIntegration(t *testing.T) {
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
},
},
GroupSearch: idpv1alpha1.LDAPIdentityProviderGroupSearch{
Base: env.SupervisorUpstreamLDAP.GroupSearchBase,
Filter: "", // use the default value of "member={}"
Attributes: idpv1alpha1.LDAPIdentityProviderGroupSearchAttributes{
GroupName: "", // use the default value of "cn"
},
},
}, idpv1alpha1.LDAPPhaseReady)
// Use a specific session cache for this test.
@@ -438,17 +445,10 @@ func requireUserCanUseKubectlWithoutAuthenticatingAgain(
for _, g := range expectedGroups {
expectedGroupsAsEmptyInterfaces = append(expectedGroupsAsEmptyInterfaces, g)
}
require.Equal(t, expectedGroupsAsEmptyInterfaces, idTokenClaims[oidc.DownstreamGroupsClaim])
require.ElementsMatch(t, expectedGroupsAsEmptyInterfaces, idTokenClaims[oidc.DownstreamGroupsClaim])
expectedYAMLGroups := func() string {
var b strings.Builder
for _, g := range expectedGroups {
b.WriteString("\n")
b.WriteString(` - `)
b.WriteString(g)
}
return b.String()
}()
expectedGroupsPlusAuthenticated := append([]string{}, expectedGroups...)
expectedGroupsPlusAuthenticated = append(expectedGroupsPlusAuthenticated, "system:authenticated")
// Confirm we are the right user according to Kube by calling the whoami API.
kubectlCmd3 := exec.CommandContext(ctx, "kubectl", "create", "-f", "-", "-o", "yaml", "--kubeconfig", kubeconfigPath)
@@ -456,28 +456,15 @@ func requireUserCanUseKubectlWithoutAuthenticatingAgain(
kubectlCmd3.Stdin = strings.NewReader(here.Docf(`
apiVersion: identity.concierge.%s/v1alpha1
kind: WhoAmIRequest
`, env.APIGroupSuffix))
`, env.APIGroupSuffix))
kubectlOutput3, err := kubectlCmd3.CombinedOutput()
require.NoError(t, err)
require.Equal(t, here.Docf(`
apiVersion: identity.concierge.%s/v1alpha1
kind: WhoAmIRequest
metadata:
creationTimestamp: null
spec: {}
status:
kubernetesUserInfo:
user:
groups:%s
- system:authenticated
username: %s
`, env.APIGroupSuffix, expectedYAMLGroups, expectedUsername),
string(kubectlOutput3))
whoAmI := deserializeWhoAmIRequest(t, string(kubectlOutput3), env.APIGroupSuffix)
require.Equal(t, expectedUsername, whoAmI.Status.KubernetesUserInfo.User.Username)
require.ElementsMatch(t, expectedGroupsPlusAuthenticated, whoAmI.Status.KubernetesUserInfo.User.Groups)
expectedGroupsPlusAuthenticated := append([]string{}, expectedGroups...)
expectedGroupsPlusAuthenticated = append(expectedGroupsPlusAuthenticated, "system:authenticated")
// Validate that `pinniped whoami` returns the correct identity.
assertWhoami(
ctx,
+124 -14
View File
@@ -15,7 +15,6 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
@@ -70,7 +69,7 @@ func TestLDAPSearch(t *testing.T) {
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(nil)),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -79,7 +78,7 @@ func TestLDAPSearch(t *testing.T) {
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Base = "dc=pinniped,dc=dev" })),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -88,7 +87,7 @@ func TestLDAPSearch(t *testing.T) {
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Filter = "(cn={})" })),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -100,7 +99,7 @@ func TestLDAPSearch(t *testing.T) {
p.UserSearch.Filter = "cn={}"
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "cn=pinny,ou=users,dc=pinniped,dc=dev", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "cn=pinny,ou=users,dc=pinniped,dc=dev", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -111,7 +110,7 @@ func TestLDAPSearch(t *testing.T) {
p.UserSearch.Filter = "(|(cn={})(mail={}))"
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -122,7 +121,7 @@ func TestLDAPSearch(t *testing.T) {
p.UserSearch.Filter = "(|(cn={})(mail={}))"
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -131,7 +130,7 @@ func TestLDAPSearch(t *testing.T) {
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UIDAttribute = "dn" })),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "cn=pinny,ou=users,dc=pinniped,dc=dev", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "cn=pinny,ou=users,dc=pinniped,dc=dev", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -140,7 +139,7 @@ func TestLDAPSearch(t *testing.T) {
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UIDAttribute = "sn" })),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "Seal", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "Seal", Groups: []string{"ball-game-players", "seals"}},
},
},
{
@@ -149,7 +148,7 @@ func TestLDAPSearch(t *testing.T) {
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UsernameAttribute = "sn" })),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "Seal", UID: "1000", Groups: []string{}}, // note that the final answer has case preserved from the entry
User: &user.DefaultInfo{Name: "Seal", UID: "1000", Groups: []string{"ball-game-players", "seals"}}, // note that the final answer has case preserved from the entry
},
},
{
@@ -162,6 +161,75 @@ func TestLDAPSearch(t *testing.T) {
})),
wantError: `must specify UserSearch Filter when UserSearch UsernameAttribute is "dn"`,
},
{
name: "group search disabled",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.Base = ""
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
},
},
{
name: "group search base causes no groups to be found for user",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.Base = "ou=users,dc=pinniped,dc=dev" // there are no groups under this part of the tree
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
},
},
{
name: "using dn as the group name attribute",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.GroupNameAttribute = "dn"
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{
"cn=ball-game-players,ou=beach-groups,ou=groups,dc=pinniped,dc=dev",
"cn=seals,ou=groups,dc=pinniped,dc=dev",
}},
},
},
{
name: "using some other custom group name attribute",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.GroupNameAttribute = "objectClass" // silly example, but still a meaningful test
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"groupOfNames", "groupOfNames"}},
},
},
{
name: "using a more complex group search filter",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.Filter = "(&(&(objectClass=groupOfNames)(member={}))(cn=seals))"
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"seals"}},
},
},
{
name: "using a group filter which causes no groups to be found for the user",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.Filter = "foobar={}" // foobar is not a valid attribute name for this LDAP server's schema
})),
wantAuthResponse: &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
},
},
{
name: "when the bind user username is not a valid DN",
username: "pinny",
@@ -211,6 +279,13 @@ func TestLDAPSearch(t *testing.T) {
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Filter = "*" })),
wantError: `error searching for user "pinny": LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`,
},
{
name: "when the group search filter does not compile",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.Filter = "*" })),
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter`,
},
{
name: "when there are too many search results for the user",
username: "pinny",
@@ -293,6 +368,13 @@ func TestLDAPSearch(t *testing.T) {
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.UIDAttribute = "SN" })), // this is case-sensitive
wantError: `found 0 values for attribute "SN" while searching for user "pinny", but expected 1 result`,
},
{
name: "when the GroupNameAttribute has the wrong case",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.GroupNameAttribute = "CN" })), // this is case-sensitive
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": found 0 values for attribute "CN" while searching for user "cn=pinny,ou=users,dc=pinniped,dc=dev", but expected 1 result`,
},
{
name: "when the UsernameAttribute is DN and has the wrong case",
username: "pinny",
@@ -313,21 +395,44 @@ func TestLDAPSearch(t *testing.T) {
wantError: `found 0 values for attribute "DN" while searching for user "pinny", but expected 1 result`,
},
{
name: "when the search base is invalid",
name: "when the GroupNameAttribute is DN and has the wrong case",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) {
p.GroupSearch.GroupNameAttribute = "DN" // dn must be lower-case
})),
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": found 0 values for attribute "DN" while searching for user "cn=pinny,ou=users,dc=pinniped,dc=dev", but expected 1 result`,
},
{
name: "when the user search base is invalid",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Base = "invalid-base" })),
wantError: `error searching for user "pinny": LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
},
{
name: "when the search base does not exist",
name: "when the group search base is invalid",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.Base = "invalid-base" })),
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 34 "Invalid DN Syntax": invalid DN`,
},
{
name: "when the user search base does not exist",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Base = "ou=does-not-exist,dc=pinniped,dc=dev" })),
wantError: `error searching for user "pinny": LDAP Result Code 32 "No Such Object": `,
},
{
name: "when the search base causes no search results",
name: "when the group search base does not exist",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.GroupSearch.Base = "ou=does-not-exist,dc=pinniped,dc=dev" })),
wantError: `error searching for group memberships for user with DN "cn=pinny,ou=users,dc=pinniped,dc=dev": LDAP Result Code 32 "No Such Object": `,
},
{
name: "when the user search base causes no search results",
username: "pinny",
password: pinnyPassword,
provider: upstreamldap.New(*providerConfig(func(p *upstreamldap.ProviderConfig) { p.UserSearch.Base = "ou=groups,dc=pinniped,dc=dev" })),
@@ -425,7 +530,7 @@ func TestSimultaneousRequestsOnSingleProvider(t *testing.T) {
assert.NoError(t, result.err)
assert.True(t, result.authenticated, "expected the user to be authenticated, but they were not")
assert.Equal(t, &authenticator.Response{
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{}},
User: &user.DefaultInfo{Name: "pinny", UID: "1000", Groups: []string{"ball-game-players", "seals"}},
}, result.response)
}
}
@@ -449,6 +554,11 @@ func defaultProviderConfig(env *library.TestEnv, ldapHostPort string) *upstreaml
UsernameAttribute: "cn",
UIDAttribute: "uidNumber",
},
GroupSearch: upstreamldap.GroupSearchConfig{
Base: "ou=groups,dc=pinniped,dc=dev",
Filter: "", // defaults to member={}
GroupNameAttribute: "", // defaults to cn
},
}
}
+28 -6
View File
@@ -45,6 +45,7 @@ func TestSupervisorLogin(t *testing.T) {
requestAuthorization func(t *testing.T, downstreamAuthorizeURL, downstreamCallbackURL string, httpClient *http.Client)
wantDownstreamIDTokenSubjectToMatch string
wantDownstreamIDTokenUsernameToMatch string
wantDownstreamIDTokenGroups []string
}{
{
name: "oidc",
@@ -65,9 +66,10 @@ func TestSupervisorLogin(t *testing.T) {
wantDownstreamIDTokenSubjectToMatch: regexp.QuoteMeta(env.SupervisorUpstreamOIDC.Issuer+"?sub=") + ".+",
// the ID token Username should include the upstream user ID after the upstream issuer name
wantDownstreamIDTokenUsernameToMatch: regexp.QuoteMeta(env.SupervisorUpstreamOIDC.Issuer+"?sub=") + ".+",
wantDownstreamIDTokenGroups: env.SupervisorUpstreamOIDC.ExpectedGroups,
},
{
name: "ldap with email as username",
name: "ldap with email as username and groups names as DNs",
createIDP: func(t *testing.T) {
t.Helper()
secret := library.CreateTestSecret(t, env.SupervisorNamespace, "ldap-service-account", v1.SecretTypeBasicAuth,
@@ -92,6 +94,13 @@ func TestSupervisorLogin(t *testing.T) {
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
},
},
GroupSearch: idpv1alpha1.LDAPIdentityProviderGroupSearch{
Base: env.SupervisorUpstreamLDAP.GroupSearchBase,
Filter: "",
Attributes: idpv1alpha1.LDAPIdentityProviderGroupSearchAttributes{
GroupName: "dn",
},
},
}, idpv1alpha1.LDAPPhaseReady)
expectedMsg := fmt.Sprintf(
`successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`,
@@ -114,9 +123,10 @@ func TestSupervisorLogin(t *testing.T) {
),
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
wantDownstreamIDTokenUsernameToMatch: regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUserMailAttributeValue),
wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs,
},
{
name: "ldap with CN as username ", // try another variation of configuration options
name: "ldap with CN as username and group names as CNs", // try another variation of configuration options
createIDP: func(t *testing.T) {
t.Helper()
secret := library.CreateTestSecret(t, env.SupervisorNamespace, "ldap-service-account", v1.SecretTypeBasicAuth,
@@ -141,6 +151,13 @@ func TestSupervisorLogin(t *testing.T) {
UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName,
},
},
GroupSearch: idpv1alpha1.LDAPIdentityProviderGroupSearch{
Base: env.SupervisorUpstreamLDAP.GroupSearchBase,
Filter: "",
Attributes: idpv1alpha1.LDAPIdentityProviderGroupSearchAttributes{
GroupName: "cn",
},
},
}, idpv1alpha1.LDAPPhaseReady)
expectedMsg := fmt.Sprintf(
`successfully able to connect to "%s" and bind as user "%s" [validated with Secret "%s" at version "%s"]`,
@@ -163,6 +180,7 @@ func TestSupervisorLogin(t *testing.T) {
),
// the ID token Username should have been pulled from the requested UserSearch.Attributes.Username attribute
wantDownstreamIDTokenUsernameToMatch: regexp.QuoteMeta(env.SupervisorUpstreamLDAP.TestUserDN),
wantDownstreamIDTokenGroups: env.SupervisorUpstreamLDAP.TestUserDirectGroupsCNs,
},
}
for _, test := range tests {
@@ -173,6 +191,7 @@ func TestSupervisorLogin(t *testing.T) {
test.requestAuthorization,
test.wantDownstreamIDTokenSubjectToMatch,
test.wantDownstreamIDTokenUsernameToMatch,
test.wantDownstreamIDTokenGroups,
)
})
}
@@ -207,7 +226,7 @@ func testSupervisorLogin(
t *testing.T,
createIDP func(t *testing.T),
requestAuthorization func(t *testing.T, downstreamAuthorizeURL, downstreamCallbackURL string, httpClient *http.Client),
wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch string,
wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch string, wantDownstreamIDTokenGroups []string,
) {
env := library.IntegrationEnv(t)
@@ -350,7 +369,7 @@ func testSupervisorLogin(
expectedIDTokenClaims := []string{"iss", "exp", "sub", "aud", "auth_time", "iat", "jti", "nonce", "rat", "username", "groups"}
verifyTokenResponse(t,
tokenResponse, discovery, downstreamOAuth2Config, nonceParam,
expectedIDTokenClaims, wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch)
expectedIDTokenClaims, wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch, wantDownstreamIDTokenGroups)
// token exchange on the original token
doTokenExchange(t, &downstreamOAuth2Config, tokenResponse, httpClient, discovery)
@@ -363,7 +382,7 @@ func testSupervisorLogin(
expectedIDTokenClaims = append(expectedIDTokenClaims, "at_hash")
verifyTokenResponse(t,
refreshedTokenResponse, discovery, downstreamOAuth2Config, "",
expectedIDTokenClaims, wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch)
expectedIDTokenClaims, wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch, wantDownstreamIDTokenGroups)
require.NotEqual(t, tokenResponse.AccessToken, refreshedTokenResponse.AccessToken)
require.NotEqual(t, tokenResponse.RefreshToken, refreshedTokenResponse.RefreshToken)
@@ -380,7 +399,7 @@ func verifyTokenResponse(
downstreamOAuth2Config oauth2.Config,
nonceParam nonce.Nonce,
expectedIDTokenClaims []string,
wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch string,
wantDownstreamIDTokenSubjectToMatch, wantDownstreamIDTokenUsernameToMatch string, wantDownstreamIDTokenGroups []string,
) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
@@ -415,6 +434,9 @@ func verifyTokenResponse(
// Check username claim of the ID token.
require.Regexp(t, wantDownstreamIDTokenUsernameToMatch, idTokenClaims["username"].(string))
// Check the groups claim.
require.ElementsMatch(t, wantDownstreamIDTokenGroups, idTokenClaims["groups"])
// Some light verification of the other tokens that were returned.
require.NotEmpty(t, tokenResponse.AccessToken)
require.Equal(t, "bearer", tokenResponse.TokenType)
+22 -12
View File
@@ -7,6 +7,7 @@ import (
"encoding/base64"
"io/ioutil"
"os"
"sort"
"strings"
"sync"
"testing"
@@ -71,18 +72,21 @@ type TestOIDCUpstream struct {
}
type TestLDAPUpstream struct {
Host string `json:"host"`
CABundle string `json:"caBundle"`
BindUsername string `json:"bindUsername"`
BindPassword string `json:"bindPassword"`
UserSearchBase string `json:"userSearchBase"`
TestUserDN string `json:"testUserDN"`
TestUserCN string `json:"testUserCN"`
TestUserPassword string `json:"testUserPassword"`
TestUserMailAttributeName string `json:"testUserMailAttributeName"`
TestUserMailAttributeValue string `json:"testUserMailAttributeValue"`
TestUserUniqueIDAttributeName string `json:"testUserUniqueIDAttributeName"`
TestUserUniqueIDAttributeValue string `json:"testUserUniqueIDAttributeValue"`
Host string `json:"host"`
CABundle string `json:"caBundle"`
BindUsername string `json:"bindUsername"`
BindPassword string `json:"bindPassword"`
UserSearchBase string `json:"userSearchBase"`
GroupSearchBase string `json:"groupSearchBase"`
TestUserDN string `json:"testUserDN"`
TestUserCN string `json:"testUserCN"`
TestUserPassword string `json:"testUserPassword"`
TestUserMailAttributeName string `json:"testUserMailAttributeName"`
TestUserMailAttributeValue string `json:"testUserMailAttributeValue"`
TestUserUniqueIDAttributeName string `json:"testUserUniqueIDAttributeName"`
TestUserUniqueIDAttributeValue string `json:"testUserUniqueIDAttributeValue"`
TestUserDirectGroupsCNs []string `json:"testUserDirectGroupsCNs"`
TestUserDirectGroupsDNs []string `json:"testUserDirectGroupsDNs"` //nolint:golint // this is "distinguished names", not "DNS"
}
// ProxyEnv returns a set of environment variable strings (e.g., to combine with os.Environ()) which set up the configured test HTTP proxy.
@@ -240,14 +244,20 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
BindUsername: needEnv(t, "PINNIPED_TEST_LDAP_BIND_ACCOUNT_USERNAME"),
BindPassword: needEnv(t, "PINNIPED_TEST_LDAP_BIND_ACCOUNT_PASSWORD"),
UserSearchBase: needEnv(t, "PINNIPED_TEST_LDAP_USERS_SEARCH_BASE"),
GroupSearchBase: needEnv(t, "PINNIPED_TEST_LDAP_GROUPS_SEARCH_BASE"),
TestUserDN: needEnv(t, "PINNIPED_TEST_LDAP_USER_DN"),
TestUserCN: needEnv(t, "PINNIPED_TEST_LDAP_USER_CN"),
TestUserUniqueIDAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_NAME"),
TestUserUniqueIDAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_UNIQUE_ID_ATTRIBUTE_VALUE"),
TestUserMailAttributeName: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_NAME"),
TestUserMailAttributeValue: needEnv(t, "PINNIPED_TEST_LDAP_USER_EMAIL_ATTRIBUTE_VALUE"),
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"), ";")),
TestUserPassword: needEnv(t, "PINNIPED_TEST_LDAP_USER_PASSWORD"),
}
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsCNs)
sort.Strings(result.SupervisorUpstreamLDAP.TestUserDirectGroupsDNs)
}
func (e *TestEnv) HasCapability(cap Capability) bool {