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/service_authenticate.go

104 lines
3.6 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package ldap
import (
"context"
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/event"
"github.com/hashicorp/boundary/internal/iam"
)
type (
// AuthenticatorFactory is used by "service functions" to create a new
// ldap.Authenticator (typically an ldap.Repository)
AuthenticatorFactory func() (Authenticator, error)
// LookupUserFactory is used by "service functions" to create a new
// LookupUser (typically an iam repo)
LookupUserFactory func() (LookupUser, error)
// AuthTokenCreatorFactory is used by "service functions" to create a new
// AuthTokenCreator (typically an auth token repo)
AuthTokenCreatorFactory func() (AuthTokenCreator, error)
)
// Authenticate is an ldap domain service function for handling an LDAP
// authentication flow. On success, it returns an auth token.
//
// The service operation includes:
// - Authenticate the user against the auth method's configured ldap server.
// - Use iam.(Repository).LookupUserWithLogin(...) look up the iam.User matching the Account.
// - Use the authtoken.(Repository).CreateAuthToken(...) to create a pending auth token for the authenticated user.
func Authenticate(
ctx context.Context,
authenticatorFn AuthenticatorFactory,
lookupUserFn LookupUserFactory,
tokenCreatorFn AuthTokenCreatorFactory,
authMethodId, loginName, password string,
) (*authtoken.AuthToken, error) {
const op = "ldap.Authenticate"
switch {
case authenticatorFn == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing authenticator factory")
case lookupUserFn == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing lookup user factory")
case tokenCreatorFn == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing auth token creator factory")
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")
case password == "":
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing password")
}
r, err := authenticatorFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
acct, err := r.Authenticate(ctx, authMethodId, loginName, password)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
l, err := lookupUserFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
user, err := l.LookupUserWithLogin(ctx, acct.PublicId)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
at, err := tokenCreatorFn()
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
token, err := at.CreateAuthToken(ctx, user, acct.PublicId)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
if err := event.WriteObservation(ctx, op, event.WithDetails("user_id", user.GetPublicId(), "auth_token_start",
token.GetCreateTime(), "auth_token_end", token.GetExpirationTime())); err != nil {
return nil, errors.Wrap(ctx, err, op, errors.WithMsg("Unable to write observation event for authenticate method"))
}
return token, nil
}
type Authenticator interface {
Authenticate(ctx context.Context, authMethodId, loginName, password string) (*Account, error)
}
type LookupUser interface {
LookupUserWithLogin(ctx context.Context, accountId string, opt ...iam.Option) (*iam.User, error)
}
type AuthTokenCreator interface {
CreateAuthToken(ctx context.Context, withIamUser *iam.User, withAuthAccountId string, opt ...authtoken.Option) (*authtoken.AuthToken, error)
}