mirror of https://github.com/hashicorp/boundary
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.
418 lines
12 KiB
418 lines
12 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package ldap
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/boundary/globals"
|
|
"github.com/hashicorp/boundary/internal/auth/ldap/store"
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/iam"
|
|
"github.com/hashicorp/boundary/internal/oplog"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestNewAccount(t *testing.T) {
|
|
t.Parallel()
|
|
testCtx := context.Background()
|
|
testAuthMethodId := fmt.Sprintf("%s_1", globals.LdapAuthMethodPrefix)
|
|
tests := []struct {
|
|
name string
|
|
ctx context.Context
|
|
scopeId string
|
|
authMethodId string
|
|
loginName string
|
|
opt []Option
|
|
want *Account
|
|
wantErrMatch *errors.Template
|
|
wantErrContains string
|
|
}{
|
|
{
|
|
name: "success-with-all-opts",
|
|
ctx: testCtx,
|
|
scopeId: "global",
|
|
authMethodId: testAuthMethodId,
|
|
loginName: "test-login-name",
|
|
opt: []Option{
|
|
WithName(testCtx, "test-name"),
|
|
WithDescription(testCtx, "test-description"),
|
|
WithEmail(testCtx, "alice@bob.com"),
|
|
WithFullName(testCtx, "alice eve smith"),
|
|
WithDn(testCtx, "uid=alice, ou=people, o=test org"),
|
|
WithMemberOfGroups(testCtx, "test-group"),
|
|
},
|
|
want: &Account{
|
|
Account: &store.Account{
|
|
AuthMethodId: testAuthMethodId,
|
|
ScopeId: "global",
|
|
LoginName: "test-login-name",
|
|
Name: "test-name",
|
|
Description: "test-description",
|
|
Email: "alice@bob.com",
|
|
FullName: "alice eve smith",
|
|
Dn: "uid=alice, ou=people, o=test org",
|
|
MemberOfGroups: "[\"test-group\"]",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "missing-scope-id",
|
|
ctx: testCtx,
|
|
authMethodId: testAuthMethodId,
|
|
loginName: "test-login-name",
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing scope id",
|
|
},
|
|
{
|
|
name: "missing-auth-method-id",
|
|
ctx: testCtx,
|
|
scopeId: "global",
|
|
loginName: "test-login-name",
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing auth method id",
|
|
},
|
|
{
|
|
name: "missing-login-name",
|
|
ctx: testCtx,
|
|
scopeId: "global",
|
|
authMethodId: testAuthMethodId,
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing login name",
|
|
},
|
|
{
|
|
name: "validate-err",
|
|
ctx: testCtx,
|
|
scopeId: "global",
|
|
authMethodId: testAuthMethodId,
|
|
loginName: "test-login-name",
|
|
opt: []Option{WithEmail(testCtx, strings.Repeat("-", 400))},
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "email address is too long",
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
got, err := NewAccount(tc.ctx, tc.scopeId, tc.authMethodId, tc.loginName, tc.opt...)
|
|
if tc.wantErrMatch != nil {
|
|
require.Error(err)
|
|
assert.Nil(got)
|
|
assert.True(errors.Match(tc.wantErrMatch, err))
|
|
if tc.wantErrContains != "" {
|
|
assert.Contains(err.Error(), tc.wantErrContains)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Equal(tc.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAccount_clone(t *testing.T) {
|
|
t.Parallel()
|
|
testCtx := context.TODO()
|
|
testConn, _ := db.TestSetup(t, "postgres")
|
|
testWrapper := db.TestWrapper(t)
|
|
|
|
t.Run("valid", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
|
|
m := TestAuthMethod(t, testConn, testWrapper, org.PublicId, []string{"ldaps://ldap1"})
|
|
orig, err := NewAccount(testCtx, m.ScopeId, m.PublicId, "alice", WithFullName(testCtx, "Alice Eve Smith"), WithEmail(testCtx, "alice@alice.com"))
|
|
require.NoError(err)
|
|
cp := orig.clone()
|
|
assert.True(proto.Equal(cp.Account, orig.Account))
|
|
})
|
|
t.Run("not-equal", func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
org, _ := iam.TestScopes(t, iam.TestRepo(t, testConn, testWrapper))
|
|
m := TestAuthMethod(t, testConn, testWrapper, org.PublicId, []string{"ldaps://ldap1"})
|
|
orig, err := NewAccount(testCtx, m.ScopeId, m.PublicId, "alice", WithFullName(testCtx, "Alice Eve Smith"), WithEmail(testCtx, "alice@alice.com"))
|
|
require.NoError(err)
|
|
orig2, err := NewAccount(testCtx, m.ScopeId, m.PublicId, "bob", WithFullName(testCtx, "Bob Eve Smith"), WithEmail(testCtx, "bob@alice.com"))
|
|
require.NoError(err)
|
|
|
|
cp := orig.clone()
|
|
assert.True(!proto.Equal(cp.Account, orig2.Account))
|
|
})
|
|
}
|
|
|
|
func TestAccount_SetTableName(t *testing.T) {
|
|
t.Parallel()
|
|
defaultTableName := accountTableName
|
|
tests := []struct {
|
|
name string
|
|
setNameTo string
|
|
want string
|
|
}{
|
|
{
|
|
name: "new-name",
|
|
setNameTo: "new-name",
|
|
want: "new-name",
|
|
},
|
|
{
|
|
name: "reset to default",
|
|
setNameTo: "",
|
|
want: defaultTableName,
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
def := AllocAccount()
|
|
require.Equal(defaultTableName, def.TableName())
|
|
m := AllocAccount()
|
|
m.SetTableName(tc.setNameTo)
|
|
assert.Equal(tc.want, m.TableName())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAccount_oplog(t *testing.T) {
|
|
t.Parallel()
|
|
testCtx := context.Background()
|
|
testAcct, err := NewAccount(testCtx, "global", "test-id", "test-login-name")
|
|
testAcct.PublicId = "test-public-id"
|
|
require.NoError(t, err)
|
|
tests := []struct {
|
|
name string
|
|
ctx context.Context
|
|
acct *Account
|
|
opType oplog.OpType
|
|
want oplog.Metadata
|
|
wantErrMatch *errors.Template
|
|
wantErrContains string
|
|
}{
|
|
{
|
|
name: "create",
|
|
ctx: testCtx,
|
|
acct: testAcct,
|
|
opType: oplog.OpType_OP_TYPE_CREATE,
|
|
want: oplog.Metadata{
|
|
"auth-method-id": {"test-id"},
|
|
"resource-public-id": {"test-public-id"},
|
|
"scope-id": {"global"},
|
|
"op-type": {oplog.OpType_OP_TYPE_CREATE.String()},
|
|
"resource-type": {"ldap account"},
|
|
},
|
|
},
|
|
{
|
|
name: "update",
|
|
ctx: testCtx,
|
|
acct: testAcct,
|
|
opType: oplog.OpType_OP_TYPE_UPDATE,
|
|
want: oplog.Metadata{
|
|
"auth-method-id": {"test-id"},
|
|
"resource-public-id": {"test-public-id"},
|
|
"scope-id": {"global"},
|
|
"op-type": {oplog.OpType_OP_TYPE_UPDATE.String()},
|
|
"resource-type": {"ldap account"},
|
|
},
|
|
},
|
|
{
|
|
name: "missing-auth-method-id",
|
|
ctx: testCtx,
|
|
acct: func() *Account {
|
|
cp := testAcct.clone()
|
|
cp.AuthMethodId = ""
|
|
return cp
|
|
}(),
|
|
opType: oplog.OpType_OP_TYPE_UPDATE,
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing auth method id",
|
|
},
|
|
{
|
|
name: "missing-scope-id",
|
|
ctx: testCtx,
|
|
acct: func() *Account {
|
|
cp := testAcct.clone()
|
|
cp.ScopeId = ""
|
|
return cp
|
|
}(),
|
|
opType: oplog.OpType_OP_TYPE_UPDATE,
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing scope id",
|
|
},
|
|
{
|
|
name: "missing-public-id",
|
|
ctx: testCtx,
|
|
acct: func() *Account {
|
|
cp := testAcct.clone()
|
|
cp.PublicId = ""
|
|
return cp
|
|
}(),
|
|
opType: oplog.OpType_OP_TYPE_UPDATE,
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing public id",
|
|
},
|
|
{
|
|
name: "missing-op-type",
|
|
ctx: testCtx,
|
|
acct: testAcct,
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing op type",
|
|
},
|
|
{
|
|
name: "missing-account",
|
|
ctx: testCtx,
|
|
opType: oplog.OpType_OP_TYPE_UPDATE,
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing account",
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
got, err := tc.acct.oplog(tc.ctx, tc.opType)
|
|
if tc.wantErrMatch != nil {
|
|
require.Error(err)
|
|
assert.Nil(got)
|
|
assert.True(errors.Match(tc.wantErrMatch, err))
|
|
if tc.wantErrContains != "" {
|
|
assert.Contains(err.Error(), tc.wantErrContains)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Equal(tc.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAccount_GetAuthMethodId(t *testing.T) {
|
|
t.Parallel()
|
|
assert.Empty(t, AllocAccount().GetAuthMethodId())
|
|
}
|
|
|
|
func TestAccount_GetSubject(t *testing.T) {
|
|
t.Parallel()
|
|
assert.Empty(t, AllocAccount().GetSubject())
|
|
}
|
|
|
|
func TestAccount_validate(t *testing.T) {
|
|
t.Parallel()
|
|
testCtx := context.Background()
|
|
tests := []struct {
|
|
name string
|
|
ctx context.Context
|
|
caller errors.Op
|
|
acct *Account
|
|
wantErrMatch *errors.Template
|
|
wantErrContains string
|
|
}{
|
|
{
|
|
name: "missing-caller",
|
|
ctx: testCtx,
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing caller",
|
|
},
|
|
{
|
|
name: "missing-scope-id",
|
|
ctx: testCtx,
|
|
caller: "test",
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
a.ScopeId = ""
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing scope id",
|
|
},
|
|
{
|
|
name: "missing-auth-method-id",
|
|
ctx: testCtx,
|
|
caller: "test",
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
a.AuthMethodId = ""
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing auth method id",
|
|
},
|
|
{
|
|
name: "missing-login-name",
|
|
ctx: testCtx,
|
|
caller: "test",
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
a.LoginName = ""
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "missing login name",
|
|
},
|
|
{
|
|
name: "email-too-long",
|
|
ctx: testCtx,
|
|
caller: "test",
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
a.Email = strings.Repeat("-", 321)
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "email address is too long",
|
|
},
|
|
{
|
|
name: "full-name-too-long",
|
|
ctx: testCtx,
|
|
caller: "test",
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
a.FullName = strings.Repeat("-", 513)
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "full name is too long",
|
|
},
|
|
{
|
|
name: "login-name-not-lower-case",
|
|
ctx: testCtx,
|
|
caller: "test",
|
|
acct: func() *Account {
|
|
a, err := NewAccount(testCtx, "global", "test-auth-method-id", "test-login-name")
|
|
require.NoError(t, err)
|
|
a.LoginName = "Test-Login-Name"
|
|
return a
|
|
}(),
|
|
wantErrMatch: errors.T(errors.InvalidParameter),
|
|
wantErrContains: "login name must be lower case",
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
err := tc.acct.validate(tc.ctx, tc.caller)
|
|
if tc.wantErrMatch != nil {
|
|
require.Error(err)
|
|
assert.True(errors.Match(tc.wantErrMatch, err))
|
|
if tc.wantErrContains != "" {
|
|
assert.Contains(err.Error(), tc.wantErrContains)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
})
|
|
}
|
|
}
|