From 0374ea2c795be1e99caa8fb310897ceaed59966a Mon Sep 17 00:00:00 2001 From: albertony <12441419+albertony@users.noreply.github.com> Date: Sat, 25 Jun 2022 15:33:12 +0200 Subject: [PATCH] Use jwt-go (golang-jwt) instead of deprecated jws (x/oauth2/jws) golang.org/x/oauth2/jws is deprecated: this package is not intended for public use and might be removed in the future. It exists for internal use only. Please switch to another JWS package or copy this package into your own source tree. github.com/golang-jwt/jwt/v4 seems to be a good alternative, and was already an implicit dependency. --- .golangci.yml | 5 ----- backend/box/box.go | 38 +++++++++++++++++++------------------- go.mod | 2 +- lib/jwtutil/jwtutil.go | 14 +++++++++----- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index c138617a8..c241475ce 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -33,11 +33,6 @@ issues: - staticcheck text: 'SA1019: "github.com/rclone/rclone/cmd/serve/httplib" is deprecated' - # TODO: Remove if/when this is fixed by merging PR #6277. - - linters: - - staticcheck - text: 'SA1019: "golang.org/x/oauth2/jws" is deprecated' - run: # timeout for analysis, e.g. 30s, 5m, default is 1m timeout: 10m diff --git a/backend/box/box.go b/backend/box/box.go index e0cfbed07..474443d39 100644 --- a/backend/box/box.go +++ b/backend/box/box.go @@ -27,6 +27,7 @@ import ( "sync/atomic" "time" + "github.com/golang-jwt/jwt/v4" "github.com/rclone/rclone/backend/box/api" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/config" @@ -45,7 +46,6 @@ import ( "github.com/rclone/rclone/lib/rest" "github.com/youmark/pkcs8" "golang.org/x/oauth2" - "golang.org/x/oauth2/jws" ) const ( @@ -76,6 +76,11 @@ var ( } ) +type boxCustomClaims struct { + jwt.RegisteredClaims + BoxSubType string `json:"box_sub_type,omitempty"` +} + // Register with Fs func init() { fs.Register(&fs.RegInfo{ @@ -178,7 +183,7 @@ func refreshJWTToken(ctx context.Context, jsonFile string, boxSubType string, na signingHeaders := getSigningHeaders(boxConfig) queryParams := getQueryParams(boxConfig) client := fshttp.NewClient(ctx) - err = jwtutil.Config("box", name, claims, signingHeaders, queryParams, privateKey, m, client) + err = jwtutil.Config("box", name, tokenURL, *claims, signingHeaders, queryParams, privateKey, m, client) return err } @@ -194,34 +199,29 @@ func getBoxConfig(configFile string) (boxConfig *api.ConfigJSON, err error) { return boxConfig, nil } -func getClaims(boxConfig *api.ConfigJSON, boxSubType string) (claims *jws.ClaimSet, err error) { +func getClaims(boxConfig *api.ConfigJSON, boxSubType string) (claims *boxCustomClaims, err error) { val, err := jwtutil.RandomHex(20) if err != nil { return nil, fmt.Errorf("box: failed to generate random string for jti: %w", err) } - claims = &jws.ClaimSet{ - Iss: boxConfig.BoxAppSettings.ClientID, - Sub: boxConfig.EnterpriseID, - Aud: tokenURL, - Exp: time.Now().Add(time.Second * 45).Unix(), - PrivateClaims: map[string]interface{}{ - "box_sub_type": boxSubType, - "aud": tokenURL, - "jti": val, + claims = &boxCustomClaims{ + RegisteredClaims: jwt.RegisteredClaims{ + ID: val, + Issuer: boxConfig.BoxAppSettings.ClientID, + Subject: boxConfig.EnterpriseID, + Audience: jwt.ClaimStrings{tokenURL}, + ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Second * 45)), }, + BoxSubType: boxSubType, } - return claims, nil } -func getSigningHeaders(boxConfig *api.ConfigJSON) *jws.Header { - signingHeaders := &jws.Header{ - Algorithm: "RS256", - Typ: "JWT", - KeyID: boxConfig.BoxAppSettings.AppAuth.PublicKeyID, +func getSigningHeaders(boxConfig *api.ConfigJSON) map[string]interface{} { + signingHeaders := map[string]interface{}{ + "kid": boxConfig.BoxAppSettings.AppAuth.PublicKeyID, } - return signingHeaders } diff --git a/go.mod b/go.mod index ddc395619..7cad6cb8a 100644 --- a/go.mod +++ b/go.mod @@ -141,7 +141,7 @@ require ( require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/pkg/xattr v0.4.9 diff --git a/lib/jwtutil/jwtutil.go b/lib/jwtutil/jwtutil.go index da3b0e7cb..e5f0dbd8e 100644 --- a/lib/jwtutil/jwtutil.go +++ b/lib/jwtutil/jwtutil.go @@ -14,12 +14,12 @@ import ( "strings" "time" + "github.com/golang-jwt/jwt/v4" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/lib/oauthutil" "golang.org/x/oauth2" - "golang.org/x/oauth2/jws" ) // RandomHex creates a random string of the given length @@ -32,12 +32,16 @@ func RandomHex(n int) (string, error) { } // Config configures rclone using JWT -func Config(id, name string, claims *jws.ClaimSet, header *jws.Header, queryParams map[string]string, privateKey *rsa.PrivateKey, m configmap.Mapper, client *http.Client) (err error) { - payload, err := jws.Encode(header, claims, privateKey) +func Config(id, name, url string, claims jwt.Claims, headerParams map[string]interface{}, queryParams map[string]string, privateKey *rsa.PrivateKey, m configmap.Mapper, client *http.Client) (err error) { + jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + for key, value := range headerParams { + jwtToken.Header[key] = value + } + payload, err := jwtToken.SignedString(privateKey) if err != nil { return fmt.Errorf("jwtutil: failed to encode payload: %w", err) } - req, err := http.NewRequest("POST", claims.Aud, nil) + req, err := http.NewRequest("POST", url, nil) if err != nil { return fmt.Errorf("jwtutil: failed to create new request: %w", err) } @@ -49,7 +53,7 @@ func Config(id, name string, claims *jws.ClaimSet, header *jws.Header, queryPara } queryString := q.Encode() - req, err = http.NewRequest("POST", claims.Aud, bytes.NewBuffer([]byte(queryString))) + req, err = http.NewRequest("POST", url, bytes.NewBuffer([]byte(queryString))) if err != nil { return fmt.Errorf("jwtutil: failed to create new request: %w", err) }