| // 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 main_test |
| |
| import ( |
| "crypto/tls" |
| "encoding/base64" |
| _ "encoding/json" |
| "fmt" |
| "io/ioutil" |
| "net/http" |
| "net/http/cookiejar" |
| "strings" |
| "testing" |
| |
| "v.io/v23/context" |
| "v.io/v23/naming" |
| "v.io/v23/security" |
| "v.io/v23/services/stats" |
| "v.io/v23/vom" |
| "v.io/x/ref/test/testutil" |
| "v.io/x/ref/test/v23test" |
| ) |
| |
| const urlRE = "^(https://.*)$" |
| |
| func httpGet(t *testing.T, url string) string { |
| transport := &http.Transport{ |
| TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, |
| } |
| jar, err := cookiejar.New(&cookiejar.Options{}) |
| if err != nil { |
| t.Fatalf("failed to create a cookie jar: %v", err) |
| } |
| client := &http.Client{ |
| Jar: jar, |
| Transport: transport, |
| } |
| resp, err := client.Get(url) |
| if err != nil { |
| t.Fatalf("Get(%q) failed: %v", url, err) |
| } |
| output, err := ioutil.ReadAll(resp.Body) |
| resp.Body.Close() |
| if err != nil { |
| t.Fatalf("ReadAll() failed: %v", err) |
| } |
| return string(output) |
| } |
| |
| func seekBlessings(t *testing.T, sh *v23test.Shell, principal, httpAddr string) { |
| args := []string{ |
| "seekblessings", |
| "--browser=false", |
| fmt.Sprintf("--from=%s/auth/google", httpAddr), |
| "-v=3", |
| } |
| cmd := sh.Cmd(principal, args...) |
| cmd.Start() |
| line := cmd.S.ExpectSetEventuallyRE(urlRE)[0][1] |
| // Scan the output of "principal seekblessings", looking for the |
| // URL that can be used to retrieve the blessings. |
| output := httpGet(t, line) |
| if want := "Received blessings: <tt>root:u:testemail@example.com:test-extension"; !strings.Contains(output, want) { |
| t.Fatalf("failed to seek blessings: %v", string(output)) |
| } |
| } |
| |
| func testOauthHandler(t *testing.T, addr string) { |
| p := testutil.NewPrincipal("foo") |
| keyBytes, err := p.PublicKey().MarshalBinary() |
| if err != nil { |
| t.Fatal(err) |
| } |
| url := addr + "/auth/google/bless?token=tok&output_format=base64vom&public_key=" + base64.URLEncoding.EncodeToString(keyBytes) |
| output := httpGet(t, url) |
| var blessings security.Blessings |
| if raw, err := base64.URLEncoding.DecodeString(output); err != nil { |
| t.Fatal(err) |
| } else if err = vom.Decode(raw, &blessings); err != nil { |
| t.Fatal(err) |
| } |
| expected := "root:o:test-client-id:testemail@example.com" |
| if !blessings.CouldHaveNames([]string{expected}) { |
| t.Fatalf("Wanted blessing root:o:clientid:email, got %v", blessings) |
| } |
| } |
| |
| func readCounter(t *testing.T, ctx *context.T, addr, stat string) (int64, error) { |
| v, err := stats.StatsClient(naming.Join(addr, stat)).Value(ctx) |
| if err != nil { |
| return 0, err |
| } |
| var c int64 |
| err = v.ToValue(&c) |
| return c, err |
| } |
| |
| func TestV23IdentityServer(t *testing.T) { |
| v23test.SkipUnlessRunningIntegrationTests(t) |
| sh := v23test.NewShell(t, nil) |
| defer sh.Cleanup() |
| sh.StartRootMountTable() |
| |
| // Start identityd: |
| // |
| // identityd must have credentials that recognize the root mounttable. |
| // In production, the two share a common root certificate and thus |
| // recognize each other. The same is done here: sh.Credentials.Principal |
| // wields the root key. |
| identityd := v23test.BuildGoPkg(sh, "v.io/x/ref/services/identity/internal/identityd_test") |
| creds := sh.ForkCredentials("u") |
| oauthCreds := sh.ForkCredentials("o") |
| |
| cmd := sh.Cmd(identityd, |
| "-v23.tcp.address=127.0.0.1:0", |
| "-http-addr=127.0.0.1:0", |
| "-oauth-agent-path="+oauthCreds.Handle).WithCredentials(creds) |
| cmd.Start() |
| httpAddr := cmd.S.ExpectVar("HTTP_ADDR") |
| v23Addr := cmd.S.ExpectVar("NAME") |
| |
| // Use the principal tool to seekblessings. |
| // This tool will not run with any credentials: Its whole purpose is to "seek" them! |
| principal := v23test.BuildGoPkg(sh, "v.io/x/ref/cmd/principal") |
| // Test an initial seekblessings call. |
| seekBlessings(t, sh, principal, httpAddr) |
| // Test that a subsequent call succeeds with the same |
| // credentials. This means that the blessings and principal from the |
| // first call works correctly. |
| // TODO(ashankar): Does anyone recall what was the intent here? Running |
| // the tool twice doesn't seem to help? |
| seekBlessings(t, sh, principal, httpAddr) |
| |
| // Check stats: Since not blessings were issued over HTTP right now, the value should be 0. |
| if got, _ := readCounter(t, sh.ForkContext("u"), v23Addr, "__debug/stats/http/blessings/root:o"); got != 0 { |
| t.Errorf("Got %d, want 0 for the count of blessings issued over HTTP", got) |
| } |
| testOauthHandler(t, httpAddr) |
| if got, err := readCounter(t, sh.ForkContext("u"), v23Addr, "__debug/stats/http/blessings/root:o"); got != 1 || err != nil { |
| t.Errorf("Got (%d, %v), want (1, <nil>) for the count of blessings issued over HTTP", got, err) |
| } |
| } |
| |
| func TestMain(m *testing.M) { |
| v23test.TestMain(m) |
| } |