Guest User

Untitled

a guest
May 30th, 2018
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 6.04 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "errors"
  5.     "fmt"
  6.  
  7.     log "github.com/sirupsen/logrus"
  8.     "github.com/aws/aws-sdk-go/aws/awserr"
  9.     jwt "github.com/dgrijalva/jwt-go"
  10.     "github.com/lestrrat/go-jwx/jwk"
  11.  
  12.     "github.com/aws/aws-sdk-go/aws"
  13.     "github.com/aws/aws-sdk-go/aws/session"
  14.     "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
  15.     "github.com/spf13/viper"
  16. )
  17.  
  18. // Cognito represents an abstraction of the Amazon Cognito identity provider service.
  19. type Cognito struct {
  20.     cip *cognitoidentityprovider.CognitoIdentityProvider
  21. }
  22.  
  23. var userPoolID string
  24. var clientID string
  25. var jwksURL string
  26. var keySet *jwk.Set
  27.  
  28. func init() {
  29.  
  30.     log.Info("Initializing Cognito")
  31.  
  32.     log.Info("Loading configuration")
  33.     viper.SetConfigName("config") // config.toml
  34.     viper.AddConfigPath(".")      // use working directory
  35.  
  36.     if err := viper.ReadInConfig(); err != nil {
  37.         log.Errorf("error reading config file, %v", err)
  38.         return
  39.     }
  40.  
  41.     userPoolID = viper.GetString("cognito.userPoolID")
  42.     clientID = viper.GetString("cognito.clientID")
  43.     jwksURL = viper.GetString("cognito.jwksURL")
  44.  
  45.     log.Info("userPoolID: ", userPoolID)
  46.     log.Info("clientID: ", clientID)
  47.     log.Info("jwksURL: ", jwksURL)
  48.  
  49.     if err := loadKeySet(); err != nil {
  50.         log.Error("Error: ", err)
  51.     }
  52. }
  53.  
  54. // loadKeySet caches the keyset so we don't have to make a request every time
  55. // we want to verify a JWT
  56. func loadKeySet() error {
  57.     log.Info("Caching keyset")
  58.     var err error
  59.     keySet, err = jwk.FetchHTTP(jwksURL)
  60.     if err != nil {
  61.         return err
  62.     }
  63.     return nil
  64. }
  65.  
  66. // NewCognito creates a new instance of the Cognito client
  67. func NewCognito() *Cognito {
  68.  
  69.     c := &Cognito{}
  70.  
  71.     // Create Session
  72.     sess := session.Must(session.NewSession())
  73.     c.cip = cognitoidentityprovider.New(sess)
  74.  
  75.     return c
  76. }
  77.  
  78. // SignUp creates a new Cognito user in the user pool, setting its status
  79. // to CONFIRMED. Returns the authenticated user's JWT access token.
  80. func (c *Cognito) SignUp(username string, password string, email string, fullName string) (string, error) {
  81.  
  82.     log.Info("AdminCreateUser: ", username)
  83.  
  84.     // Creates user in FORCE_CHANGE_PASSWORD state
  85.     _, err := c.cip.AdminCreateUser(&cognitoidentityprovider.AdminCreateUserInput{
  86.         Username:          aws.String(username),
  87.         TemporaryPassword: aws.String(password),
  88.         UserPoolId:        aws.String(userPoolID),
  89.         UserAttributes: []*cognitoidentityprovider.AttributeType{
  90.             {
  91.                 Name:  aws.String("email_verified"),
  92.                 Value: aws.String("true"),
  93.             },
  94.             {
  95.                 Name:  aws.String("email"),
  96.                 Value: aws.String(email),
  97.             },
  98.             {
  99.                 Name:  aws.String("name"),
  100.                 Value: aws.String(fullName),
  101.             },
  102.         },
  103.     })
  104.  
  105.     if err != nil {
  106.         log.Error("Error: ", err.Error())
  107.         return "", err
  108.     }
  109.  
  110.     // Attempt login to get session value, which is used to confirm the user
  111.  
  112.     aia := &cognitoidentityprovider.AdminInitiateAuthInput{
  113.         AuthFlow: aws.String("ADMIN_NO_SRP_AUTH"),
  114.         AuthParameters: map[string]*string{
  115.             "USERNAME": aws.String(username),
  116.             "PASSWORD": aws.String(password),
  117.         },
  118.         ClientId:   aws.String(clientID),
  119.         UserPoolId: aws.String(userPoolID),
  120.     }
  121.  
  122.     log.Info("AdminInitiateAuth: ", username)
  123.     authresp, autherr := c.cip.AdminInitiateAuth(aia)
  124.  
  125.     log.Info("ChallengeName: ", aws.StringValue(authresp.ChallengeName))
  126.  
  127.     if autherr != nil {
  128.         log.Warn(autherr.Error())
  129.     }
  130.  
  131.     // Set user to CONFIRMED
  132.  
  133.     artaci := &cognitoidentityprovider.AdminRespondToAuthChallengeInput{
  134.         ChallengeName: aws.String("NEW_PASSWORD_REQUIRED"), // Required
  135.         ClientId:      aws.String(clientID),                // Required
  136.         UserPoolId:    aws.String(userPoolID),              // Required
  137.         ChallengeResponses: map[string]*string{
  138.             "USERNAME":     aws.String(username),
  139.             "NEW_PASSWORD": aws.String(password), // Required
  140.         },
  141.         Session: authresp.Session, // session value from AdminInitiateAuth
  142.     }
  143.  
  144.     log.Info("AdminRespondToAuthChallenge: ", username)
  145.     chalresp, err := c.cip.AdminRespondToAuthChallenge(artaci)
  146.  
  147.     if err != nil {
  148.         log.Error(err.Error())
  149.         return "", err.(awserr.Error).OrigErr()
  150.     }
  151.  
  152.     idToken := aws.StringValue(chalresp.AuthenticationResult.IdToken)
  153.     accessToken := aws.StringValue(chalresp.AuthenticationResult.AccessToken)
  154.  
  155.     log.Debug("ID Token: ", idToken)
  156.     log.Debug("AccessToken: ", accessToken)
  157.  
  158.     return accessToken, nil
  159. }
  160.  
  161. // SignIn authenticates a user and returns a JWT token
  162. func (c *Cognito) SignIn(username string, password string) (string, error) {
  163.  
  164.     aia := &cognitoidentityprovider.AdminInitiateAuthInput{
  165.         AuthFlow: aws.String("ADMIN_NO_SRP_AUTH"),
  166.         AuthParameters: map[string]*string{
  167.             "USERNAME": aws.String(username),
  168.             "PASSWORD": aws.String(password),
  169.         },
  170.         ClientId:   aws.String(clientID),
  171.         UserPoolId: aws.String(userPoolID),
  172.     }
  173.  
  174.     log.Info("AdminInitiateAuth: ", username)
  175.     authresp, autherr := c.cip.AdminInitiateAuth(aia)
  176.  
  177.     if autherr != nil {
  178.         log.Error(autherr.Error())
  179.         return "", autherr
  180.     }
  181.  
  182.     accessToken := aws.StringValue(authresp.AuthenticationResult.AccessToken)
  183.  
  184.     log.Debug("AccessToken: ", accessToken)
  185.  
  186.     return accessToken, nil
  187. }
  188.  
  189. // ValidateToken validates a JWT token and returns the 'sub' claim.
  190. func (c *Cognito) ValidateToken(jwtToken string) (string, error) {
  191.  
  192.     log.Debug("ValidateToken: ", jwtToken)
  193.  
  194.     token, err := jwt.Parse(jwtToken, c.getKey)
  195.     if err != nil {
  196.         return "", fmt.Errorf("Could not parse JWT: %v", err)
  197.     }
  198.  
  199.     log.Debug("JWT signature: ", token.Signature)
  200.  
  201.     if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
  202.         if claims["token_use"] != "access" {
  203.             return "", fmt.Errorf("token_use mismatch: %s", claims["token_use"])
  204.         }
  205.  
  206.         return claims["sub"].(string), nil // Valid token
  207.     }
  208.  
  209.     return "", nil // Invalid token
  210. }
  211.  
  212. // getKey returns the key for validating in ValidateToken
  213. func (c *Cognito) getKey(token *jwt.Token) (interface{}, error) {
  214.     keyID, ok := token.Header["kid"].(string)
  215.     if !ok {
  216.         return nil, errors.New("expecting JWT header to have string kid")
  217.     }
  218.  
  219.     log.Debug("kid: ", keyID)
  220.  
  221.     if key := keySet.LookupKeyID(keyID); len(key) == 1 {
  222.         return key[0].Materialize()
  223.     }
  224.  
  225.     return nil, errors.New("unable to find key")
  226. }
Add Comment
Please, Sign In to add comment