Some updates based on PR review

This commit is contained in:
Ryan Richard
2021-04-27 12:43:09 -07:00
parent b3b108500a
commit 263a33cc85
33 changed files with 441 additions and 613 deletions
@@ -61,6 +61,17 @@ type ldapWatcherController struct {
// NewLDAPUpstreamWatcherController instantiates a new controllerlib.Controller which will populate the provided UpstreamLDAPIdentityProviderICache.
func NewLDAPUpstreamWatcherController(
idpCache UpstreamLDAPIdentityProviderICache,
client pinnipedclientset.Interface,
ldapIdentityProviderInformer idpinformers.LDAPIdentityProviderInformer,
secretInformer corev1informers.SecretInformer,
withInformer pinnipedcontroller.WithInformerOptionFunc,
) controllerlib.Controller {
// nil means to use a real production dialer when creating objects to add to the dynamicUpstreamIDPProvider cache.
return newInternal(idpCache, nil, client, ldapIdentityProviderInformer, secretInformer, withInformer)
}
func newInternal(
idpCache UpstreamLDAPIdentityProviderICache,
ldapDialer upstreamldap.LDAPDialer,
client pinnipedclientset.Interface,
@@ -124,7 +135,7 @@ func (c *ldapWatcherController) validateUpstream(ctx context.Context, upstream *
Base: spec.UserSearch.Base,
Filter: spec.UserSearch.Filter,
UsernameAttribute: spec.UserSearch.Attributes.Username,
UIDAttribute: spec.UserSearch.Attributes.UniqueID,
UIDAttribute: spec.UserSearch.Attributes.UID,
},
Dialer: c.ldapDialer,
}
@@ -80,7 +80,7 @@ func TestLDAPUpstreamWatcherControllerFilterSecrets(t *testing.T) {
secretInformer := kubeInformers.Core().V1().Secrets()
withInformer := testutil.NewObservableWithInformerOption()
NewLDAPUpstreamWatcherController(nil, nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer)
NewLDAPUpstreamWatcherController(nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer)
unrelated := corev1.Secret{}
filter := withInformer.GetFilterForInformer(secretInformer)
@@ -125,7 +125,7 @@ func TestLDAPUpstreamWatcherControllerFilterLDAPIdentityProviders(t *testing.T)
secretInformer := kubeInformers.Core().V1().Secrets()
withInformer := testutil.NewObservableWithInformerOption()
NewLDAPUpstreamWatcherController(nil, nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer)
NewLDAPUpstreamWatcherController(nil, nil, ldapIDPInformer, secretInformer, withInformer.WithInformer)
unrelated := corev1.Secret{}
filter := withInformer.GetFilterForInformer(ldapIDPInformer)
@@ -174,14 +174,14 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: testName, Namespace: testNamespace, Generation: 1234},
Spec: v1alpha1.LDAPIdentityProviderSpec{
Host: testHost,
TLS: &v1alpha1.LDAPIdentityProviderTLSSpec{CertificateAuthorityData: testCABundleBase64Encoded},
Bind: v1alpha1.LDAPIdentityProviderBindSpec{SecretName: testSecretName},
UserSearch: v1alpha1.LDAPIdentityProviderUserSearchSpec{
TLS: &v1alpha1.TLSSpec{CertificateAuthorityData: testCABundleBase64Encoded},
Bind: v1alpha1.LDAPIdentityProviderBind{SecretName: testSecretName},
UserSearch: v1alpha1.LDAPIdentityProviderUserSearch{
Base: testUserSearchBase,
Filter: testUserSearchFilter,
Attributes: v1alpha1.LDAPIdentityProviderUserSearchAttributesSpec{
Attributes: v1alpha1.LDAPIdentityProviderUserSearchAttributes{
Username: testUsernameAttrName,
UniqueID: testUIDAttrName,
UID: testUIDAttrName,
},
},
},
@@ -815,7 +815,7 @@ func TestLDAPUpstreamWatcherControllerSync(t *testing.T) {
return conn, nil
})}
controller := NewLDAPUpstreamWatcherController(
controller := newInternal(
cache,
dialer,
fakePinnipedClient,
+2 -2
View File
@@ -27,8 +27,8 @@ import (
)
const (
CustomUsernameHeaderName = "X-Pinniped-Upstream-Username"
CustomPasswordHeaderName = "X-Pinniped-Upstream-Password" //nolint:gosec // this is not a credential
CustomUsernameHeaderName = "X-Pinniped-Idp-Username"
CustomPasswordHeaderName = "X-Pinniped-Idp-Password" //nolint:gosec // this is not a credential
)
func NewHandler(
+2 -2
View File
@@ -1119,10 +1119,10 @@ func TestAuthorizationEndpoint(t *testing.T) {
req.Header.Set("Cookie", test.csrfCookie)
}
if test.customUsernameHeader != nil {
req.Header.Set("X-Pinniped-Upstream-Username", *test.customUsernameHeader)
req.Header.Set("X-Pinniped-Idp-Username", *test.customUsernameHeader)
}
if test.customPasswordHeader != nil {
req.Header.Set("X-Pinniped-Upstream-Password", *test.customPasswordHeader)
req.Header.Set("X-Pinniped-Idp-Password", *test.customPasswordHeader)
}
rsp := httptest.NewRecorder()
subject.ServeHTTP(rsp, req)
@@ -39,7 +39,7 @@ import (
// Test helpers for the OIDC package.
// ExchangeAuthcodeAndValidateTokenArgs is a POGO (plain old go object?) used to spy on calls to
// ExchangeAuthcodeAndValidateTokenArgs is used to spy on calls to
// TestUpstreamOIDCIdentityProvider.ExchangeAuthcodeAndValidateTokensFunc().
type ExchangeAuthcodeAndValidateTokenArgs struct {
Ctx context.Context
+6 -3
View File
@@ -8,6 +8,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net"
"strings"
@@ -23,7 +24,6 @@ const (
ldapsScheme = "ldaps"
distinguishedNameAttributeName = "dn"
userSearchFilterInterpolationLocationMarker = "{}"
invalidCredentialsErrorPrefix = `LDAP Result Code 49 "Invalid Credentials":`
)
// Conn abstracts the upstream LDAP communication protocol (mostly for testing).
@@ -46,6 +46,8 @@ type LDAPDialer interface {
// LDAPDialerFunc makes it easy to use a func as an LDAPDialer.
type LDAPDialerFunc func(ctx context.Context, hostAndPort string) (Conn, error)
var _ LDAPDialer = LDAPDialerFunc(func(ctx context.Context, hostAndPort string) (Conn, error) { return nil, nil })
func (f LDAPDialerFunc) Dial(ctx context.Context, hostAndPort string) (Conn, error) {
return f(ctx, hostAndPort)
}
@@ -307,7 +309,8 @@ func (p *Provider) searchAndBindUser(conn Conn, username string, bindFunc func(c
if err != nil {
plog.DebugErr("error binding for user (if this is not the expected dn for this username, please check the user search configuration)",
err, "upstreamName", p.GetName(), "username", username, "dn", userEntry.DN)
if strings.HasPrefix(err.Error(), invalidCredentialsErrorPrefix) {
ldapErr := &ldap.Error{}
if errors.As(err, &ldapErr) && ldapErr.ResultCode == ldap.LDAPResultInvalidCredentials {
return "", "", nil
}
return "", "", fmt.Errorf(`error binding for user "%s" using provided password against DN "%s": %w`, username, userEntry.DN, err)
@@ -321,7 +324,7 @@ func (p *Provider) userSearchRequest(username string) *ldap.SearchRequest {
return &ldap.SearchRequest{
BaseDN: p.c.UserSearch.Base,
Scope: ldap.ScopeWholeSubtree,
DerefAliases: ldap.DerefAlways, // TODO what's the best value here?
DerefAliases: ldap.NeverDerefAliases,
SizeLimit: 2,
TimeLimit: 90,
TypesOnly: false,
+6 -2
View File
@@ -67,7 +67,7 @@ func TestEndUserAuthentication(t *testing.T) {
request := &ldap.SearchRequest{
BaseDN: testUserSearchBase,
Scope: ldap.ScopeWholeSubtree,
DerefAliases: ldap.DerefAlways,
DerefAliases: ldap.NeverDerefAliases,
SizeLimit: 2,
TimeLimit: 90,
TypesOnly: false,
@@ -571,7 +571,11 @@ func TestEndUserAuthentication(t *testing.T) {
wantUnauthenticated: true,
skipDryRunAuthenticateUser: true,
bindEndUserMocks: func(conn *mockldapconn.MockConn) {
conn.EXPECT().Bind(testSearchResultDNValue, testUpstreamPassword).Return(errors.New(`LDAP Result Code 49 "Invalid Credentials": some bind error`)).Times(1)
err := &ldap.Error{
Err: errors.New("some bind error"),
ResultCode: ldap.LDAPResultInvalidCredentials,
}
conn.EXPECT().Bind(testSearchResultDNValue, testUpstreamPassword).Return(err).Times(1)
},
},
{