go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/openid/gcevm_test.go (about) 1 // Copyright 2022 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package openid 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 "go.chromium.org/luci/common/clock" 23 "go.chromium.org/luci/common/clock/testclock" 24 25 "go.chromium.org/luci/server/auth" 26 "go.chromium.org/luci/server/auth/authtest" 27 "go.chromium.org/luci/server/auth/signing/signingtest" 28 29 . "github.com/smartystreets/goconvey/convey" 30 . "go.chromium.org/luci/common/testing/assertions" 31 ) 32 33 func TestGoogleComputeAuthMethod(t *testing.T) { 34 t.Parallel() 35 36 ctx := context.Background() 37 ctx, _ = testclock.UseTime(ctx, time.Unix(1442540000, 0)) 38 39 signer := signingtest.NewSigner(nil) 40 certs, _ := signer.Certificates(ctx) 41 keyID := signer.KeyNameForTest() 42 43 mintVMToken := func(tok IDToken) string { 44 return idTokenForTest(ctx, &tok, keyID, signer) 45 } 46 47 const fakeHost = "fake-host.example.com" 48 49 method := &GoogleComputeAuthMethod{ 50 Header: "X-Token-Header", 51 AudienceCheck: AudienceMatchesHost, 52 certs: certs, 53 } 54 call := func(authHeader string) (*auth.User, error) { 55 req := authtest.NewFakeRequestMetadata() 56 req.FakeHost = fakeHost 57 req.FakeHeader.Set("X-Token-Header", authHeader) 58 u, _, err := method.Authenticate(ctx, req) 59 return u, err 60 } 61 62 Convey("Skipped if no header", t, func() { 63 user, err := call("") 64 So(err, ShouldBeNil) 65 So(user, ShouldBeNil) 66 }) 67 68 Convey("Valid token", t, func() { 69 tok := IDToken{ 70 Iss: "https://accounts.google.com", 71 Sub: "example@example.gserviceaccount.com", 72 Email: "example@example.gserviceaccount.com", 73 EmailVerified: true, 74 Aud: "https://" + fakeHost, 75 Iat: clock.Now(ctx).Unix(), 76 Exp: clock.Now(ctx).Add(time.Hour).Unix(), 77 } 78 tok.Google.ComputeEngine.ProjectID = "example.com:project-id" 79 tok.Google.ComputeEngine.Zone = "zone-id" 80 tok.Google.ComputeEngine.InstanceName = "instance-id" 81 82 user, err := call(mintVMToken(tok)) 83 So(err, ShouldBeNil) 84 So(user, ShouldResemble, &auth.User{ 85 Identity: "bot:instance-id@gce.project-id.example.com", 86 Extra: &GoogleComputeTokenInfo{ 87 Audience: "https://" + fakeHost, 88 ServiceAccount: "example@example.gserviceaccount.com", 89 Instance: "instance-id", 90 Zone: "zone-id", 91 Project: "example.com:project-id", 92 }, 93 }) 94 }) 95 96 Convey("No GCE info", t, func() { 97 tok := IDToken{ 98 Iss: "https://accounts.google.com", 99 Sub: "example@example.gserviceaccount.com", 100 Email: "example@example.gserviceaccount.com", 101 EmailVerified: true, 102 Aud: "https://" + fakeHost, 103 Iat: clock.Now(ctx).Unix(), 104 Exp: clock.Now(ctx).Add(time.Hour).Unix(), 105 } 106 107 _, err := call(mintVMToken(tok)) 108 So(err, ShouldErrLike, "no google.compute_engine in the GCE VM token") 109 }) 110 111 Convey("Bad audience info", t, func() { 112 tok := IDToken{ 113 Iss: "https://accounts.google.com", 114 Sub: "example@example.gserviceaccount.com", 115 Email: "example@example.gserviceaccount.com", 116 EmailVerified: true, 117 Aud: "https://WRONG", 118 Iat: clock.Now(ctx).Unix(), 119 Exp: clock.Now(ctx).Add(time.Hour).Unix(), 120 } 121 tok.Google.ComputeEngine.ProjectID = "example.com:project-id" 122 tok.Google.ComputeEngine.Zone = "zone-id" 123 tok.Google.ComputeEngine.InstanceName = "instance-id" 124 125 _, err := call(mintVMToken(tok)) 126 So(err, ShouldEqual, auth.ErrBadAudience) 127 }) 128 }