Authorize gRPC requests with vault API tokens
This commit is contained in:
+183
-34
@@ -8,7 +8,9 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.julianfamily.org/keepassgo/apitokens"
|
||||
"git.julianfamily.org/keepassgo/clipboard"
|
||||
"git.julianfamily.org/keepassgo/passwords"
|
||||
keepassgov1 "git.julianfamily.org/keepassgo/proto/keepassgo/v1"
|
||||
@@ -190,23 +192,27 @@ func mapLifecycleError(operation string, err error) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ListEntries(_ context.Context, req *keepassgov1.ListEntriesRequest) (*keepassgov1.ListEntriesResponse, error) {
|
||||
func (s *Server) ListEntries(ctx context.Context, req *keepassgov1.ListEntriesRequest) (*keepassgov1.ListEntriesResponse, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
if _, err := s.authorizePathRequest(ctx, apitokens.OperationListEntries, req.GetPath()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
model := s.visibleModel()
|
||||
var entries []vault.Entry
|
||||
if strings.TrimSpace(req.GetQuery()) != "" {
|
||||
results := s.model.Search(req.GetQuery())
|
||||
results := model.Search(req.GetQuery())
|
||||
entries = make([]vault.Entry, 0, len(results))
|
||||
for _, result := range results {
|
||||
entries = append(entries, result.Entry)
|
||||
}
|
||||
} else {
|
||||
entries = s.model.EntriesInPath(req.GetPath())
|
||||
entries = model.EntriesInPath(req.GetPath())
|
||||
}
|
||||
|
||||
resp := &keepassgov1.ListEntriesResponse{
|
||||
@@ -219,23 +225,30 @@ func (s *Server) ListEntries(_ context.Context, req *keepassgov1.ListEntriesRequ
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListGroups(_ context.Context, req *keepassgov1.ListGroupsRequest) (*keepassgov1.ListGroupsResponse, error) {
|
||||
func (s *Server) ListGroups(ctx context.Context, req *keepassgov1.ListGroupsRequest) (*keepassgov1.ListGroupsResponse, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
if _, err := s.authorizePathRequest(ctx, apitokens.OperationListGroups, req.GetPath()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &keepassgov1.ListGroupsResponse{
|
||||
Names: s.model.ChildGroups(req.GetPath()),
|
||||
Names: s.visibleModel().ChildGroups(req.GetPath()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) CreateGroup(_ context.Context, req *keepassgov1.CreateGroupRequest) (*keepassgov1.CreateGroupResponse, error) {
|
||||
func (s *Server) CreateGroup(ctx context.Context, req *keepassgov1.CreateGroupRequest) (*keepassgov1.CreateGroupResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, err := s.authorizePathRequest(ctx, apitokens.OperationMutateGroup, req.GetParentPath()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
@@ -245,10 +258,14 @@ func (s *Server) CreateGroup(_ context.Context, req *keepassgov1.CreateGroupRequ
|
||||
return &keepassgov1.CreateGroupResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RenameGroup(_ context.Context, req *keepassgov1.RenameGroupRequest) (*keepassgov1.RenameGroupResponse, error) {
|
||||
func (s *Server) RenameGroup(ctx context.Context, req *keepassgov1.RenameGroupRequest) (*keepassgov1.RenameGroupResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, err := s.authorizePathRequest(ctx, apitokens.OperationMutateGroup, req.GetPath()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
@@ -264,10 +281,14 @@ func (s *Server) RenameGroup(_ context.Context, req *keepassgov1.RenameGroupRequ
|
||||
return &keepassgov1.RenameGroupResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteGroup(_ context.Context, req *keepassgov1.DeleteGroupRequest) (*keepassgov1.DeleteGroupResponse, error) {
|
||||
func (s *Server) DeleteGroup(ctx context.Context, req *keepassgov1.DeleteGroupRequest) (*keepassgov1.DeleteGroupResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, err := s.authorizePathRequest(ctx, apitokens.OperationMutateGroup, req.GetPath()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
@@ -287,7 +308,7 @@ func (s *Server) DeleteGroup(_ context.Context, req *keepassgov1.DeleteGroupRequ
|
||||
return &keepassgov1.DeleteGroupResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpsertEntry(_ context.Context, req *keepassgov1.UpsertEntryRequest) (*keepassgov1.UpsertEntryResponse, error) {
|
||||
func (s *Server) UpsertEntry(ctx context.Context, req *keepassgov1.UpsertEntryRequest) (*keepassgov1.UpsertEntryResponse, error) {
|
||||
if req.GetEntry() == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "missing entry")
|
||||
}
|
||||
@@ -299,6 +320,10 @@ func (s *Server) UpsertEntry(_ context.Context, req *keepassgov1.UpsertEntryRequ
|
||||
s.mu.Unlock()
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationMutateEntry, entry); err != nil {
|
||||
s.mu.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
s.model.UpsertEntry(entry)
|
||||
s.dirty = true
|
||||
s.mu.Unlock()
|
||||
@@ -306,13 +331,18 @@ func (s *Server) UpsertEntry(_ context.Context, req *keepassgov1.UpsertEntryRequ
|
||||
return &keepassgov1.UpsertEntryResponse{Entry: entryToProto(entry)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteEntry(_ context.Context, req *keepassgov1.DeleteEntryRequest) (*keepassgov1.DeleteEntryResponse, error) {
|
||||
func (s *Server) DeleteEntry(ctx context.Context, req *keepassgov1.DeleteEntryRequest) (*keepassgov1.DeleteEntryResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
if entry, err := findEntryByID(s.model, req.GetId()); err == nil {
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationMutateEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.model.DeleteEntry(req.GetId()); err != nil {
|
||||
if errors.Is(err, vault.ErrEntryNotFound) {
|
||||
@@ -325,7 +355,7 @@ func (s *Server) DeleteEntry(_ context.Context, req *keepassgov1.DeleteEntryRequ
|
||||
return &keepassgov1.DeleteEntryResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RestoreEntry(_ context.Context, req *keepassgov1.RestoreEntryRequest) (*keepassgov1.RestoreEntryResponse, error) {
|
||||
func (s *Server) RestoreEntry(ctx context.Context, req *keepassgov1.RestoreEntryRequest) (*keepassgov1.RestoreEntryResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@@ -340,6 +370,11 @@ func (s *Server) RestoreEntry(_ context.Context, req *keepassgov1.RestoreEntryRe
|
||||
break
|
||||
}
|
||||
}
|
||||
if restored.ID != "" {
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationMutateEntry, restored); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.model.RestoreEntry(req.GetId()); err != nil {
|
||||
if errors.Is(err, vault.ErrEntryNotFound) {
|
||||
@@ -352,7 +387,7 @@ func (s *Server) RestoreEntry(_ context.Context, req *keepassgov1.RestoreEntryRe
|
||||
return &keepassgov1.RestoreEntryResponse{Entry: entryToProto(restored)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListEntryHistory(_ context.Context, req *keepassgov1.ListEntryHistoryRequest) (*keepassgov1.ListEntryHistoryResponse, error) {
|
||||
func (s *Server) ListEntryHistory(ctx context.Context, req *keepassgov1.ListEntryHistoryRequest) (*keepassgov1.ListEntryHistoryResponse, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
@@ -364,6 +399,9 @@ func (s *Server) ListEntryHistory(_ context.Context, req *keepassgov1.ListEntryH
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationReadEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &keepassgov1.ListEntryHistoryResponse{
|
||||
Entries: make([]*keepassgov1.Entry, 0, len(entry.History)),
|
||||
@@ -374,13 +412,20 @@ func (s *Server) ListEntryHistory(_ context.Context, req *keepassgov1.ListEntryH
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) RestoreEntryHistory(_ context.Context, req *keepassgov1.RestoreEntryHistoryRequest) (*keepassgov1.RestoreEntryHistoryResponse, error) {
|
||||
func (s *Server) RestoreEntryHistory(ctx context.Context, req *keepassgov1.RestoreEntryHistoryRequest) (*keepassgov1.RestoreEntryHistoryResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
entry, err := findEntryByID(s.model, req.GetId())
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationMutateEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.model.RestoreEntryVersion(req.GetId(), int(req.GetHistoryIndex())); err != nil {
|
||||
if errors.Is(err, vault.ErrEntryNotFound) {
|
||||
@@ -389,7 +434,7 @@ func (s *Server) RestoreEntryHistory(_ context.Context, req *keepassgov1.Restore
|
||||
return nil, status.Errorf(codes.Internal, "restore entry history: %v", err)
|
||||
}
|
||||
|
||||
entry, err := findEntryByID(s.model, req.GetId())
|
||||
entry, err = findEntryByID(s.model, req.GetId())
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
@@ -477,7 +522,7 @@ func (s *Server) InstantiateTemplate(_ context.Context, req *keepassgov1.Instant
|
||||
return &keepassgov1.InstantiateTemplateResponse{Entry: entryToProto(entry)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListAttachments(_ context.Context, req *keepassgov1.ListAttachmentsRequest) (*keepassgov1.ListAttachmentsResponse, error) {
|
||||
func (s *Server) ListAttachments(ctx context.Context, req *keepassgov1.ListAttachmentsRequest) (*keepassgov1.ListAttachmentsResponse, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
@@ -489,6 +534,9 @@ func (s *Server) ListAttachments(_ context.Context, req *keepassgov1.ListAttachm
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationReadEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
names := make([]string, 0, len(entry.Attachments))
|
||||
for name := range entry.Attachments {
|
||||
@@ -499,7 +547,7 @@ func (s *Server) ListAttachments(_ context.Context, req *keepassgov1.ListAttachm
|
||||
return &keepassgov1.ListAttachmentsResponse{Names: names}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UploadAttachment(_ context.Context, req *keepassgov1.UploadAttachmentRequest) (*keepassgov1.UploadAttachmentResponse, error) {
|
||||
func (s *Server) UploadAttachment(ctx context.Context, req *keepassgov1.UploadAttachmentRequest) (*keepassgov1.UploadAttachmentResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@@ -511,6 +559,9 @@ func (s *Server) UploadAttachment(_ context.Context, req *keepassgov1.UploadAtta
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationMutateEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Attachments == nil {
|
||||
entry.Attachments = map[string][]byte{}
|
||||
@@ -522,7 +573,7 @@ func (s *Server) UploadAttachment(_ context.Context, req *keepassgov1.UploadAtta
|
||||
return &keepassgov1.UploadAttachmentResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DownloadAttachment(_ context.Context, req *keepassgov1.DownloadAttachmentRequest) (*keepassgov1.DownloadAttachmentResponse, error) {
|
||||
func (s *Server) DownloadAttachment(ctx context.Context, req *keepassgov1.DownloadAttachmentRequest) (*keepassgov1.DownloadAttachmentResponse, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
@@ -534,6 +585,9 @@ func (s *Server) DownloadAttachment(_ context.Context, req *keepassgov1.Download
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationReadEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
content, ok := entry.Attachments[req.GetName()]
|
||||
if !ok {
|
||||
@@ -545,7 +599,7 @@ func (s *Server) DownloadAttachment(_ context.Context, req *keepassgov1.Download
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteAttachment(_ context.Context, req *keepassgov1.DeleteAttachmentRequest) (*keepassgov1.DeleteAttachmentResponse, error) {
|
||||
func (s *Server) DeleteAttachment(ctx context.Context, req *keepassgov1.DeleteAttachmentRequest) (*keepassgov1.DeleteAttachmentResponse, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@@ -557,6 +611,9 @@ func (s *Server) DeleteAttachment(_ context.Context, req *keepassgov1.DeleteAtta
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, apitokens.OperationMutateEntry, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, ok := entry.Attachments[req.GetName()]; !ok {
|
||||
return nil, status.Error(codes.NotFound, "attachment not found")
|
||||
@@ -572,7 +629,7 @@ func (s *Server) DeleteAttachment(_ context.Context, req *keepassgov1.DeleteAtta
|
||||
return &keepassgov1.DeleteAttachmentResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) CopyEntryField(_ context.Context, req *keepassgov1.CopyEntryFieldRequest) (*keepassgov1.CopyEntryFieldResponse, error) {
|
||||
func (s *Server) CopyEntryField(ctx context.Context, req *keepassgov1.CopyEntryFieldRequest) (*keepassgov1.CopyEntryFieldResponse, error) {
|
||||
s.mu.RLock()
|
||||
model := s.model
|
||||
locked := s.locked
|
||||
@@ -581,6 +638,13 @@ func (s *Server) CopyEntryField(_ context.Context, req *keepassgov1.CopyEntryFie
|
||||
if locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
entry, err := findEntryByID(model, req.GetId())
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, err.Error())
|
||||
}
|
||||
if _, err := s.authorizeEntryRequest(ctx, copyOperation(req.GetTarget()), entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
service := clipboard.Service{Writer: s.clipboard}
|
||||
if err := service.Copy(model, req.GetId(), clipboard.Target(req.GetTarget())); err != nil {
|
||||
@@ -597,10 +661,14 @@ func (s *Server) CopyEntryField(_ context.Context, req *keepassgov1.CopyEntryFie
|
||||
return &keepassgov1.CopyEntryFieldResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GeneratePassword(_ context.Context, req *keepassgov1.GeneratePasswordRequest) (*keepassgov1.GeneratePasswordResponse, error) {
|
||||
func (s *Server) GeneratePassword(ctx context.Context, req *keepassgov1.GeneratePasswordRequest) (*keepassgov1.GeneratePasswordResponse, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if _, err := s.authenticateRequest(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.locked {
|
||||
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
|
||||
}
|
||||
@@ -665,27 +733,108 @@ func findMutableEntryByID(model *vault.Model, id string) (vault.Entry, int, erro
|
||||
return vault.Entry{}, -1, vault.ErrEntryNotFound
|
||||
}
|
||||
|
||||
func BearerTokenInterceptor(expectedToken string) grpc.UnaryServerInterceptor {
|
||||
func (s *Server) visibleModel() vault.Model {
|
||||
out := s.model
|
||||
out.Entries = nil
|
||||
for _, entry := range s.model.Entries {
|
||||
token, ok, err := apitokens.TokenFromEntry(entry)
|
||||
if err == nil && ok && token.ID != "" {
|
||||
continue
|
||||
}
|
||||
out.Entries = append(out.Entries, entry)
|
||||
}
|
||||
out.Groups = nil
|
||||
for _, path := range s.model.Groups {
|
||||
if len(path) >= 2 && path[0] == "Root" && path[1] == "API Tokens" {
|
||||
continue
|
||||
}
|
||||
out.Groups = append(out.Groups, path)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var timeNow = func() time.Time { return time.Now().UTC() }
|
||||
|
||||
func (s *Server) authenticateRequest(ctx context.Context) (apitokens.Token, error) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return apitokens.Token{}, status.Error(codes.Unauthenticated, "missing metadata")
|
||||
}
|
||||
values := md.Get("authorization")
|
||||
if len(values) == 0 {
|
||||
return apitokens.Token{}, status.Error(codes.Unauthenticated, "missing authorization")
|
||||
}
|
||||
const prefix = "Bearer "
|
||||
if !strings.HasPrefix(values[0], prefix) {
|
||||
return apitokens.Token{}, status.Error(codes.Unauthenticated, "invalid bearer token")
|
||||
}
|
||||
tokens, err := apitokens.Entries(s.model)
|
||||
if err != nil {
|
||||
return apitokens.Token{}, status.Errorf(codes.Internal, "load api tokens: %v", err)
|
||||
}
|
||||
token, err := apitokens.Authenticate(tokens, strings.TrimSpace(strings.TrimPrefix(values[0], prefix)), timeNow())
|
||||
if err != nil {
|
||||
switch err {
|
||||
case apitokens.ErrInvalidToken, apitokens.ErrExpiredToken, apitokens.ErrDisabledToken:
|
||||
return apitokens.Token{}, status.Error(codes.Unauthenticated, err.Error())
|
||||
default:
|
||||
return apitokens.Token{}, status.Errorf(codes.Internal, "authenticate api token: %v", err)
|
||||
}
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (s *Server) authorizePathRequest(ctx context.Context, op apitokens.Operation, path []string) (apitokens.Token, error) {
|
||||
token, err := s.authenticateRequest(ctx)
|
||||
if err != nil {
|
||||
return apitokens.Token{}, err
|
||||
}
|
||||
if apitokens.Evaluate(token, op, apitokens.Resource{Kind: apitokens.ResourceGroup, Path: path}) != apitokens.DecisionAllow {
|
||||
return apitokens.Token{}, status.Error(codes.PermissionDenied, "access is not allowed for this token")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (s *Server) authorizeEntryRequest(ctx context.Context, op apitokens.Operation, entry vault.Entry) (apitokens.Token, error) {
|
||||
token, err := s.authenticateRequest(ctx)
|
||||
if err != nil {
|
||||
return apitokens.Token{}, err
|
||||
}
|
||||
if apitokens.Evaluate(token, op, apitokens.Resource{Kind: apitokens.ResourceEntry, EntryID: entry.ID, Path: entry.Path}) != apitokens.DecisionAllow {
|
||||
return apitokens.Token{}, status.Error(codes.PermissionDenied, "access is not allowed for this token")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func copyOperation(target string) apitokens.Operation {
|
||||
switch clipboard.Target(target) {
|
||||
case clipboard.TargetUsername:
|
||||
return apitokens.OperationCopyUsername
|
||||
case clipboard.TargetURL:
|
||||
return apitokens.OperationCopyURL
|
||||
default:
|
||||
return apitokens.OperationCopyPassword
|
||||
}
|
||||
}
|
||||
|
||||
func AuthInterceptor(server *Server) grpc.UnaryServerInterceptor {
|
||||
return func(
|
||||
ctx context.Context,
|
||||
req any,
|
||||
info *grpc.UnaryServerInfo,
|
||||
handler grpc.UnaryHandler,
|
||||
) (any, error) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return nil, status.Error(codes.Unauthenticated, "missing metadata")
|
||||
switch info.FullMethod {
|
||||
case "/keepassgo.v1.VaultService/GetSessionStatus",
|
||||
"/keepassgo.v1.VaultService/OpenVault",
|
||||
"/keepassgo.v1.VaultService/OpenRemoteVault",
|
||||
"/keepassgo.v1.VaultService/SaveVault",
|
||||
"/keepassgo.v1.VaultService/LockVault",
|
||||
"/keepassgo.v1.VaultService/UnlockVault":
|
||||
if _, err := server.authenticateRequest(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
values := md.Get("authorization")
|
||||
if len(values) == 0 {
|
||||
return nil, status.Error(codes.Unauthenticated, "missing authorization")
|
||||
}
|
||||
|
||||
if values[0] != "Bearer "+expectedToken {
|
||||
return nil, status.Error(codes.Unauthenticated, "invalid bearer token")
|
||||
}
|
||||
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user