blob: 9dedfce0775ffaa0f650e4e29cd5ac1fd0edf9ef [file] [log] [blame] [edit]
// Copyright 2015 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 rpc
import (
"v.io/v23/context"
"v.io/v23/options"
"v.io/v23/rpc"
"v.io/v23/security"
"v.io/v23/verror"
"v.io/x/ref/lib/apilog"
)
var (
// These errors are intended to be used as arguments to higher
// level errors and hence {1}{2} is omitted from their format
// strings to avoid repeating these n-times in the final error
// message visible to the user.
errAuthServerNotAllowed = reg(".errAuthServerNotAllowed",
"server blessings {3} do not match any allowed server patterns {4}{:5}")
errMultipleAuthorizationPolicies = reg(".errMultipleAuthorizationPolicies", "at most one ServerAuthorizer option can be provided")
)
type serverAuthorizer struct {
auth security.Authorizer
extraPattern security.BlessingPattern
}
// newServerAuthorizer returns a security.Authorizer for authorizing the server
// during a flow. The authorization policy is based on options supplied to the
// call that initiated the flow.
//
// TODO(ashankar): Trace why we have the behavior in the following comment and
// consider removing it. It might be a relic from the early iterations of
// server authorization, but I suspect we can get rid of
// security.SplitPatternName and security.JoinPatternName? If we do, then this pattern argument
// goes away.
// If pattern is non-empty, then in addition, the server's blessing must satisfy the pattern.
//
// This method assumes that canCreateServerAuthorizer(opts) is nil.
func newServerAuthorizer(pattern security.BlessingPattern, opts ...rpc.CallOpt) security.Authorizer {
if len(pattern) == 0 {
return authorizerFromOpts(opts...)
}
return &serverAuthorizer{
auth: authorizerFromOpts(opts...),
extraPattern: pattern,
}
}
func authorizerFromOpts(opts ...rpc.CallOpt) security.Authorizer {
for _, o := range opts {
if v, ok := o.(options.ServerAuthorizer); ok {
return v
}
}
return security.EndpointAuthorizer()
}
func (a *serverAuthorizer) Authorize(ctx *context.T, call security.Call) error {
defer apilog.LogCallf(ctx, "call=")(ctx, "") // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
if err := a.auth.Authorize(ctx, call); err != nil {
return err
}
names, rejected := security.RemoteBlessingNames(ctx, call)
if !a.extraPattern.MatchedBy(names...) {
return verror.New(errAuthServerNotAllowed, ctx, names, a.extraPattern, rejected)
}
return nil
}
func canCreateServerAuthorizer(ctx *context.T, opts []rpc.CallOpt) error {
policy := false
for _, o := range opts {
switch o.(type) {
case options.ServerAuthorizer:
if policy {
return verror.New(errMultipleAuthorizationPolicies, ctx)
}
policy = true
}
}
return nil
}