github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/lib/jwtutil/jwtutil.go (about) 1 package jwtutil 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "crypto/rsa" 7 "encoding/hex" 8 "encoding/json" 9 "net/http" 10 "time" 11 12 "github.com/pkg/errors" 13 "github.com/rclone/rclone/fs/config/configmap" 14 "github.com/rclone/rclone/lib/oauthutil" 15 16 "golang.org/x/oauth2" 17 "golang.org/x/oauth2/jws" 18 ) 19 20 // RandomHex creates a random string of the given length 21 func RandomHex(n int) (string, error) { 22 bytes := make([]byte, n) 23 if _, err := rand.Read(bytes); err != nil { 24 return "", err 25 } 26 return hex.EncodeToString(bytes), nil 27 } 28 29 // Config configures rclone using JWT 30 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) { 31 payload, err := jws.Encode(header, claims, privateKey) 32 if err != nil { 33 return errors.Wrap(err, "jwtutil: failed to encode payload") 34 } 35 req, err := http.NewRequest("POST", claims.Aud, nil) 36 if err != nil { 37 return errors.Wrap(err, "jwtutil: failed to create new request") 38 } 39 q := req.URL.Query() 40 q.Add("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer") 41 q.Add("assertion", payload) 42 for key, value := range queryParams { 43 q.Add(key, value) 44 } 45 queryString := q.Encode() 46 47 req, err = http.NewRequest("POST", claims.Aud, bytes.NewBuffer([]byte(queryString))) 48 if err != nil { 49 return errors.Wrap(err, "jwtutil: failed to create new request") 50 } 51 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 52 53 resp, err := client.Do(req) 54 if err != nil { 55 return errors.Wrap(err, "jwtutil: failed making auth request") 56 } 57 if resp.StatusCode != 200 { 58 return errors.Wrap(err, "jwtutil: failed making auth request") 59 } 60 defer func() { 61 deferedErr := resp.Body.Close() 62 if deferedErr != nil { 63 err = errors.Wrap(err, "jwtutil: failed to close resp.Body") 64 } 65 }() 66 67 result := &response{} 68 err = json.NewDecoder(resp.Body).Decode(result) 69 if err != nil || result.AccessToken == "" { 70 return errors.Wrap(err, "jwtutil: failed to get token") 71 } 72 token := &oauth2.Token{ 73 AccessToken: result.AccessToken, 74 TokenType: result.TokenType, 75 } 76 e := result.ExpiresIn 77 if e != 0 { 78 token.Expiry = time.Now().Add(time.Duration(e) * time.Second) 79 } 80 return oauthutil.PutToken(name, m, token, true) 81 } 82 83 type response struct { 84 AccessToken string `json:"access_token"` 85 TokenType string `json:"token_type"` 86 ExpiresIn int `json:"expires_in"` 87 }