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

	"v.io/v23"
	"v.io/v23/options"
	"v.io/v23/security"
	"v.io/x/ref/runtime/internal/naming"

	"v.io/x/ref/test/testutil"
)

func TestServerAuthorizer(t *testing.T) {
	var (
		pclient = testutil.NewPrincipal()
		pserver = testutil.NewPrincipal()
		pother  = testutil.NewPrincipal()

		ali, _      = pserver.BlessSelf("ali")
		bob, _      = pserver.BlessSelf("bob")
		che, _      = pserver.BlessSelf("che")
		otherAli, _ = pother.BlessSelf("ali")
		zero        = security.Blessings{}

		ctx, shutdown = initForTest()

		U = func(blessings ...security.Blessings) security.Blessings {
			u, err := security.UnionOfBlessings(blessings...)
			if err != nil {
				t.Fatal(err)
			}
			return u
		}
	)
	defer shutdown()
	ctx, _ = v23.WithPrincipal(ctx, pclient)
	// Make client recognize ali, bob and otherAli blessings
	for _, b := range []security.Blessings{ali, bob, otherAli} {
		if err := pclient.AddToRoots(b); err != nil {
			t.Fatal(err)
		}
	}
	// All tests are run as if pclient is the client end and pserver is remote end.
	tests := []struct {
		serverBlessingNames []string
		auth                security.Authorizer
		authorizedServers   []security.Blessings
		unauthorizedServers []security.Blessings
	}{
		{
			// No blessings in the endpoint means that all servers are authorized.
			nil,
			newServerAuthorizer(""),
			[]security.Blessings{ali, otherAli, bob, che},
			[]security.Blessings{zero},
		},
		{
			// Endpoint sets the expectations for "ali" and "bob".
			[]string{"ali", "bob"},
			newServerAuthorizer(""),
			[]security.Blessings{ali, otherAli, bob, U(ali, che), U(bob, che)},
			[]security.Blessings{che},
		},
		{
			// Still only ali, otherAli and bob are authorized (che is not
			// authorized since it is not recognized by the client)
			[]string{"ali", "bob", "che"},
			newServerAuthorizer(""),
			[]security.Blessings{ali, otherAli, bob, U(ali, che), U(bob, che)},
			[]security.Blessings{che},
		},
		{

			// Only ali and otherAli are authorized (since there is an
			// allowed-servers policy that does not allow "bob")
			[]string{"ali", "bob", "che"},
			newServerAuthorizer("", options.AllowedServersPolicy{"ali", "bob"}, options.AllowedServersPolicy{"ali"}),
			[]security.Blessings{ali, otherAli, U(ali, che), U(ali, bob)},
			[]security.Blessings{bob, che},
		},
		{
			// Multiple AllowedServersPolicy are treated as an AND (and individual ones are "ORs")
			nil,
			newServerAuthorizer("", options.AllowedServersPolicy{"ali", "che"}, options.AllowedServersPolicy{"bob", "che"}),
			[]security.Blessings{U(ali, bob)},
			[]security.Blessings{ali, bob, che, U(ali, che), U(bob, che)},
		},
		{
			// Only otherAli is authorized (since only pother's public key is
			// authorized)
			[]string{"ali"},
			newServerAuthorizer("", options.ServerPublicKey{PublicKey: pother.PublicKey()}),
			[]security.Blessings{otherAli},
			[]security.Blessings{ali, bob, che},
		},
		{
			// Blessings in endpoint can be ignored.
			[]string{"ali"},
			newServerAuthorizer("", options.SkipServerEndpointAuthorization{}),
			[]security.Blessings{ali, bob, che, otherAli},
			nil,
		},
		{
			// Pattern specified is respected
			nil,
			newServerAuthorizer("bob"),
			[]security.Blessings{bob, U(ali, bob)},
			[]security.Blessings{ali, otherAli, che},
		},
		{
			// And concatenated with any existing AllowedServersPolicy
			[]string{"ali", "bob", "che"},
			newServerAuthorizer("bob", options.AllowedServersPolicy{"bob", "che"}),
			[]security.Blessings{bob, U(ali, bob), U(ali, bob, che)},
			[]security.Blessings{ali, che},
		},
		{
			// And if the intersection of AllowedServersPolicy and the pattern be empty, then so be it!
			[]string{"ali", "bob", "che"},
			newServerAuthorizer("bob", options.AllowedServersPolicy{"ali", "che"}),
			[]security.Blessings{U(ali, bob), U(ali, bob, che)},
			[]security.Blessings{ali, otherAli, bob, che, U(ali, che)},
		},
	}
	for _, test := range tests {
		for _, s := range test.authorizedServers {
			if err := test.auth.Authorize(ctx, &mockCall{
				p:   pclient,
				r:   s,
				rep: &naming.Endpoint{Blessings: test.serverBlessingNames},
			}); err != nil {
				t.Errorf("serverAuthorizer: %#v failed to authorize server: %v", test.auth, s)
			}
		}
		for _, s := range test.unauthorizedServers {
			if err := test.auth.Authorize(ctx, &mockCall{
				p:   pclient,
				r:   s,
				rep: &naming.Endpoint{Blessings: test.serverBlessingNames},
			}); err == nil {
				t.Errorf("serverAuthorizer: %#v authorized server: %v", test.auth, s)
			}
		}
	}
}
