Add initial templating support to Vault credential libraries This adds support for templating various account and user values into Vault dynamic credential library POST bodies and GET/POST paths. It also unifies how parameters are used in grants, with backwards compatibility.
This commit is contained in:
1 parent
b5ef8a516b
commit
cede1aec93
25 files changed
+612
-78
No files matched your search
@@ -10,13 +10,15 @@ import (
|
||||
|
||||
"github.com/hashicorp/boundary/api/recovery"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/tokens"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
"github.com/hashicorp/boundary/internal/perms"
|
||||
@@ -25,6 +27,9 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
"github.com/hashicorp/boundary/internal/types/subtypes"
|
||||
"github.com/hashicorp/boundary/internal/util"
|
||||
"github.com/hashicorp/boundary/internal/util/template"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
||||
"github.com/mr-tron/base58"
|
||||
@@ -56,6 +61,9 @@ type key int
|
||||
var verifierKey key
|
||||
|
||||
type VerifyResults struct {
|
||||
UserData template.Data
|
||||
// This is copied out from UserData above but used to avoid nil checks in
|
||||
// lots of places that embed this value
|
||||
UserId string
|
||||
AuthTokenId string
|
||||
Error error
|
||||
@@ -92,15 +100,47 @@ type VerifyResults struct {
|
||||
}
|
||||
|
||||
type verifier struct {
|
||||
iamRepoFn common.IamRepoFactory
|
||||
authTokenRepoFn common.AuthTokenRepoFactory
|
||||
serversRepoFn common.ServersRepoFactory
|
||||
kms *kms.Kms
|
||||
requestInfo *authpb.RequestInfo
|
||||
res *perms.Resource
|
||||
act action.Type
|
||||
ctx context.Context
|
||||
acl perms.ACL
|
||||
iamRepoFn common.IamRepoFactory
|
||||
authTokenRepoFn common.AuthTokenRepoFactory
|
||||
serversRepoFn common.ServersRepoFactory
|
||||
passwordAuthRepoFn common.PasswordAuthRepoFactory
|
||||
oidcAuthRepoFn common.OidcAuthRepoFactory
|
||||
kms *kms.Kms
|
||||
requestInfo *authpb.RequestInfo
|
||||
res *perms.Resource
|
||||
act action.Type
|
||||
ctx context.Context
|
||||
acl perms.ACL
|
||||
}
|
||||
|
||||
// TODO (jefferai 10/2022): NewVerifierContextWithAccounts performs the function
|
||||
// of NewVerifierContext (see the docs for that function) but with extra
|
||||
// parameters that can be used to look up account information. This is not
|
||||
// intended to be a long-lived function; see
|
||||
// https://hashicorp.atlassian.net/browse/ICU-6571 and
|
||||
// https://hashicorp.atlassian.net/browse/ICU-6572
|
||||
//
|
||||
// This is being added for a quick turnaround purpose and to avoid making large
|
||||
// numbers of changes to tests when we may do a much bigger refactor; when those
|
||||
// items are addressed this can be removed.
|
||||
func NewVerifierContextWithAccounts(ctx context.Context,
|
||||
iamRepoFn common.IamRepoFactory,
|
||||
authTokenRepoFn common.AuthTokenRepoFactory,
|
||||
serversRepoFn common.ServersRepoFactory,
|
||||
passwordAuthRepoFn common.PasswordAuthRepoFactory,
|
||||
oidcAuthRepoFn common.OidcAuthRepoFactory,
|
||||
kms *kms.Kms,
|
||||
requestInfo *authpb.RequestInfo,
|
||||
) context.Context {
|
||||
return context.WithValue(ctx, verifierKey, &verifier{
|
||||
iamRepoFn: iamRepoFn,
|
||||
authTokenRepoFn: authTokenRepoFn,
|
||||
serversRepoFn: serversRepoFn,
|
||||
passwordAuthRepoFn: passwordAuthRepoFn,
|
||||
oidcAuthRepoFn: oidcAuthRepoFn,
|
||||
kms: kms,
|
||||
requestInfo: requestInfo,
|
||||
})
|
||||
}
|
||||
|
||||
// NewVerifierContext creates a context that carries a verifier object from the
|
||||
@@ -114,13 +154,7 @@ func NewVerifierContext(ctx context.Context,
|
||||
kms *kms.Kms,
|
||||
requestInfo *authpb.RequestInfo,
|
||||
) context.Context {
|
||||
return context.WithValue(ctx, verifierKey, &verifier{
|
||||
iamRepoFn: iamRepoFn,
|
||||
authTokenRepoFn: authTokenRepoFn,
|
||||
serversRepoFn: serversRepoFn,
|
||||
kms: kms,
|
||||
requestInfo: requestInfo,
|
||||
})
|
||||
return NewVerifierContextWithAccounts(ctx, iamRepoFn, authTokenRepoFn, serversRepoFn, nil, nil, kms, requestInfo)
|
||||
}
|
||||
|
||||
// Verify takes in a context that has expected parameters as values and runs an
|
||||
@@ -209,6 +243,7 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
|
||||
}
|
||||
}
|
||||
ret.UserId = v.requestInfo.UserIdOverride
|
||||
ret.UserData.User.Id = util.Pointer(ret.UserId)
|
||||
if reqInfo != nil {
|
||||
reqInfo.UserId = ret.UserId
|
||||
}
|
||||
@@ -235,14 +270,17 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
|
||||
|
||||
var authResults perms.ACLResults
|
||||
var grantTuples []perms.GrantTuple
|
||||
var accountId, userName, userEmail string
|
||||
var userData template.Data
|
||||
var err error
|
||||
authResults, ret.UserId, accountId, userName, userEmail, ret.Scope, v.acl, grantTuples, err = v.performAuthCheck(ctx)
|
||||
authResults, ret.UserData, ret.Scope, v.acl, grantTuples, err = v.performAuthCheck(ctx)
|
||||
if err != nil {
|
||||
event.WriteError(ctx, op, err, event.WithInfoMsg("error performing authn/authz check"))
|
||||
return
|
||||
}
|
||||
|
||||
if ret.UserData.User.Id != nil {
|
||||
ret.UserId = *ret.UserData.User.Id
|
||||
}
|
||||
ret.AuthTokenId = v.requestInfo.PublicId
|
||||
ret.AuthenticationFinished = authResults.AuthenticationFinished
|
||||
if !authResults.Authorized {
|
||||
@@ -288,14 +326,20 @@ func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) {
|
||||
})
|
||||
}
|
||||
ea.UserInfo = &event.UserInfo{
|
||||
UserId: ret.UserId,
|
||||
AuthAccountId: accountId,
|
||||
UserId: ret.UserId,
|
||||
}
|
||||
if userData.Account.Id != nil {
|
||||
ea.UserInfo.AuthAccountId = *userData.Account.Id
|
||||
}
|
||||
ea.GrantsInfo = &event.GrantsInfo{
|
||||
Grants: grants,
|
||||
}
|
||||
ea.UserName = userName
|
||||
ea.UserEmail = userEmail
|
||||
if userData.User.FullName != nil {
|
||||
ea.UserName = *userData.User.FullName
|
||||
}
|
||||
if userData.User.Email != nil {
|
||||
ea.UserEmail = *userData.User.Email
|
||||
}
|
||||
|
||||
if reqInfo != nil {
|
||||
reqInfo.UserId = ret.UserId
|
||||
@@ -434,10 +478,7 @@ func (v *verifier) decryptToken(ctx context.Context) {
|
||||
|
||||
func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
aclResults perms.ACLResults,
|
||||
userId string,
|
||||
accountId string,
|
||||
userName string,
|
||||
userEmail string,
|
||||
userData template.Data,
|
||||
scopeInfo *scopes.ScopeInfo,
|
||||
retAcl perms.ACL,
|
||||
grantTuples []perms.GrantTuple,
|
||||
@@ -449,7 +490,10 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
// Make the linter happy
|
||||
_ = retErr
|
||||
scopeInfo = new(scopes.ScopeInfo)
|
||||
userId = AnonymousUserId
|
||||
|
||||
// This will always be set, so further down below we can switch on whether
|
||||
// it's empty
|
||||
userData.User.Id = util.Pointer(AnonymousUserId)
|
||||
|
||||
// Validate the token and fetch the corresponding user ID
|
||||
switch v.requestInfo.TokenFormat {
|
||||
@@ -459,7 +503,7 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
case uint32(AuthTokenTypeRecoveryKms):
|
||||
// We validated the encrypted token in decryptToken and handled the
|
||||
// nonces there, so just set the user
|
||||
userId = "u_recovery"
|
||||
userData.User.Id = util.Pointer("u_recovery")
|
||||
|
||||
case uint32(AuthTokenTypeBearer), uint32(AuthTokenTypeSplitCookie):
|
||||
if v.requestInfo.Token == "" {
|
||||
@@ -479,12 +523,12 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
break
|
||||
}
|
||||
if at != nil {
|
||||
accountId = at.GetAuthAccountId()
|
||||
userId = at.GetIamUserId()
|
||||
if userId == "" {
|
||||
userData.Account.Id = util.Pointer(at.GetAuthAccountId())
|
||||
userData.User.Id = util.Pointer(at.GetIamUserId())
|
||||
if *userData.User.Id == "" {
|
||||
event.WriteError(ctx, op, stderrors.New("perform auth check: valid token did not map to a user, likely because no account is associated with the user any longer; continuing as u_anon"), event.WithInfo("token_id", at.GetPublicId()))
|
||||
userId = AnonymousUserId
|
||||
accountId = ""
|
||||
userData.User.Id = util.Pointer(AnonymousUserId)
|
||||
userData.Account.Id = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,13 +539,51 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
return
|
||||
}
|
||||
|
||||
u, _, err := iamRepo.LookupUser(ctx, userId)
|
||||
u, _, err := iamRepo.LookupUser(ctx, *userData.User.Id)
|
||||
if err != nil {
|
||||
retErr = errors.Wrap(ctx, err, op, errors.WithMsg("failed to lookup user"))
|
||||
return
|
||||
}
|
||||
userEmail = u.Email
|
||||
userName = u.FullName
|
||||
userData.User.Name = util.Pointer(u.Name)
|
||||
userData.User.Email = util.Pointer(u.Email)
|
||||
userData.User.FullName = util.Pointer(u.FullName)
|
||||
|
||||
if userData.Account.Id != nil && *userData.Account.Id != "" && v.passwordAuthRepoFn != nil && v.oidcAuthRepoFn != nil {
|
||||
const domain = "auth"
|
||||
var acct auth.Account
|
||||
var err error
|
||||
switch subtypes.SubtypeFromId(domain, *userData.Account.Id) {
|
||||
case password.Subtype:
|
||||
repo, repoErr := v.passwordAuthRepoFn()
|
||||
if repoErr != nil {
|
||||
retErr = errors.Wrap(ctx, repoErr, op, errors.WithMsg("failed to get password auth repo"))
|
||||
return
|
||||
}
|
||||
acct, err = repo.LookupAccount(ctx, *userData.Account.Id)
|
||||
case oidc.Subtype:
|
||||
repo, repoErr := v.oidcAuthRepoFn()
|
||||
if repoErr != nil {
|
||||
retErr = errors.Wrap(ctx, repoErr, op, errors.WithMsg("failed to get oidc auth repo"))
|
||||
return
|
||||
}
|
||||
acct, err = repo.LookupAccount(ctx, *userData.Account.Id)
|
||||
default:
|
||||
retErr = errors.Wrap(ctx, err, op, errors.WithMsg("unrecognized account id type"))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
if errors.IsNotFoundError(err) {
|
||||
retErr = errors.Wrap(ctx, err, op, errors.WithMsg("account doesn't exist"))
|
||||
return
|
||||
}
|
||||
retErr = errors.Wrap(ctx, err, op, errors.WithMsg("error looking up account"))
|
||||
return
|
||||
}
|
||||
userData.Account.Name = util.Pointer(acct.GetName())
|
||||
userData.Account.Email = util.Pointer(acct.GetEmail())
|
||||
userData.Account.LoginName = util.Pointer(acct.GetLoginName())
|
||||
userData.Account.Subject = util.Pointer(acct.GetSubject())
|
||||
}
|
||||
|
||||
// Look up scope details to return. We can skip a lookup when using the
|
||||
// global scope
|
||||
@@ -546,7 +628,7 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
|
||||
// Fetch and parse grants for this user ID (which may include grants for
|
||||
// u_anon and u_auth)
|
||||
grantTuples, err = iamRepo.GrantsForUser(v.ctx, userId)
|
||||
grantTuples, err = iamRepo.GrantsForUser(v.ctx, *userData.User.Id)
|
||||
if err != nil {
|
||||
retErr = errors.Wrap(ctx, err, op)
|
||||
return
|
||||
@@ -556,12 +638,17 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
// that we've since restricted, e.g. "id=foo;actions=create,read". These
|
||||
// will simply not have an effect.
|
||||
for _, pair := range grantTuples {
|
||||
permsOpts := []perms.Option{
|
||||
perms.WithUserId(*userData.User.Id),
|
||||
perms.WithSkipFinalValidation(true),
|
||||
}
|
||||
if userData.Account.Id != nil {
|
||||
permsOpts = append(permsOpts, perms.WithAccountId(*userData.Account.Id))
|
||||
}
|
||||
parsed, err := perms.Parse(
|
||||
pair.ScopeId,
|
||||
pair.Grant,
|
||||
perms.WithUserId(userId),
|
||||
perms.WithAccountId(accountId),
|
||||
perms.WithSkipFinalValidation(true))
|
||||
permsOpts...)
|
||||
if err != nil {
|
||||
retErr = errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed to parse grant %#v", pair.Grant)))
|
||||
return
|
||||
@@ -570,7 +657,7 @@ func (v verifier) performAuthCheck(ctx context.Context) (
|
||||
}
|
||||
|
||||
retAcl = perms.NewACL(parsedGrants...)
|
||||
aclResults = retAcl.Allowed(*v.res, v.act, userId)
|
||||
aclResults = retAcl.Allowed(*v.res, v.act, *userData.User.Id)
|
||||
// We don't set authenticated above because setting this but not authorized
|
||||
// is used for further permissions checks, such as during recursive listing.
|
||||
// So we want to make sure any code relying on that has the full set of
|
||||
@@ -601,6 +688,13 @@ func (r *VerifyResults) fetchActions(id string, typ resource.Type, availableActi
|
||||
return availableActions
|
||||
}
|
||||
|
||||
// If there is no user ID set by definition there are no actions to fetch.
|
||||
// This shouldn't happen because we should always fall back to at least the
|
||||
// anonymous user so it's defense in depth.
|
||||
if r.UserData.User.Id == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
opts := getOpts(opt...)
|
||||
res := opts.withResource
|
||||
// If not passed in, use what's already been populated through verification
|
||||
@@ -620,7 +714,7 @@ func (r *VerifyResults) fetchActions(id string, typ resource.Type, availableActi
|
||||
|
||||
ret := make(action.ActionSet, 0, len(availableActions))
|
||||
for _, act := range availableActions {
|
||||
if r.v.acl.Allowed(*res, act, r.UserId).Authorized {
|
||||
if r.v.acl.Allowed(*res, act, *r.UserData.User.Id).Authorized {
|
||||
ret = append(ret, act)
|
||||
}
|
||||
}
|
||||
@@ -636,9 +730,14 @@ func (r *VerifyResults) FetchOutputFields(res perms.Resource, act action.Type) p
|
||||
return perms.OutputFieldsMap{"*": true}
|
||||
case r.v.requestInfo.DisableAuthEntirely:
|
||||
return nil
|
||||
case r.UserData.User.Id == nil:
|
||||
// If there is no user ID set by definition there are no actions to fetch.
|
||||
// This shouldn't happen because we should always fall back to at least the
|
||||
// anonymous user so it's defense in depth.
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.v.acl.Allowed(res, act, r.UserId).OutputFields
|
||||
return r.v.acl.Allowed(res, act, *r.UserData.User.Id).OutputFields
|
||||
}
|
||||
|
||||
// ACL returns the perms.ACL of the verifier.
|
||||
|
||||
@@ -57,6 +57,8 @@ func newGrpcServer(
|
||||
iamRepoFn common.IamRepoFactory,
|
||||
authTokenRepoFn common.AuthTokenRepoFactory,
|
||||
serversRepoFn common.ServersRepoFactory,
|
||||
passwordAuthRepoFn common.PasswordAuthRepoFactory,
|
||||
oidcAuthRepoFn common.OidcAuthRepoFactory,
|
||||
kms *kms.Kms,
|
||||
eventer *event.Eventer,
|
||||
) (*grpc.Server, string, error) {
|
||||
@@ -65,7 +67,7 @@ func newGrpcServer(
|
||||
if err != nil {
|
||||
return nil, "", errors.Wrap(ctx, err, op, errors.WithMsg("unable to generate gateway ticket"))
|
||||
}
|
||||
requestCtxInterceptor, err := requestCtxInterceptor(ctx, iamRepoFn, authTokenRepoFn, serversRepoFn, kms, ticket, eventer)
|
||||
requestCtxInterceptor, err := requestCtxInterceptor(ctx, iamRepoFn, authTokenRepoFn, serversRepoFn, passwordAuthRepoFn, oidcAuthRepoFn, kms, ticket, eventer)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
@@ -853,7 +853,7 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
dynamic, err = credRepo.Issue(ctx, sess.GetPublicId(), vaultReqs)
|
||||
dynamic, err = credRepo.Issue(ctx, sess.GetPublicId(), vaultReqs, credential.WithTemplateData(authResults.UserData))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package tcp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
@@ -11,6 +13,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
"github.com/hashicorp/boundary/internal/authtoken"
|
||||
"github.com/hashicorp/boundary/internal/credential"
|
||||
credstatic "github.com/hashicorp/boundary/internal/credential/static"
|
||||
@@ -2260,6 +2264,12 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(rw, rw, kms)
|
||||
}
|
||||
passwordAuthRepoFn := func() (*password.Repository, error) {
|
||||
return password.NewRepository(rw, rw, kms)
|
||||
}
|
||||
oidcAuthRepoFn := func() (*oidc.Repository, error) {
|
||||
return oidc.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
plg := host.TestPlugin(t, conn, "test")
|
||||
plgm := map[string]plgpb.HostPluginServiceClient{
|
||||
@@ -2290,12 +2300,23 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
return plugin.NewRepository(rw, rw, kms, sche, plgm)
|
||||
}
|
||||
|
||||
loginName := "foo@bar.com"
|
||||
accountName := "passname"
|
||||
userName := "username"
|
||||
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
||||
ctx = auth.NewVerifierContext(requests.NewRequestContext(ctx),
|
||||
at := authtoken.TestAuthToken(t,
|
||||
conn,
|
||||
kms,
|
||||
org.GetPublicId(),
|
||||
authtoken.WithPasswordOptions(password.WithLoginName(loginName), password.WithName(accountName)),
|
||||
authtoken.WithIamOptions(iam.WithName(userName)))
|
||||
ctx = auth.NewVerifierContextWithAccounts(requests.NewRequestContext(ctx),
|
||||
iamRepoFn,
|
||||
atRepoFn,
|
||||
serversRepoFn,
|
||||
passwordAuthRepoFn,
|
||||
oidcAuthRepoFn,
|
||||
kms,
|
||||
&authpb.RequestInfo{
|
||||
Token: at.GetToken(),
|
||||
@@ -2327,7 +2348,7 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
plugin.TestRunSetSync(t, conn, kms, plgm)
|
||||
|
||||
v := vault.NewTestVaultServer(t)
|
||||
v.MountPKI(t)
|
||||
v.MountPKI(t, vault.WithTestMountPath("pki/"+userName))
|
||||
sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "boundary-controller", "pki"}))
|
||||
|
||||
vaultStore := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
|
||||
@@ -2340,13 +2361,13 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
|
||||
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
|
||||
Path: &wrapperspb.StringValue{
|
||||
Value: path.Join("pki", "issue", "boundary"),
|
||||
Value: path.Join("pki/{{ .User.Name}}", "issue", "boundary"),
|
||||
},
|
||||
HttpMethod: &wrapperspb.StringValue{
|
||||
Value: "POST",
|
||||
},
|
||||
HttpRequestBody: &wrapperspb.StringValue{
|
||||
Value: `{"common_name":"boundary.com"}`,
|
||||
Value: `{"common_name":"boundary.com", "alt_names": "{{.User.Name}},{{.Account.Name}},{{.Account.LoginName}},{{ truncateFrom .Account.LoginName "@" }}"}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2474,6 +2495,16 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
assert.Truef(t, strings.HasPrefix(gotV.(string), v.(string)), "%q:%q doesn't have prefix %q", k, gotV, v)
|
||||
}
|
||||
|
||||
b, _ := pem.Decode([]byte(dSec["certificate"].(string)))
|
||||
require.NotNil(t, b)
|
||||
cert, err := x509.ParseCertificate(b.Bytes)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, cert.DNSNames, userName)
|
||||
assert.Contains(t, cert.DNSNames, accountName)
|
||||
assert.Contains(t, cert.DNSNames, strings.Split(loginName, "@")[0])
|
||||
assert.Contains(t, cert.EmailAddresses, loginName)
|
||||
|
||||
gotCred.Secret = nil
|
||||
|
||||
got.AuthorizationToken, got.SessionId, got.CreatedTime = "", "", nil
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s Service) ListUsers(ctx context.Context, req *pbs.ListUsersRequest) (*pbs
|
||||
continue
|
||||
}
|
||||
|
||||
outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId)
|
||||
outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(*authResults.UserData.User.Id)
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(&outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
|
||||
@@ -48,6 +48,8 @@ func requestCtxInterceptor(
|
||||
iamRepoFn common.IamRepoFactory,
|
||||
authTokenRepoFn common.AuthTokenRepoFactory,
|
||||
serversRepoFn common.ServersRepoFactory,
|
||||
passwordAuthRepoFn common.PasswordAuthRepoFactory,
|
||||
oidcAuthRepoFn common.OidcAuthRepoFactory,
|
||||
kms *kms.Kms,
|
||||
ticket string,
|
||||
eventer *event.Eventer,
|
||||
@@ -105,7 +107,7 @@ func requestCtxInterceptor(
|
||||
return nil, errors.New(interceptorCtx, errors.Internal, op, "Invalid context (bad ticket)")
|
||||
}
|
||||
|
||||
interceptorCtx = auth.NewVerifierContext(interceptorCtx, iamRepoFn, authTokenRepoFn, serversRepoFn, kms, &requestInfo)
|
||||
interceptorCtx = auth.NewVerifierContextWithAccounts(interceptorCtx, iamRepoFn, authTokenRepoFn, serversRepoFn, passwordAuthRepoFn, oidcAuthRepoFn, kms, &requestInfo)
|
||||
|
||||
// Add general request information to the context. The information from
|
||||
// the auth verifier context is pretty specifically curated to
|
||||
|
||||
@@ -311,7 +311,7 @@ func Test_requestCtxInterceptor(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
interceptor, err := requestCtxInterceptor(factoryCtx, tt.iamRepoFn, tt.authTokenRepoFn, tt.serversRepoFn, tt.kms, tt.ticket, tt.eventer)
|
||||
interceptor, err := requestCtxInterceptor(factoryCtx, tt.iamRepoFn, tt.authTokenRepoFn, tt.serversRepoFn, nil, nil, tt.kms, tt.ticket, tt.eventer)
|
||||
if tt.wantFactoryErr {
|
||||
require.Error(err)
|
||||
assert.Nil(interceptor)
|
||||
|
||||
@@ -35,7 +35,7 @@ func closeListener(_ context.Context, l net.Listener, _ any, _ int) error {
|
||||
func (c *Controller) startListeners() error {
|
||||
servers := make([]func(), 0, len(c.conf.Listeners))
|
||||
|
||||
grpcServer, gwTicket, err := newGrpcServer(c.baseContext, c.IamRepoFn, c.AuthTokenRepoFn, c.ServersRepoFn, c.kms, c.conf.Eventer)
|
||||
grpcServer, gwTicket, err := newGrpcServer(c.baseContext, c.IamRepoFn, c.AuthTokenRepoFn, c.ServersRepoFn, c.PasswordAuthRepoFn, c.OidcRepoFn, c.kms, c.conf.Eventer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new grpc server: %w", err)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user