Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/mfa/mfa.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ func MFAResponseFromContext(ctx context.Context) (*proto.MFAAuthenticateResponse
if !ok {
return nil, trace.BadParameter("unexpected context value type %T", val)
}
if mfaResp == nil {
return nil, trace.NotFound("mfa response not found in the context")
}
return mfaResp, nil
}
return nil, trace.NotFound("mfa response not found in the context")
Expand Down
16 changes: 16 additions & 0 deletions lib/auth/users/usersv1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ func (s *Service) CreateUser(ctx context.Context, req *userspb.CreateUserRequest
return nil, trace.Wrap(err)
}

if err := authz.AuthorizeAdminAction(ctx, authzCtx); err != nil {
return nil, trace.Wrap(err)
}

if err = okta.CheckOrigin(authzCtx, req.User); err != nil {
return nil, trace.Wrap(err)
}
Expand Down Expand Up @@ -280,6 +284,10 @@ func (s *Service) UpdateUser(ctx context.Context, req *userspb.UpdateUserRequest
return nil, trace.Wrap(err)
}

if err := authz.AuthorizeAdminAction(ctx, authzCtx); err != nil {
return nil, trace.Wrap(err)
}

if err = okta.CheckOrigin(authzCtx, req.User); err != nil {
return nil, trace.Wrap(err)
}
Expand Down Expand Up @@ -346,6 +354,10 @@ func (s *Service) UpsertUser(ctx context.Context, req *userspb.UpsertUserRequest
return nil, trace.Wrap(err)
}

if err := authz.AuthorizeAdminAction(ctx, authzCtx); err != nil {
return nil, trace.Wrap(err)
}

if createdBy := req.User.GetCreatedBy(); createdBy.IsEmpty() {
req.User.SetCreatedBy(types.CreatedBy{
User: types.UserRef{Name: authzCtx.User.GetName()},
Expand Down Expand Up @@ -418,6 +430,10 @@ func (s *Service) DeleteUser(ctx context.Context, req *userspb.DeleteUserRequest
return nil, trace.Wrap(err)
}

if err := authz.AuthorizeAdminAction(ctx, authzCtx); err != nil {
return nil, trace.Wrap(err)
}

prevUser, err := s.cache.GetUser(ctx, req.Name, false)
var omitEditorEvent bool
if err != nil && !trace.IsNotFound(err) {
Expand Down
8 changes: 4 additions & 4 deletions lib/auth/users/usersv1/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func (a fakeAuthorizer) Authorize(ctx context.Context) (*authz.Context, error) {
},
},
},
Identity: identity,
Identity: identity,
AdminActionAuthorized: true,
}, nil
}

Expand Down Expand Up @@ -102,8 +103,8 @@ func (a fakeAuthorizer) Authorize(ctx context.Context) (*authz.Context, error) {
Username: "alice",
},
},
AdminActionAuthorized: true,
}, nil

}

type fakeChecker struct {
Expand Down Expand Up @@ -866,7 +867,6 @@ func TestRBAC(t *testing.T) {

for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {

env, err := newTestEnv(withAuthorizer(&fakeAuthorizer{authzContext: &authz.Context{
User: llama,
Checker: test.checker,
Expand All @@ -876,6 +876,7 @@ func TestRBAC(t *testing.T) {
Groups: []string{"dev"},
},
},
AdminActionAuthorized: true,
}}))
require.NoError(t, err, "creating test service")

Expand All @@ -888,5 +889,4 @@ func TestRBAC(t *testing.T) {
require.ElementsMatch(t, test.expectChecks, test.checker.checks)
})
}

}
7 changes: 4 additions & 3 deletions lib/authz/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ type Context struct {
// AdminActionVerified is whether this auth request is verified for admin actions. This
// either means that the request was MFA verified through the context or Hardware Key support,
// or the identity does not require admin MFA (built in roles, bot impersonated user, etc).
adminActionAuthorized bool
AdminActionAuthorized bool
}

// GetUserMetadata returns information about the authenticated identity
Expand Down Expand Up @@ -384,7 +384,7 @@ func (a *authorizer) checkAdminActionVerification(ctx context.Context, authConte
return trace.Wrap(err)
}

authContext.adminActionAuthorized = true
authContext.AdminActionAuthorized = true
return nil
}

Expand Down Expand Up @@ -1101,6 +1101,7 @@ func ContextForBuiltinRole(r BuiltinRole, recConfig types.SessionRecordingConfig
Identity: r,
UnmappedIdentity: r,
disableDeviceRoleMode: true, // Builtin roles skip device trust.
AdminActionAuthorized: true, // builtin roles skip mfa for admin actions.
}, nil
}

Expand Down Expand Up @@ -1324,7 +1325,7 @@ func AuthorizeContextWithVerbs(ctx context.Context, log logrus.FieldLogger, auth

// AuthorizeAdminAction will ensure that the user is authorized to perform admin actions.
func AuthorizeAdminAction(ctx context.Context, authCtx *Context) error {
if !authCtx.adminActionAuthorized {
if !authCtx.AdminActionAuthorized {
return trace.Wrap(&mfa.ErrAdminActionMFARequired)
}
return nil
Expand Down
1 change: 0 additions & 1 deletion lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,6 @@ func (process *TeleportProcess) initAuthExternalAuditLog(auditConfig types.Clust
if len(loggers) < 1 {
if externalAuditStorage.IsUsed() {
return nil, externalAuditMissingAthenaError

}
return nil, nil
}
Expand Down
7 changes: 6 additions & 1 deletion lib/web/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/julienschmidt/httprouter"

"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/mfa"
"github.com/gravitational/teleport/api/types"
wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes"
"github.com/gravitational/teleport/lib/httplib"
Expand Down Expand Up @@ -155,7 +156,11 @@ func updateUser(r *http.Request, m userAPIGetter, createdBy string) (*ui.User, e
return nil, trace.Wrap(err)
}

user, err := m.GetUser(r.Context(), req.Name, false)
// Remove the MFA resp from the context before getting the user.
// Otherwise, it will be consumed before the Update which actually
// requires the MFA.
getUserCtx := mfa.ContextWithMFAResponse(r.Context(), nil)
user, err := m.GetUser(getUserCtx, req.Name, false)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
Loading