// 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 (
	"reflect"

	"v.io/v23/context"
	"v.io/v23/options"
	"v.io/v23/rpc"
	"v.io/v23/security"
	"v.io/v23/verror"
	"v.io/x/lib/vlog"
)

// TODO(ribrdb): Flip this to true once everything is updated and also update
// the server authorizer tests.
const enableSecureServerAuth = false

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.
	errNoBlessingsFromServer      = reg(".errNoBlessingsFromServer", "server has not presented any blessings")
	errAuthNoServerBlessingsMatch = reg(".errAuthNoServerBlessingsMatch",
		"server blessings {3} do not match client expectations {4}, (rejected blessings: {5})")
	errAuthServerNotAllowed = reg(".errAuthServerNotAllowed",
		"server blessings {3} do not match any allowed server patterns {4}{:5}")
	errAuthServerKeyNotAllowed = reg(".errAuthServerKeyNotAllowed",
		"remote public key {3} not matched by server key {4}")
	errMultiplePublicKeys = reg(".errMultiplePublicKeyOptions", "at most one ServerPublicKey options can be provided")
)

// serverAuthorizer implements security.Authorizer.
type serverAuthorizer struct {
	allowedServerPolicies     [][]security.BlessingPattern
	serverPublicKey           security.PublicKey
	ignoreBlessingsInEndpoint bool
}

// 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. Additionally, if pattern is non-empty then
// the server will be authorized only if it presents at least one blessing
// that matches pattern.
//
// This method assumes that canCreateServerAuthorizer(opts) is nil.
func newServerAuthorizer(pattern security.BlessingPattern, opts ...rpc.CallOpt) security.Authorizer {
	auth := &serverAuthorizer{}
	for _, o := range opts {
		switch v := o.(type) {
		case options.ServerPublicKey:
			auth.serverPublicKey = v.PublicKey
		case options.AllowedServersPolicy:
			auth.allowedServerPolicies = append(auth.allowedServerPolicies, v)
		case options.SkipServerEndpointAuthorization:
			auth.ignoreBlessingsInEndpoint = true
		}
	}
	if len(pattern) > 0 {
		auth.allowedServerPolicies = append(auth.allowedServerPolicies, []security.BlessingPattern{pattern})
	}
	return auth
}

func (a *serverAuthorizer) Authorize(ctx *context.T, call security.Call) error {
	defer vlog.LogCallf("ctx=,call=")("") // AUTO-GENERATED, DO NOT EDIT, MUST BE FIRST STATEMENT
	if call.RemoteBlessings().IsZero() {
		return verror.New(errNoBlessingsFromServer, ctx)
	}
	serverBlessings, rejectedBlessings := security.RemoteBlessingNames(ctx, call)

	if epb := call.RemoteEndpoint().BlessingNames(); len(epb) > 0 && !a.ignoreBlessingsInEndpoint {
		matched := false
		for _, b := range epb {
			// TODO(ashankar,ataly): Should this be
			// security.BlessingPattern(b).MakeNonExtendable().MatchedBy()?
			// Because, without that, a delegate of the real server
			// can be a man-in-the-middle without failing
			// authorization. Is that a desirable property?
			if security.BlessingPattern(b).MatchedBy(serverBlessings...) {
				matched = true
				break
			}
		}
		if !matched {
			return verror.New(errAuthNoServerBlessingsMatch, ctx, serverBlessings, epb, rejectedBlessings)
		}
	} else if enableSecureServerAuth && len(epb) == 0 {
		// No blessings in the endpoint to set expectations on the
		// "identity" of the server.  Use the default authorization
		// policy.
		if err := security.DefaultAuthorizer().Authorize(ctx, call); err != nil {
			return err
		}
	}

	for _, patterns := range a.allowedServerPolicies {
		if !matchedBy(patterns, serverBlessings) {
			return verror.New(errAuthServerNotAllowed, ctx, serverBlessings, patterns, rejectedBlessings)
		}
	}

	if remoteKey, key := call.RemoteBlessings().PublicKey(), a.serverPublicKey; key != nil && !reflect.DeepEqual(remoteKey, key) {
		return verror.New(errAuthServerKeyNotAllowed, ctx, remoteKey, key)
	}

	return nil
}

func matchedBy(patterns []security.BlessingPattern, blessings []string) bool {
	if patterns == nil {
		return true
	}
	for _, p := range patterns {
		if p.MatchedBy(blessings...) {
			return true
		}
	}
	return false
}

func canCreateServerAuthorizer(ctx *context.T, opts []rpc.CallOpt) error {
	var pkey security.PublicKey
	for _, o := range opts {
		switch v := o.(type) {
		case options.ServerPublicKey:
			if pkey != nil && !reflect.DeepEqual(pkey, v.PublicKey) {
				return verror.New(errMultiplePublicKeys, ctx)
			}
			pkey = v.PublicKey
		}
	}
	return nil
}
