| // 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 blesser |
| |
| import ( |
| "reflect" |
| "sort" |
| "strings" |
| "testing" |
| "time" |
| |
| "v.io/x/ref/services/identity/internal/oauth" |
| "v.io/x/ref/test/testutil" |
| |
| "v.io/v23/security" |
| ) |
| |
| func join(elements ...string) string { |
| return strings.Join(elements, security.ChainSeparator) |
| } |
| |
| func TestOAuthBlesser(t *testing.T) { |
| var ( |
| provider, user = testutil.NewPrincipal(), testutil.NewPrincipal() |
| ctx, call = fakeContextAndCall(provider, user) |
| ) |
| mockEmail := "testemail@example.com" |
| mockClientID := "test-client-id" |
| mockClientName := "test-client" |
| blesser := NewOAuthBlesserServer(OAuthBlesserParams{ |
| OAuthProvider: oauth.NewMockOAuth(mockEmail, mockClientID), |
| BlessingDuration: time.Hour, |
| AccessTokenClients: []oauth.AccessTokenClient{ |
| oauth.AccessTokenClient{ |
| Name: mockClientName, |
| ClientID: mockClientID, |
| }, |
| }, |
| }) |
| |
| b, extension, err := blesser.BlessUsingAccessToken(ctx, call, "test-access-token") |
| if err != nil { |
| t.Errorf("BlessUsingAccessToken failed: %v", err) |
| } |
| |
| wantExtension := join(mockEmail, mockClientName) |
| if extension != wantExtension { |
| t.Errorf("got extension: %s, want: %s", extension, wantExtension) |
| } |
| |
| if !reflect.DeepEqual(b.PublicKey(), user.PublicKey()) { |
| t.Errorf("Received blessing for public key %v. Client:%v, Blesser:%v", b.PublicKey(), user.PublicKey(), provider.PublicKey()) |
| } |
| |
| // When the user does not recognize the provider, it should not see any strings for |
| // the client's blessings. |
| if got := user.BlessingsInfo(b); got != nil { |
| t.Errorf("Got blessing with info %v, want nil", got) |
| } |
| // But once it recognizes the provider, it should see exactly the name |
| // "provider/testemail@example.com/test-client". |
| security.AddToRoots(user, b) |
| binfo := user.BlessingsInfo(b) |
| if num := len(binfo); num != 1 { |
| t.Errorf("Got blessings with %d names, want exactly one name", num) |
| } |
| if _, ok := binfo[join("provider", wantExtension)]; !ok { |
| t.Errorf("BlessingsInfo %v does not have name %s", binfo, wantExtension) |
| } |
| } |
| |
| func TestOAuthBlesserWithCaveats(t *testing.T) { |
| var ( |
| provider, user = testutil.NewPrincipal(), testutil.NewPrincipal() |
| ctx, call = fakeContextAndCall(provider, user) |
| ) |
| mockEmail := "testemail@example.com" |
| mockClientID := "test-client-id" |
| mockClientName := "test-client" |
| blesser := NewOAuthBlesserServer(OAuthBlesserParams{ |
| OAuthProvider: oauth.NewMockOAuth(mockEmail, mockClientID), |
| BlessingDuration: time.Hour, |
| AccessTokenClients: []oauth.AccessTokenClient{ |
| oauth.AccessTokenClient{ |
| Name: mockClientName, |
| ClientID: mockClientID, |
| }, |
| }, |
| }) |
| |
| expiryCav, err := security.NewExpiryCaveat(time.Now().Add(time.Minute)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| methodCav, err := security.NewMethodCaveat("foo", "bar") |
| if err != nil { |
| t.Fatal(err) |
| } |
| caveats := []security.Caveat{expiryCav, methodCav} |
| |
| b, extension, err := blesser.BlessUsingAccessTokenWithCaveats(ctx, call, "test-access-token", caveats) |
| if err != nil { |
| t.Errorf("BlessUsingAccessToken failed: %v", err) |
| } |
| |
| wantExtension := join(mockEmail, mockClientName) |
| if extension != wantExtension { |
| t.Errorf("got extension: %s, want: %s", extension, wantExtension) |
| } |
| |
| if !reflect.DeepEqual(b.PublicKey(), user.PublicKey()) { |
| t.Errorf("Received blessing for public key %v. Client:%v, Blesser:%v", b.PublicKey(), user.PublicKey(), provider.PublicKey()) |
| } |
| |
| // When the user does not recognize the provider, it should not see any strings for |
| // the client's blessings. |
| if got := user.BlessingsInfo(b); got != nil { |
| t.Errorf("Got blessing with info %v, want nil", got) |
| } |
| // But once it recognizes the provider, it should see exactly the name |
| // "provider/testemail@example.com/test-client". |
| security.AddToRoots(user, b) |
| binfo := user.BlessingsInfo(b) |
| if num := len(binfo); num != 1 { |
| t.Errorf("Got blessings with %d names, want exactly one name", num) |
| } |
| cavs, ok := binfo[join("provider", wantExtension)] |
| if !ok { |
| t.Errorf("BlessingsInfo %v does not have name %s", binfo, wantExtension) |
| } |
| if !caveatsMatch(cavs, caveats) { |
| t.Errorf("got %v, want %v", cavs, caveats) |
| } |
| } |
| |
| func caveatsMatch(got, want []security.Caveat) bool { |
| if len(got) != len(want) { |
| return false |
| } |
| gotStrings := make([]string, len(got)) |
| wantStrings := make([]string, len(want)) |
| for i := 0; i < len(got); i++ { |
| gotStrings[i] = got[i].String() |
| wantStrings[i] = want[i].String() |
| } |
| sort.Strings(gotStrings) |
| sort.Strings(wantStrings) |
| return reflect.DeepEqual(gotStrings, wantStrings) |
| } |