Advertisement
Guest User

Untitled

a guest
May 30th, 2018
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement