You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/auth/ldap/repository_auth_method_read...

274 lines
10 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package ldap
import (
"context"
"crypto/ed25519"
"crypto/rand"
"crypto/x509"
"testing"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRepository_LookupAuthMethod(t *testing.T) {
testConn, _ := db.TestSetup(t, "postgres")
testRw := db.New(testConn)
testWrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, testConn, testWrapper)
testCtx := context.Background()
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
orgDbWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
amInactive := TestAuthMethod(t, testConn, orgDbWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, WithOperationalState(testCtx, InactiveState))
amActivePriv := TestAuthMethod(t, testConn, orgDbWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, WithOperationalState(testCtx, ActivePrivateState))
amActivePub := TestAuthMethod(t, testConn, orgDbWrapper, org.PublicId, []string{"ldaps://ldap3.alice.com"}, WithOperationalState(testCtx, ActivePublicState))
amActivePub.IsPrimaryAuthMethod = true
iam.TestSetPrimaryAuthMethod(t, iam.TestRepo(t, testConn, testWrapper), org, amActivePub.PublicId)
amId, err := newAuthMethodId(testCtx)
require.NoError(t, err)
tests := []struct {
name string
in string
opt []Option
want *AuthMethod
wantIsPrimary bool
wantErrMatch *errors.Template
wantErrContains string
}{
{
name: "missing-public-id",
wantErrMatch: errors.T(errors.InvalidParameter),
wantErrContains: "missing public id",
},
{
name: "invalid-opts",
in: amActivePub.GetPublicId(),
opt: []Option{WithBindCredential(testCtx, "", "")},
wantErrMatch: errors.T(errors.InvalidParameter),
wantErrContains: "missing both dn and password",
},
{
name: "non-existing-auth-method-id",
in: amId,
},
{
name: "existing-auth-method-id",
in: amActivePriv.GetPublicId(),
want: amActivePriv,
},
{
name: "unauthenticated-user-not-found-using-active-priv",
in: amActivePriv.GetPublicId(),
opt: []Option{WithUnauthenticatedUser(testCtx, true)},
want: nil,
},
{
name: "unauthenticated-user-found-active-pub",
in: amActivePub.GetPublicId(),
opt: []Option{WithUnauthenticatedUser(testCtx, true)},
want: amActivePub,
wantIsPrimary: true,
},
{
name: "unauthenticated-user-found-inactive",
in: amInactive.GetPublicId(),
opt: []Option{WithUnauthenticatedUser(testCtx, true)},
want: nil,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
repo, err := NewRepository(testCtx, testRw, testRw, testKms)
assert.NoError(err)
require.NotNil(repo)
got, err := repo.LookupAuthMethod(testCtx, tc.in, tc.opt...)
if tc.wantErrMatch != nil {
require.Error(err)
assert.Truef(errors.Match(tc.wantErrMatch, err), "want err code: %q got: %q", tc.wantErrMatch, err)
assert.Nil(got)
if tc.wantErrContains != "" {
assert.Contains(err.Error(), tc.wantErrContains)
}
return
}
require.NoError(err)
assert.EqualValues(tc.want, got)
})
}
}
func TestRepository_getAuthMethods(t *testing.T) {
testConn, _ := db.TestSetup(t, "postgres")
testRw := db.New(testConn)
testWrapper := db.TestWrapper(t)
testKms := kms.TestKms(t, testConn, testWrapper)
testCtx := context.Background()
tests := []struct {
name string
setupFn func() (authMethodId string, scopeIds []string, want []*AuthMethod)
opt []Option
wantErrMatch *errors.Template
wantErrContains string
}{
{
name: "valid-multi-scopes",
setupFn: func() (string, []string, []*AuthMethod) {
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
orgDBWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
org2, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
orgDBWrapper2, err := testKms.GetWrapper(context.Background(), org2.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
// make a test auth method with all options
am1a := TestAuthMethod(t, testConn, orgDBWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, WithOperationalState(testCtx, InactiveState))
am1b := TestAuthMethod(t, testConn, orgDBWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, WithOperationalState(testCtx, InactiveState))
am2 := TestAuthMethod(t, testConn, orgDBWrapper2, org2.PublicId, []string{"ldaps://ldap3.alice.com"}, WithOperationalState(testCtx, InactiveState))
return "", []string{am1a.ScopeId, am1b.ScopeId, am2.ScopeId}, []*AuthMethod{am1a, am1b, am2}
},
},
{
name: "valid-single-scopes",
setupFn: func() (string, []string, []*AuthMethod) {
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
orgDBWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
am1a := TestAuthMethod(t, testConn, orgDBWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, WithOperationalState(testCtx, InactiveState))
am1b := TestAuthMethod(t, testConn, orgDBWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, WithOperationalState(testCtx, InactiveState))
return "", []string{am1a.ScopeId}, []*AuthMethod{am1a, am1b}
},
},
{
name: "valid-auth-method-id-all-opts",
setupFn: func() (string, []string, []*AuthMethod) {
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
orgDbWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
testCert, _ := TestGenerateCA(t, "localhost")
_, testPrivKey, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
derPrivKey, err := x509.MarshalPKCS8PrivateKey(testPrivKey)
require.NoError(t, err)
am := TestAuthMethod(t, testConn, orgDbWrapper, org.PublicId, []string{"ldaps://alice.com"},
WithName(testCtx, "test-name"),
WithDescription(testCtx, "test-description"),
WithStartTLS(testCtx),
WithInsecureTLS(testCtx),
WithDiscoverDn(testCtx),
WithAnonGroupSearch(testCtx),
WithUpnDomain(testCtx, "alice.com"),
WithUserDn(testCtx, "user-dn"),
WithUserAttr(testCtx, "user-attr"),
WithUserFilter(testCtx, "user-filter"),
WithEnableGroups(testCtx),
WithUseTokenGroups(testCtx),
WithGroupDn(testCtx, "group-dn"),
WithGroupAttr(testCtx, "group-attr"),
WithGroupFilter(testCtx, "group-filter"),
WithBindCredential(testCtx, "bind-dn", "bind-password"),
WithCertificates(testCtx, testCert),
WithClientCertificate(testCtx, derPrivKey, testCert), // not a client cert but good enough for this test.)
WithAccountAttributeMap(testCtx, map[string]AccountToAttribute{"mail": ToEmailAttribute, "displayName": ToFullNameAttribute}),
WithMaximumPageSize(testCtx, 10),
WithDerefAliases(testCtx, DerefAlways),
)
return am.PublicId, nil, []*AuthMethod{am}
},
},
{
name: "with-limits",
setupFn: func() (string, []string, []*AuthMethod) {
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
orgDBWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
am1a := TestAuthMethod(t, testConn, orgDBWrapper, org.PublicId, []string{"ldaps://alice.com"})
_ = TestAuthMethod(t, testConn, orgDBWrapper, org.PublicId, []string{"ldaps://alice2.com"})
return "", []string{am1a.ScopeId}, []*AuthMethod{am1a}
},
opt: []Option{WithLimit(testCtx, 1), WithOrderByCreateTime(testCtx, true)},
},
{
name: "unauthenticated-user",
setupFn: func() (string, []string, []*AuthMethod) {
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
require.NoError(t, err)
_ = TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, WithOperationalState(testCtx, InactiveState))
_ = TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, WithOperationalState(testCtx, ActivePrivateState))
amActivePub := TestAuthMethod(t, testConn, databaseWrapper, org.PublicId, []string{"ldaps://ldap3.alice.com"}, WithOperationalState(testCtx, ActivePublicState))
return "", []string{amActivePub.ScopeId}, []*AuthMethod{amActivePub}
},
opt: []Option{WithUnauthenticatedUser(testCtx, true)},
},
{
name: "not-found-auth-method-id",
setupFn: func() (string, []string, []*AuthMethod) {
return "not-a-valid-id", nil, nil
},
},
{
name: "not-found-scope-ids",
setupFn: func() (string, []string, []*AuthMethod) {
return "", []string{"not-valid-scope-1", "not-valid-scope-2"}, nil
},
},
{
name: "no-search-criteria",
setupFn: func() (string, []string, []*AuthMethod) {
return "", nil, nil
},
wantErrMatch: errors.T(errors.InvalidParameter),
wantErrContains: "missing search criteria: both auth method id and scope ids are empty",
},
{
name: "search-too-many",
setupFn: func() (string, []string, []*AuthMethod) {
return "auth-method-id", []string{"scope-id"}, nil
},
wantErrMatch: errors.T(errors.InvalidParameter),
wantErrContains: "searching for both an auth method id and scope ids is not supported",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
r, err := NewRepository(testCtx, testRw, testRw, testKms)
require.NoError(err)
authMethodId, scopeIds, want := tc.setupFn()
got, err := r.getAuthMethods(testCtx, authMethodId, scopeIds, tc.opt...)
if tc.wantErrMatch != nil {
require.Error(err)
assert.Truef(errors.Match(tc.wantErrMatch, err), "want err code: %q got: %q", tc.wantErrMatch, err)
assert.Nil(got)
if tc.wantErrContains != "" {
assert.Contains(err.Error(), tc.wantErrContains)
}
return
}
require.NoError(err)
TestSortAuthMethods(t, want)
TestSortAuthMethods(t, got)
assert.Equal(want, got)
})
}
}