@@ -15,14 +15,18 @@ import (
15
15
"time"
16
16
17
17
"github.com/coreos/go-oidc/v3/oidc"
18
- "github.com/golang-jwt/jwt/v4"
18
+ "github.com/go-jose/go-jose/v4"
19
+ "github.com/go-jose/go-jose/v4/jwt"
19
20
"github.com/google/go-github/v43/github"
20
21
"github.com/google/uuid"
21
22
"github.com/moby/moby/pkg/namesgenerator"
22
23
"golang.org/x/oauth2"
23
24
"golang.org/x/xerrors"
24
25
25
26
"cdr.dev/slog"
27
+ "github.com/coder/coder/v2/coderd/cryptokeys"
28
+ "github.com/coder/coder/v2/coderd/idpsync"
29
+ "github.com/coder/coder/v2/coderd/jwtutils"
26
30
27
31
"github.com/coder/coder/v2/coderd/apikey"
28
32
"github.com/coder/coder/v2/coderd/audit"
@@ -49,7 +53,7 @@ const (
49
53
)
50
54
51
55
type OAuthConvertStateClaims struct {
52
- jwt.RegisteredClaims
56
+ jwt.Claims
53
57
54
58
UserID uuid.UUID `json:"user_id"`
55
59
State string `json:"state"`
@@ -149,11 +153,11 @@ func (api *API) postConvertLoginType(rw http.ResponseWriter, r *http.Request) {
149
153
// Eg: Developers with more than 1 deployment.
150
154
now := time .Now ()
151
155
claims := & OAuthConvertStateClaims {
152
- RegisteredClaims : jwt.RegisteredClaims {
156
+ Claims : jwt.Claims {
153
157
Issuer : api .DeploymentID ,
154
158
Subject : stateString ,
155
159
Audience : []string {user .ID .String ()},
156
- ExpiresAt : jwt .NewNumericDate (now .Add (time .Minute * 5 )),
160
+ Expiry : jwt .NewNumericDate (now .Add (time .Minute * 5 )),
157
161
NotBefore : jwt .NewNumericDate (now .Add (time .Second * - 1 )),
158
162
IssuedAt : jwt .NewNumericDate (now ),
159
163
ID : uuid .NewString (),
@@ -164,9 +168,7 @@ func (api *API) postConvertLoginType(rw http.ResponseWriter, r *http.Request) {
164
168
ToLoginType : req .ToType ,
165
169
}
166
170
167
- token := jwt .NewWithClaims (jwt .SigningMethodHS512 , claims )
168
- // Key must be a byte slice, not an array. So make sure to include the [:]
169
- tokenString , err := token .SignedString (api .OAuthSigningKey [:])
171
+ token , err := jwtutils .Sign (dbauthz .AsKeyRotator (ctx ), api .oauthConvertKeycache , claims )
170
172
if err != nil {
171
173
httpapi .Write (ctx , rw , http .StatusInternalServerError , codersdk.Response {
172
174
Message : "Internal error signing state jwt." ,
@@ -176,8 +178,8 @@ func (api *API) postConvertLoginType(rw http.ResponseWriter, r *http.Request) {
176
178
}
177
179
178
180
aReq .New = database.AuditOAuthConvertState {
179
- CreatedAt : claims .IssuedAt .Time ,
180
- ExpiresAt : claims .ExpiresAt .Time ,
181
+ CreatedAt : claims .IssuedAt .Time () ,
182
+ ExpiresAt : claims .Expiry .Time () ,
181
183
FromLoginType : database .LoginType (claims .FromLoginType ),
182
184
ToLoginType : database .LoginType (claims .ToLoginType ),
183
185
UserID : claims .UserID ,
@@ -186,8 +188,8 @@ func (api *API) postConvertLoginType(rw http.ResponseWriter, r *http.Request) {
186
188
http .SetCookie (rw , & http.Cookie {
187
189
Name : OAuthConvertCookieValue ,
188
190
Path : "/" ,
189
- Value : tokenString ,
190
- Expires : claims .ExpiresAt .Time ,
191
+ Value : token ,
192
+ Expires : claims .Expiry .Time () ,
191
193
Secure : api .SecureAuthCookie ,
192
194
HttpOnly : true ,
193
195
// Must be SameSite to work on the redirected auth flow from the
@@ -196,7 +198,7 @@ func (api *API) postConvertLoginType(rw http.ResponseWriter, r *http.Request) {
196
198
})
197
199
httpapi .Write (ctx , rw , http .StatusCreated , codersdk.OAuthConversionResponse {
198
200
StateString : stateString ,
199
- ExpiresAt : claims .ExpiresAt .Time ,
201
+ ExpiresAt : claims .Expiry .Time () ,
200
202
ToType : claims .ToLoginType ,
201
203
UserID : claims .UserID ,
202
204
})
@@ -1675,10 +1677,8 @@ func (api *API) convertUserToOauth(ctx context.Context, r *http.Request, db data
1675
1677
}
1676
1678
}
1677
1679
var claims OAuthConvertStateClaims
1678
- token , err := jwt .ParseWithClaims (jwtCookie .Value , & claims , func (_ * jwt.Token ) (interface {}, error ) {
1679
- return api .OAuthSigningKey [:], nil
1680
- })
1681
- if xerrors .Is (err , jwt .ErrSignatureInvalid ) || ! token .Valid {
1680
+ err = jwtutils .Verify (dbauthz .AsKeyRotator (ctx ), api .oauthConvertKeycache , jwtCookie .Value , & claims )
1681
+ if xerrors .Is (err , cryptokeys .ErrKeyNotFound ) || xerrors .Is (err , cryptokeys .ErrKeyInvalid ) || xerrors .Is (err , jose .ErrCryptoFailure ) {
1682
1682
// These errors are probably because the user is mixing 2 coder deployments.
1683
1683
return database.User {}, idpsync.HTTPError {
1684
1684
Code : http .StatusBadRequest ,
@@ -1707,7 +1707,7 @@ func (api *API) convertUserToOauth(ctx context.Context, r *http.Request, db data
1707
1707
oauthConvertAudit .UserID = claims .UserID
1708
1708
oauthConvertAudit .Old = user
1709
1709
1710
- if claims .RegisteredClaims . Issuer != api .DeploymentID {
1710
+ if claims .Issuer != api .DeploymentID {
1711
1711
return database.User {}, idpsync.HTTPError {
1712
1712
Code : http .StatusForbidden ,
1713
1713
Msg : "Request to convert login type failed. Issuer mismatch. Found a cookie from another coder deployment, please try again." ,
0 commit comments