Hide physical keepass paths in token and approval UX
This commit is contained in:
+25
-6
@@ -1221,6 +1221,7 @@ func (s *Server) authorizeTemplateRequest(ctx context.Context, op apitokens.Oper
|
||||
|
||||
func (s *Server) authorizeResourceRequest(ctx context.Context, token apitokens.Token, op apitokens.Operation, resource apitokens.Resource) (apitokens.Token, error) {
|
||||
model, _ := s.snapshotModel()
|
||||
displayResource := displayAuthorizationResource(resource)
|
||||
switch evaluateAuthorization(model, token, op, resource) {
|
||||
case apitokens.DecisionAllow:
|
||||
return token, nil
|
||||
@@ -1233,9 +1234,9 @@ func (s *Server) authorizeResourceRequest(ctx context.Context, token apitokens.T
|
||||
TokenName: token.Name,
|
||||
ClientName: token.ClientName,
|
||||
Operation: op,
|
||||
Resource: resource,
|
||||
Resource: displayResource,
|
||||
})
|
||||
result, err := s.approvals.Request(ctx, token, op, resource)
|
||||
result, err := s.approvals.Request(ctx, token, op, displayResource)
|
||||
if result.Rule != nil {
|
||||
if persistErr := s.persistApprovalRule(token.ID, *result.Rule); persistErr != nil {
|
||||
return apitokens.Token{}, status.Errorf(codes.Internal, "persist approval decision: %v", persistErr)
|
||||
@@ -1249,7 +1250,7 @@ func (s *Server) authorizeResourceRequest(ctx context.Context, token apitokens.T
|
||||
TokenName: token.Name,
|
||||
ClientName: token.ClientName,
|
||||
Operation: op,
|
||||
Resource: resource,
|
||||
Resource: displayResource,
|
||||
})
|
||||
return token, nil
|
||||
case errors.Is(err, apiapproval.ErrRequestDenied):
|
||||
@@ -1259,7 +1260,7 @@ func (s *Server) authorizeResourceRequest(ctx context.Context, token apitokens.T
|
||||
TokenName: token.Name,
|
||||
ClientName: token.ClientName,
|
||||
Operation: op,
|
||||
Resource: resource,
|
||||
Resource: displayResource,
|
||||
})
|
||||
return apitokens.Token{}, status.Error(codes.PermissionDenied, "access denied by user approval")
|
||||
case errors.Is(err, apiapproval.ErrRequestCanceled):
|
||||
@@ -1269,7 +1270,7 @@ func (s *Server) authorizeResourceRequest(ctx context.Context, token apitokens.T
|
||||
TokenName: token.Name,
|
||||
ClientName: token.ClientName,
|
||||
Operation: op,
|
||||
Resource: resource,
|
||||
Resource: displayResource,
|
||||
})
|
||||
return apitokens.Token{}, status.Error(codes.Unauthenticated, "authorization request canceled")
|
||||
case errors.Is(err, apiapproval.ErrRequestTimedOut):
|
||||
@@ -1279,7 +1280,7 @@ func (s *Server) authorizeResourceRequest(ctx context.Context, token apitokens.T
|
||||
TokenName: token.Name,
|
||||
ClientName: token.ClientName,
|
||||
Operation: op,
|
||||
Resource: resource,
|
||||
Resource: displayResource,
|
||||
})
|
||||
return apitokens.Token{}, status.Error(codes.DeadlineExceeded, "authorization request timed out")
|
||||
case errors.Is(err, context.Canceled):
|
||||
@@ -1355,6 +1356,11 @@ func canonicalizeAuthorizationResource(model vault.Model, resource apitokens.Res
|
||||
return resource
|
||||
}
|
||||
|
||||
func displayAuthorizationResource(resource apitokens.Resource) apitokens.Resource {
|
||||
resource.Path = displayAuthorizationPath(resource.Path)
|
||||
return resource
|
||||
}
|
||||
|
||||
func canonicalAuthorizationPath(model vault.Model, path []string) []string {
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
@@ -1374,6 +1380,19 @@ func canonicalAuthorizationPath(model vault.Model, path []string) []string {
|
||||
return vaultview.VaultRoot(model).ToPhysicalPath(path)
|
||||
}
|
||||
|
||||
func displayAuthorizationPath(path []string) []string {
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
}
|
||||
if path[0] == vaultview.KeepassRoot {
|
||||
return append([]string{"Root"}, append([]string(nil), path[1:]...)...)
|
||||
}
|
||||
if path[0] == "Root" {
|
||||
return append([]string(nil), path...)
|
||||
}
|
||||
return append([]string(nil), path...)
|
||||
}
|
||||
|
||||
func copyOperation(target string) apitokens.Operation {
|
||||
switch clipboard.Target(target) {
|
||||
case clipboard.TargetUsername:
|
||||
|
||||
@@ -396,6 +396,58 @@ func TestVaultServiceFindsBrowserLoginsRechecksChildPoliciesAfterPrompt(t *testi
|
||||
}
|
||||
}
|
||||
|
||||
func TestVaultServiceApprovalRequestsUseLogicalRootPathForPhysicalVault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
model := vault.Model{
|
||||
Entries: []vault.Entry{
|
||||
{
|
||||
ID: "codex-nextcloud",
|
||||
Title: "Nextcloud (codex)",
|
||||
Username: "jjulian",
|
||||
Password: "secret-1",
|
||||
URL: "https://nextcloud.example.invalid",
|
||||
Path: []string{"keepass", "Joe", "codex"},
|
||||
},
|
||||
testAPITokenEntry(t),
|
||||
},
|
||||
Groups: [][]string{
|
||||
{"keepass"},
|
||||
{"keepass", "Joe"},
|
||||
{"keepass", "Joe", "codex"},
|
||||
},
|
||||
}
|
||||
client, _, service, cleanup := newTestHarnessForModel(t, model)
|
||||
defer cleanup()
|
||||
service.approvals = apiapproval.NewBroker(time.Minute)
|
||||
|
||||
respCh := make(chan *keepassgov1.ListEntriesResponse, 1)
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
resp, err := client.ListEntries(tokenContext(defaultTestTokenSecret), &keepassgov1.ListEntriesRequest{
|
||||
Path: []string{"Joe", "codex"},
|
||||
})
|
||||
respCh <- resp
|
||||
errCh <- err
|
||||
}()
|
||||
|
||||
pending := waitForServerPendingApproval(t, service, 1)[0]
|
||||
if got := pending.Resource.Path; !slices.Equal(got, []string{"Root", "Joe", "codex"}) {
|
||||
t.Fatalf("pending.Resource.Path = %v, want [Root Joe codex]", got)
|
||||
}
|
||||
if _, _, err := service.ResolveApproval(pending.ID, apiapproval.OutcomeAllowOnce); err != nil {
|
||||
t.Fatalf("ResolveApproval(allow once) error = %v", err)
|
||||
}
|
||||
|
||||
if err := <-errCh; err != nil {
|
||||
t.Fatalf("ListEntries() error = %v", err)
|
||||
}
|
||||
resp := <-respCh
|
||||
if len(resp.GetEntries()) != 1 || resp.GetEntries()[0].GetId() != "codex-nextcloud" {
|
||||
t.Fatalf("ListEntries().Entries = %#v, want codex-nextcloud after approval", resp.GetEntries())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVaultServiceDoesNotMatchSpecificBrowserEntryToParentDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user