Passed
Push — master ( 8b6a99...606072 )
by Tolga
01:20 queued 16s
created

oidc.*fakeOidcProvider.SignIDToken   A

Complexity

Conditions 4

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nop 1
dl 0
loc 16
rs 9.85
c 0
b 0
f 0
1
package oidc
2
3
import (
4
	"crypto/ecdsa"
5
	"crypto/elliptic"
6
	"crypto/rand"
7
	"crypto/rsa"
8
	"encoding/json"
9
	"fmt"
10
	"net"
11
	"net/http"
12
	"net/http/httptest"
13
14
	"github.com/go-jose/go-jose/v3"
15
	"github.com/golang-jwt/jwt/v4"
16
)
17
18
type fakeOidcProvider struct {
19
	issuerURL    string
20
	authPath     string
21
	tokenPath    string
22
	userInfoPath string
23
	JWKSPath     string
24
25
	algorithms         []string
26
	keyIds             map[jwt.SigningMethod]string
27
	jwks               []jose.JSONWebKey
28
	rsaPrivateKey      *rsa.PrivateKey
29
	rsaPrivateKeyForPS *rsa.PrivateKey
30
	ecdsaPrivateKey    *ecdsa.PrivateKey
31
	hmacKey            []byte
32
}
33
34
func newFakeOidcProvider(issuerURL string) (*fakeOidcProvider, error) {
35
	rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)
36
	if err != nil {
37
		return nil, err
38
	}
39
	rsaPrivateKeyForPS, err := rsa.GenerateKey(rand.Reader, 2048)
40
	if err != nil {
41
		return nil, err
42
	}
43
	ecdsaPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
44
	if err != nil {
45
		return nil, err
46
	}
47
	hmacKey := []byte("hmackeysecret")
48
49
	keyIds := map[jwt.SigningMethod]string{
50
		jwt.SigningMethodRS256: "rs256keyid",
51
	}
52
	jwks := []jose.JSONWebKey{
53
		{
54
			Key:       rsaPrivateKey.Public(),
55
			KeyID:     keyIds[jwt.SigningMethodRS256],
56
			Algorithm: "RS256",
57
			Use:       "sig",
58
		},
59
	}
60
61
	return &fakeOidcProvider{
62
		issuerURL:          issuerURL,
63
		authPath:           "/auth",
64
		tokenPath:          "/token",
65
		userInfoPath:       "/userInfo",
66
		JWKSPath:           "/jwks",
67
		algorithms:         []string{"RS256", "HS256", "ES256", "PS256"},
68
		rsaPrivateKey:      rsaPrivateKey,
69
		rsaPrivateKeyForPS: rsaPrivateKeyForPS,
70
		hmacKey:            hmacKey,
71
		jwks:               jwks,
72
		ecdsaPrivateKey:    ecdsaPrivateKey,
73
		keyIds:             keyIds,
74
	}, nil
75
}
76
77
func (s *fakeOidcProvider) ServeHTTP(w http.ResponseWriter, r *http.Request) {
78
	switch r.URL.Path {
79
	case "/.well-known/openid-configuration":
80
		s.ResponseWellKnown(w, r)
81
	case s.JWKSPath:
82
		s.ResponseJWKS(w, r)
83
	case s.authPath, s.tokenPath, s.userInfoPath:
84
		httpError(w, 404)
85
	}
86
}
87
88
type providerJSON struct {
89
	Issuer      string   `json:"issuer"`
90
	AuthURL     string   `json:"authorization_endpoint"`
91
	TokenURL    string   `json:"token_endpoint"`
92
	JWKSURL     string   `json:"jwks_uri"`
93
	UserInfoURL string   `json:"userinfo_endpoint"`
94
	Algorithms  []string `json:"id_token_signing_alg_values_supported"`
95
}
96
97
func (s *fakeOidcProvider) ResponseWellKnown(w http.ResponseWriter, r *http.Request) {
98
	jso := providerJSON{
99
		Issuer:      s.issuerURL,
100
		AuthURL:     s.issuerURL + s.authPath,
101
		TokenURL:    s.issuerURL + s.tokenPath,
102
		JWKSURL:     s.issuerURL + s.JWKSPath,
103
		UserInfoURL: s.issuerURL + s.userInfoPath,
104
		Algorithms:  s.algorithms,
105
	}
106
	httpJSON(w, jso)
107
}
108
109
func (s *fakeOidcProvider) ResponseJWKS(w http.ResponseWriter, r *http.Request) {
110
	jwks := &jose.JSONWebKeySet{
111
		Keys: s.jwks,
112
	}
113
	httpJSON(w, jwks)
114
}
115
116
func httpJSON(w http.ResponseWriter, v interface{}) {
117
	w.Header().Set("Content-Type", "application/json")
118
	e := json.NewEncoder(w)
119
	e.SetIndent("", "  ")
120
	if err := e.Encode(v); err != nil {
121
		httpError(w, http.StatusInternalServerError)
122
		return
123
	}
124
}
125
126
func httpError(w http.ResponseWriter, code int) {
127
	http.Error(w, http.StatusText(code), code)
128
}
129
130
func (s *fakeOidcProvider) SignIDToken(unsignedToken *jwt.Token) (string, error) {
131
	signedToken := ""
132
	var err error
133
134
	switch unsignedToken.Method {
135
	case jwt.SigningMethodRS256:
136
		signedToken, err = unsignedToken.SignedString(s.rsaPrivateKey)
137
	default:
138
		return "", fmt.Errorf("incorrect signing method type, supported algorithms: HS256, RS256, ES256, PS256")
139
	}
140
141
	if err != nil {
142
		return "", err
143
	}
144
145
	return signedToken, nil
146
}
147
148
func createUnsignedToken(regClaims jwt.RegisteredClaims, method jwt.SigningMethod) *jwt.Token {
149
	claims := struct {
150
		jwt.RegisteredClaims
151
	}{
152
		RegisteredClaims: regClaims,
153
	}
154
	token := jwt.NewWithClaims(method, claims)
155
	return token
156
}
157
158
func fakeHttpServer(url string, handler http.HandlerFunc) (*httptest.Server, error) {
159
	l, err := net.Listen("tcp", url)
160
	if err != nil {
161
		return nil, err
162
	}
163
	ts := httptest.NewUnstartedServer(handler)
164
	_ = ts.Listener.Close()
165
	ts.Listener = l
166
	ts.Start()
167
	return ts, nil
168
}
169