token.go raw

   1  package logincreds
   2  
   3  import (
   4  	"crypto/sha256"
   5  	"encoding/hex"
   6  	"errors"
   7  	"fmt"
   8  	"path/filepath"
   9  	"strings"
  10  	"time"
  11  
  12  	"github.com/aws/aws-sdk-go-v2/aws"
  13  	"github.com/aws/aws-sdk-go-v2/internal/sdk"
  14  	"github.com/aws/aws-sdk-go-v2/internal/shareddefaults"
  15  	"github.com/aws/aws-sdk-go-v2/service/signin"
  16  )
  17  
  18  var userHomeDir = shareddefaults.UserHomeDir
  19  
  20  // StandardCachedTokenFilepath returns the filepath for the cached login token
  21  // file. Key that will be used to compute a SHA256 value that is hex encoded.
  22  //
  23  // An overriden root dir can be provided, if not set the path defaults to
  24  // ~/.aws/sso/cache.
  25  func StandardCachedTokenFilepath(session, dir string) (string, error) {
  26  	session = strings.TrimSpace(session)
  27  
  28  	if len(dir) == 0 {
  29  		dir = userHomeDir()
  30  		if len(dir) == 0 {
  31  			return "", errors.New("user home dir is blank")
  32  		}
  33  		dir = filepath.Join(dir, ".aws", "login", "cache")
  34  	}
  35  
  36  	h := sha256.New()
  37  	h.Write([]byte(session))
  38  
  39  	filename := strings.ToLower(hex.EncodeToString(h.Sum(nil))) + ".json"
  40  	return filepath.Join(dir, filename), nil
  41  }
  42  
  43  // contents of the token as they appear on disk
  44  type loginToken struct {
  45  	AccessToken   *loginTokenAccessToken `json:"accessToken"`
  46  	TokenType     string                 `json:"tokenType"`
  47  	RefreshToken  string                 `json:"refreshToken"`
  48  	IdentityToken string                 `json:"identityToken"`
  49  	ClientID      string                 `json:"clientId"`
  50  	DPOPKey       string                 `json:"dpopKey"`
  51  }
  52  
  53  type loginTokenAccessToken struct {
  54  	AccessKeyID     string    `json:"accessKeyId"`
  55  	SecretAccessKey string    `json:"secretAccessKey"`
  56  	SessionToken    string    `json:"sessionToken"`
  57  	AccountID       string    `json:"accountId"`
  58  	ExpiresAt       time.Time `json:"expiresAt"`
  59  }
  60  
  61  func (t *loginToken) Validate() error {
  62  	if t.AccessToken == nil {
  63  		return fmt.Errorf("missing accessToken")
  64  	}
  65  	if t.AccessToken.AccessKeyID == "" {
  66  		return fmt.Errorf("missing accessToken.accessKeyId")
  67  	}
  68  	if t.AccessToken.SecretAccessKey == "" {
  69  		return fmt.Errorf("missing accessToken.secretAccessKey")
  70  	}
  71  	if t.AccessToken.SessionToken == "" {
  72  		return fmt.Errorf("missing accessToken.sessionToken")
  73  	}
  74  	if t.AccessToken.AccountID == "" {
  75  		return fmt.Errorf("missing accessToken.accountId")
  76  	}
  77  	if t.AccessToken.ExpiresAt.IsZero() {
  78  		return fmt.Errorf("missing accessToken.expiresAt")
  79  	}
  80  	if t.ClientID == "" {
  81  		return fmt.Errorf("missing clientId")
  82  	}
  83  	if t.RefreshToken == "" {
  84  		return fmt.Errorf("missing refreshToken")
  85  	}
  86  	if t.DPOPKey == "" {
  87  		return fmt.Errorf("missing dpopKey")
  88  	}
  89  	return nil
  90  }
  91  
  92  func (t *loginToken) Credentials() aws.Credentials {
  93  	return aws.Credentials{
  94  		AccessKeyID:     t.AccessToken.AccessKeyID,
  95  		SecretAccessKey: t.AccessToken.SecretAccessKey,
  96  		SessionToken:    t.AccessToken.SessionToken,
  97  		Source:          ProviderName,
  98  		CanExpire:       true,
  99  		Expires:         t.AccessToken.ExpiresAt,
 100  		AccountID:       t.AccessToken.AccountID,
 101  	}
 102  }
 103  
 104  func (t *loginToken) Update(out *signin.CreateOAuth2TokenOutput) {
 105  	t.AccessToken.AccessKeyID = *out.TokenOutput.AccessToken.AccessKeyId
 106  	t.AccessToken.SecretAccessKey = *out.TokenOutput.AccessToken.SecretAccessKey
 107  	t.AccessToken.SessionToken = *out.TokenOutput.AccessToken.SessionToken
 108  	t.AccessToken.ExpiresAt = sdk.NowTime().Add(time.Duration(*out.TokenOutput.ExpiresIn) * time.Second)
 109  	t.RefreshToken = *out.TokenOutput.RefreshToken
 110  }
 111