blob: a76806d7c8a8e84cc100cff3e3b5dfdd446cf858 [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package common
import (
"sort"
"v.io/v23/context"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/security/access"
wire "v.io/v23/services/syncbase"
"v.io/v23/verror"
)
// ValidatePerms does basic sanity checking on the provided perms:
// - Perms can contain only tags in the provided whitelist.
// - At least one admin must be included to avoid permanently losing access.
func ValidatePerms(ctx *context.T, perms access.Permissions, allowTags []access.Tag) error {
// Perms cannot be empty or nil.
if len(perms) == 0 {
return NewErrPermsEmpty(ctx)
}
// Perms cannot contain any tags not in the allowTags whitelist.
allowTagsSet := make(map[string]struct{}, len(allowTags))
for _, tag := range allowTags {
allowTagsSet[string(tag)] = struct{}{}
}
var disallowedTags []string
for tag, _ := range perms {
if _, ok := allowTagsSet[tag]; !ok {
disallowedTags = append(disallowedTags, tag)
}
}
if len(disallowedTags) > 0 {
sort.Strings(disallowedTags)
return NewErrPermsDisallowedTags(ctx, disallowedTags, access.TagStrings(allowTags...))
}
// Perms must include at least one Admin.
// TODO(ivanpi): More sophisticated admin verification, e.g. check that NotIn
// doesn't blacklist all possible In matches.
if adminAcl, ok := perms[string(access.Admin)]; !ok || len(adminAcl.In) == 0 {
return NewErrPermsNoAdmin(ctx)
}
// TODO(ivanpi): Check that perms are enforceable? It would make validation
// context-dependent.
return nil
}
// CheckImplicitPerms performs an authorization check against the implicit
// permissions derived from the blessing pattern in the Id. It returns the
// generated implicit perms or an authorization error.
// TODO(ivanpi): Change to check against the specific blessing used for signing
// instead of any blessing in call.Security().
func CheckImplicitPerms(ctx *context.T, call rpc.ServerCall, id wire.Id, allowedTags []access.Tag) (access.Permissions, error) {
implicitPerms := access.Permissions{}.Add(security.BlessingPattern(id.Blessing), access.TagStrings(allowedTags...)...)
// Note, allowedTags is expected to contain access.Admin.
if err := implicitPerms[string(access.Admin)].Authorize(ctx, call.Security()); err != nil {
return nil, verror.New(wire.ErrUnauthorizedCreateId, ctx, id.Blessing, id.Name, err)
}
return implicitPerms, nil
}