go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/tokenserver/appengine/impl/utils/tokensigning/inspector_test.go (about) 1 // Copyright 2017 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 tokensigning 16 17 import ( 18 "context" 19 "encoding/base64" 20 "testing" 21 "time" 22 23 "google.golang.org/protobuf/proto" 24 25 "go.chromium.org/luci/common/clock" 26 "go.chromium.org/luci/common/clock/testclock" 27 "go.chromium.org/luci/server/auth/delegation/messages" 28 "go.chromium.org/luci/server/auth/signing" 29 "go.chromium.org/luci/server/auth/signing/signingtest" 30 31 . "github.com/smartystreets/goconvey/convey" 32 . "go.chromium.org/luci/common/testing/assertions" 33 ) 34 35 func TestInspectToken(t *testing.T) { 36 t.Parallel() 37 38 ctx := context.Background() 39 ctx, tc := testclock.UseTime(ctx, testclock.TestTimeUTC) 40 41 signer := signingtest.NewSigner(&signing.ServiceInfo{ 42 ServiceAccountName: "service@example.com", 43 }) 44 inspector := inspectorForTest(signer, "") 45 46 original := &messages.Subtoken{ 47 DelegatedIdentity: "user:delegated@example.com", 48 RequestorIdentity: "user:requestor@example.com", 49 CreationTime: clock.Now(ctx).Unix(), 50 ValidityDuration: 3600, 51 Audience: []string{"*"}, 52 Services: []string{"*"}, 53 } 54 good, _ := signerForTest(signer, "").SignToken(ctx, original) 55 56 Convey("Happy path", t, func() { 57 ins, err := inspector.InspectToken(ctx, good) 58 So(err, ShouldBeNil) 59 So(ins.Signed, ShouldBeTrue) 60 So(ins.NonExpired, ShouldBeTrue) 61 So(ins.InvalidityReason, ShouldEqual, "") 62 So(ins.Envelope, ShouldHaveSameTypeAs, &messages.DelegationToken{}) 63 So(ins.Body, ShouldResembleProto, original) 64 }) 65 66 Convey("Not base64", t, func() { 67 ins, err := inspector.InspectToken(ctx, "@@@@@@@@@@@@@") 68 So(err, ShouldBeNil) 69 So(ins, ShouldResemble, &Inspection{ 70 InvalidityReason: "not base64 - illegal base64 data at input byte 0", 71 }) 72 }) 73 74 Convey("Not valid envelope proto", t, func() { 75 ins, err := inspector.InspectToken(ctx, "zzzz") 76 So(err, ShouldBeNil) 77 So(ins.InvalidityReason, ShouldStartWith, "can't unmarshal the envelope - proto") 78 }) 79 80 Convey("Bad signature", t, func() { 81 env, _, _ := deserializeForTest(ctx, good, signer) 82 env.Pkcs1Sha256Sig = []byte("lalala") 83 blob, _ := proto.Marshal(env) 84 tok := base64.RawURLEncoding.EncodeToString(blob) 85 86 ins, err := inspector.InspectToken(ctx, tok) 87 So(err, ShouldBeNil) 88 So(ins.Signed, ShouldBeFalse) 89 So(ins.NonExpired, ShouldBeTrue) 90 So(ins.InvalidityReason, ShouldEqual, "bad signature - crypto/rsa: verification error") 91 So(ins.Envelope, ShouldHaveSameTypeAs, &messages.DelegationToken{}) 92 So(ins.Body, ShouldResembleProto, original) // recovered the token body nonetheless 93 }) 94 95 Convey("Wrong SigningContext", t, func() { 96 inspectorWithCtx := inspectorForTest(signer, "Some context") 97 98 // Symptoms are same as in "Bad signature". 99 ins, err := inspectorWithCtx.InspectToken(ctx, good) 100 So(err, ShouldBeNil) 101 So(ins.Signed, ShouldBeFalse) 102 So(ins.NonExpired, ShouldBeTrue) 103 So(ins.InvalidityReason, ShouldEqual, "bad signature - crypto/rsa: verification error") 104 So(ins.Envelope, ShouldHaveSameTypeAs, &messages.DelegationToken{}) 105 So(ins.Body, ShouldResembleProto, original) // recovered the token body nonetheless 106 }) 107 108 Convey("Expired", t, func() { 109 tc.Add(2 * time.Hour) 110 111 ins, err := inspector.InspectToken(ctx, good) 112 So(err, ShouldBeNil) 113 So(ins.Signed, ShouldBeTrue) 114 So(ins.NonExpired, ShouldBeFalse) 115 So(ins.InvalidityReason, ShouldEqual, "expired") 116 So(ins.Envelope, ShouldHaveSameTypeAs, &messages.DelegationToken{}) 117 So(ins.Body, ShouldResembleProto, original) 118 }) 119 } 120 121 func inspectorForTest(certs CertificatesSupplier, signingCtx string) *Inspector { 122 return &Inspector{ 123 Certificates: certs, 124 SigningContext: signingCtx, 125 Envelope: func() proto.Message { return &messages.DelegationToken{} }, 126 Body: func() proto.Message { return &messages.Subtoken{} }, 127 Unwrap: func(e proto.Message) Unwrapped { 128 env := e.(*messages.DelegationToken) 129 return Unwrapped{ 130 Body: env.SerializedSubtoken, 131 RsaSHA256Sig: env.Pkcs1Sha256Sig, 132 KeyID: env.SigningKeyId, 133 } 134 }, 135 Lifespan: func(b proto.Message) Lifespan { 136 body := b.(*messages.Subtoken) 137 return Lifespan{ 138 NotBefore: time.Unix(body.CreationTime, 0), 139 NotAfter: time.Unix(body.CreationTime+int64(body.ValidityDuration), 0), 140 } 141 }, 142 } 143 }