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  }