164 lines
5.2 KiB
Go
164 lines
5.2 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package ldap
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/boundary/internal/auth"
|
|
"github.com/hashicorp/boundary/internal/auth/ldap/store"
|
|
"github.com/hashicorp/boundary/internal/db/timestamp"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/oplog"
|
|
"github.com/hashicorp/boundary/internal/types/resource"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
// accountTableName defines the default table name for an Account
|
|
const accountTableName = "auth_ldap_account"
|
|
|
|
// Account contains an ldap auth account. It is assigned to an ldap AuthMethod
|
|
// and updates/deletes to that AuthMethod are cascaded to its Accounts.
|
|
type Account struct {
|
|
*store.Account
|
|
tableName string
|
|
}
|
|
|
|
// make sure ldap.Account implements the auth.Account interface
|
|
var _ auth.Account = (*Account)(nil)
|
|
|
|
// NewAccount creates a new in memory Account assigned to ldap AuthMethod.
|
|
// WithFullName, WithEmail, WithDn, WithName and WithDescription are the only
|
|
// valid options. All other options are ignored.
|
|
func NewAccount(ctx context.Context, scopeId, authMethodId, loginName string, opt ...Option) (*Account, error) {
|
|
const op = "ldap.NewAccount"
|
|
switch {
|
|
case scopeId == "":
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
|
|
case authMethodId == "":
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing auth method id")
|
|
case loginName == "":
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing login name")
|
|
}
|
|
opts, err := getOpts(opt...)
|
|
if err != nil {
|
|
return nil, errors.Wrap(ctx, err, op)
|
|
}
|
|
a := &Account{
|
|
Account: &store.Account{
|
|
ScopeId: scopeId,
|
|
AuthMethodId: authMethodId,
|
|
LoginName: loginName,
|
|
Dn: opts.withDn,
|
|
Name: opts.withName,
|
|
Description: opts.withDescription,
|
|
FullName: opts.withFullName,
|
|
Email: opts.withEmail,
|
|
MemberOfGroups: opts.withMemberOfGroups,
|
|
},
|
|
}
|
|
if err := a.validate(ctx, op); err != nil {
|
|
return nil, err // intentionally not wrapped.
|
|
}
|
|
return a, nil
|
|
}
|
|
|
|
// validate the Account. On success, it will return nil.
|
|
func (a *Account) validate(ctx context.Context, caller errors.Op) error {
|
|
const op = "ldap.(Account).validate"
|
|
switch {
|
|
case caller == "":
|
|
return errors.New(ctx, errors.InvalidParameter, op, "missing caller")
|
|
case a.ScopeId == "":
|
|
return errors.New(ctx, errors.InvalidParameter, caller, "missing scope id")
|
|
case a.AuthMethodId == "":
|
|
return errors.New(ctx, errors.InvalidParameter, caller, "missing auth method id")
|
|
case a.LoginName == "":
|
|
return errors.New(ctx, errors.InvalidParameter, caller, "missing login name")
|
|
case strings.ToLower(a.LoginName) != a.LoginName:
|
|
return errors.New(ctx, errors.InvalidParameter, op, "login name must be lower case")
|
|
case a.Email != "" && len(a.Email) > 320:
|
|
return errors.New(ctx, errors.InvalidParameter, caller, "email address is too long")
|
|
case a.FullName != "" && len(a.FullName) > 512:
|
|
return errors.New(ctx, errors.InvalidParameter, caller, "full name is too long")
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// AllocAccount makes an empty one in memory
|
|
func AllocAccount() *Account {
|
|
return &Account{
|
|
Account: &store.Account{},
|
|
}
|
|
}
|
|
|
|
// clone an Account.
|
|
func (a *Account) clone() *Account {
|
|
cp := proto.Clone(a.Account)
|
|
return &Account{
|
|
Account: cp.(*store.Account),
|
|
}
|
|
}
|
|
|
|
// TableName returns the table name.
|
|
func (a *Account) TableName() string {
|
|
if a.tableName != "" {
|
|
return a.tableName
|
|
}
|
|
return accountTableName
|
|
}
|
|
|
|
// SetTableName sets the table name.
|
|
func (a *Account) SetTableName(n string) {
|
|
a.tableName = n
|
|
}
|
|
|
|
// GetSubject returns the subject, which will always be empty as this type
|
|
// doesn't currently support subject.
|
|
func (a *Account) GetSubject() string {
|
|
return ""
|
|
}
|
|
|
|
// GetResourceType returns the resource type of the Account
|
|
func (a *Account) GetResourceType() resource.Type {
|
|
return resource.Account
|
|
}
|
|
|
|
// oplog will create oplog metadata for the Account.
|
|
func (a *Account) oplog(ctx context.Context, opType oplog.OpType) (oplog.Metadata, error) {
|
|
const op = "ldap.(Account).oplog"
|
|
switch {
|
|
case a == nil:
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing account")
|
|
case opType == oplog.OpType_OP_TYPE_UNSPECIFIED:
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing op type")
|
|
case a.PublicId == "":
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing public id")
|
|
case a.ScopeId == "":
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope id")
|
|
case a.AuthMethodId == "":
|
|
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing auth method id")
|
|
}
|
|
metadata := oplog.Metadata{
|
|
"resource-public-id": []string{a.PublicId},
|
|
"resource-type": []string{"ldap account"},
|
|
"op-type": []string{opType.String()},
|
|
"scope-id": []string{a.ScopeId},
|
|
"auth-method-id": []string{a.AuthMethodId},
|
|
}
|
|
return metadata, nil
|
|
}
|
|
|
|
type deletedAccount struct {
|
|
PublicId string `gorm:"primary_key"`
|
|
DeleteTime *timestamp.Timestamp
|
|
}
|
|
|
|
// TableName returns the tablename to override the default gorm table name
|
|
func (s *deletedAccount) TableName() string {
|
|
return "auth_ldap_account_deleted"
|
|
}
|