go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/tokenserver/appengine/impl/utils/tokensigning/signer_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 22 "google.golang.org/protobuf/proto" 23 24 "go.chromium.org/luci/server/auth/delegation/messages" 25 "go.chromium.org/luci/server/auth/signing" 26 "go.chromium.org/luci/server/auth/signing/signingtest" 27 28 . "github.com/smartystreets/goconvey/convey" 29 . "go.chromium.org/luci/common/testing/assertions" 30 ) 31 32 func TestSignToken(t *testing.T) { 33 t.Parallel() 34 35 ctx := context.Background() 36 original := &messages.Subtoken{ 37 DelegatedIdentity: "user:delegated@example.com", 38 RequestorIdentity: "user:requestor@example.com", 39 CreationTime: 1477624966, 40 ValidityDuration: 3600, 41 Audience: []string{"*"}, 42 Services: []string{"*"}, 43 } 44 signer := signingtest.NewSigner(&signing.ServiceInfo{ 45 ServiceAccountName: "service@example.com", 46 }) 47 48 Convey("Works", t, func() { 49 tok, err := signerForTest(signer, "").SignToken(ctx, original) 50 So(err, ShouldBeNil) 51 So(tok, ShouldHaveLength, 276) 52 53 envelope, back, err := deserializeForTest(ctx, tok, signer) 54 So(err, ShouldBeNil) 55 So(back, ShouldResembleProto, original) 56 57 envelope.Pkcs1Sha256Sig = nil 58 envelope.SerializedSubtoken = nil 59 So(envelope, ShouldResembleProto, &messages.DelegationToken{ 60 SignerId: "user:service@example.com", 61 SigningKeyId: signer.KeyNameForTest(), 62 }) 63 }) 64 65 Convey("SigningContext works", t, func() { 66 const contextString = "Some context string" 67 68 signer := &capturingSigner{signer, nil} 69 tok, err := signerForTest(signer, contextString).SignToken(ctx, original) 70 So(err, ShouldBeNil) 71 So(tok, ShouldHaveLength, 276) 72 73 ctxPart := signer.blobs[0][:len(contextString)+1] 74 So(string(ctxPart), ShouldEqual, contextString+"\x00") 75 76 msgPart := signer.blobs[0][len(contextString)+1:] 77 msg := &messages.Subtoken{} 78 So(proto.Unmarshal(msgPart, msg), ShouldBeNil) 79 So(msg, ShouldResembleProto, original) 80 }) 81 } 82 83 type capturingSigner struct { 84 signing.Signer 85 86 blobs [][]byte 87 } 88 89 func (s *capturingSigner) SignBytes(c context.Context, blob []byte) (string, []byte, error) { 90 s.blobs = append(s.blobs, blob) 91 return s.Signer.SignBytes(c, blob) 92 } 93 94 func signerForTest(signer signing.Signer, signingCtx string) *Signer { 95 return &Signer{ 96 Signer: signer, 97 SigningContext: signingCtx, 98 Wrap: func(t *Unwrapped) proto.Message { 99 return &messages.DelegationToken{ 100 SignerId: "user:" + t.SignerID, 101 SigningKeyId: t.KeyID, 102 SerializedSubtoken: t.Body, 103 Pkcs1Sha256Sig: t.RsaSHA256Sig, 104 } 105 }, 106 } 107 } 108 109 func deserializeForTest(c context.Context, tok string, signer signing.Signer) (*messages.DelegationToken, *messages.Subtoken, error) { 110 blob, err := base64.RawURLEncoding.DecodeString(tok) 111 if err != nil { 112 return nil, nil, err 113 } 114 env := &messages.DelegationToken{} 115 if err = proto.Unmarshal(blob, env); err != nil { 116 return nil, nil, err 117 } 118 certs, err := signer.Certificates(c) 119 if err != nil { 120 return nil, nil, err 121 } 122 if err = certs.CheckSignature(env.SigningKeyId, env.SerializedSubtoken, env.Pkcs1Sha256Sig); err != nil { 123 return nil, nil, err 124 } 125 subtoken := &messages.Subtoken{} 126 if err = proto.Unmarshal(env.SerializedSubtoken, subtoken); err != nil { 127 return nil, nil, err 128 } 129 return env, subtoken, nil 130 }