/
signintest.go
109 lines (94 loc) · 3.52 KB
/
signintest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Package signintest provides shared test code for testing signing in with Google accounts.
package signintest
import (
"net/http"
"time"
"github.com/evanj/googlesignin"
"github.com/evanj/googlesignin/jwkkeys"
jose "github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/jwt"
)
// ClientID is a fake OAuth client ID to be used with googlesignin.Authenticator in tests.
const ClientID = "insecure_test_client_id"
// generated with gopkg.in/square/go-jose.v2/jwk-keygen
const insecurePrivateKey = `{"use":"sig","kty":"EC","crv":"P-256","alg":"ES256","x":"-YdsjSFTEqKWQn7ZjThmkhuDDSasgh3ACWmgFKlo_7w","y":"LejdIY1pMKjXRlf3lStziDpQGPOynW49uF_Jlymcaxg","d":"xK_dS2q20mgRrYFVlwcJHOlNWmVxneJyzWFO-CGZ0BE"}`
const testKeyID = "testkeyid"
// RequestAuthenticator makes requests authenticated for test purposes.
type RequestAuthenticator struct {
authenticator *googlesignin.Authenticator
privateKey jose.JSONWebKey
}
// InsecureMakeAuthenticated makes request an authenticated request, using the insecure test keys.
// It will then be accepted by handlers that use MustGetEmail
func (r *RequestAuthenticator) InsecureMakeAuthenticated(
request *http.Request, email string,
) *http.Request {
idToken := InsecureToken(ClientID, jwkkeys.GoogleIssuers[0], email, r.authenticator.HostedDomain)
return googlesignin.InsecureMakeAuthenticated(request, idToken)
}
type staticKeySet struct {
key jose.JSONWebKey
}
func (s *staticKeySet) Get(keyID string) (*jose.JSONWebKey, error) {
return &s.key, nil
}
// InsecureTestAuthenticator modifies the Authenticator accept insecure test keys, returning a
// RequestAuthenticator that can be use to make authorized *http.Request objects. You must use
// signintest.ClientID as the OAuth client ID when creating authenticator.
func InsecureTestAuthenticator(authenticator *googlesignin.Authenticator) *RequestAuthenticator {
r := &RequestAuthenticator{authenticator, jose.JSONWebKey{}}
r.loadJSONWebKey(insecurePrivateKey)
r.privateKey.KeyID = testKeyID
r.authenticator.CachedKeys = InsecureKeys()
return r
}
func (r *RequestAuthenticator) loadJSONWebKey(json string) {
err := r.privateKey.UnmarshalJSON([]byte(json))
if err != nil {
panic(err)
}
if !r.privateKey.Valid() {
panic("invalid key")
}
}
func parsePrivateKey() *jose.JSONWebKey {
privateKey := &jose.JSONWebKey{}
err := privateKey.UnmarshalJSON([]byte(insecurePrivateKey))
if err != nil {
panic(err)
}
return privateKey
}
// InsecureKeys returns a key set containing an insecure test key. Should only be used in tests.
func InsecureKeys() jwkkeys.Set {
return &staticKeySet{parsePrivateKey().Public()}
}
// InsecureToken returns a new token that is signed by a key in InsecureKeys. Should only be used
// in tests.
func InsecureToken(audience string, issuer string, email string, hostedDomain string) string {
privateKey := parsePrivateKey()
signingKey := jose.SigningKey{
Algorithm: jose.SignatureAlgorithm(privateKey.Algorithm),
Key: privateKey,
}
signer, err := jose.NewSigner(signingKey, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic(err)
}
claims := jwt.Claims{
Subject: "subject",
Audience: jwt.Audience{audience},
Issuer: issuer,
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Expiry: jwt.NewNumericDate(time.Now().Add(time.Hour)),
}
extraClaims := jwkkeys.GoogleExtraClaims{
Email: email,
HostedDomain: hostedDomain,
}
raw, err := jwt.Signed(signer).Claims(claims).Claims(extraClaims).CompactSerialize()
if err != nil {
panic(err)
}
return raw
}