golangでaws Cognito User Pools 認証やれるかな 


golangで Cognito User Pools認証をやりたいので調査中..



# javascriptの場合

> User Pool情報とキーとなるUsernameを使ってCognitoUserオブジェクトを作ります。また認証に必要になるUsernameとPasswordを使ってプロバイダのAuthenticationDetailsというものを作ります。最後にAuthenticationDetailsを使ってCognitoUserオブジェクトを認証させます。認証に成功するとTokenが取れます。CognitoのTokenは3種類(AccessToken, IdToken, RefreshToken)あります。User Poolsが認証するのに必要なのはIdTokenなのでこれをいろいろな画面に引き継いで使ってもOKですね。

引用元: http://dev.classmethod.jp/cloud/aws/login-form-by-using-aws-sdk-for-javascript/



# aws/amazon-cognito-identity-js での認証の実装
https://github.com/aws/amazon-cognito-identity-js/blob/master/src/CognitoUser.js#L140-L255

```js:CognitoUser.js
  /**
   * This is used for authenticating the user. it calls the AuthenticationHelper for SRP related
   * stuff
   * @param {AuthenticationDetails} authDetails Contains the authentication data
   * @param {object} callback Result callback map.
   * @param {onFailure} callback.onFailure Called on any error.
   * @param {newPasswordRequired} callback.newPasswordRequired new
   *        password and any required attributes are required to continue
   * @param {mfaRequired} callback.mfaRequired MFA code
   *        required to continue.
   * @param {customChallenge} callback.customChallenge Custom challenge
   *        response required to continue.
   * @param {authSuccess} callback.onSuccess Called on success with the new session.
   * @returns {void}
   */
  authenticateUser(authDetails, callback) {
    const authenticationHelper = new AuthenticationHelper(
      this.pool.getUserPoolId().split('_')[1]);
    const dateHelper = new DateHelper();

    let serverBValue;
    let salt;
    const authParameters = {};

    if (this.deviceKey != null) {
      authParameters.DEVICE_KEY = this.deviceKey;
    }

    authParameters.USERNAME = this.username;
    authParameters.SRP_A = authenticationHelper.getLargeAValue().toString(16);

    if (this.authenticationFlowType === 'CUSTOM_AUTH') {
      authParameters.CHALLENGE_NAME = 'SRP_A';
    }

    this.client.makeUnauthenticatedRequest('initiateAuth', {
      AuthFlow: this.authenticationFlowType,
      ClientId: this.pool.getClientId(),
      AuthParameters: authParameters,
      ClientMetadata: authDetails.getValidationData(),
    }, (err, data) => {
      if (err) {
        return callback.onFailure(err);
      }

      const challengeParameters = data.ChallengeParameters;

      this.username = challengeParameters.USER_ID_FOR_SRP;
      serverBValue = new BigInteger(challengeParameters.SRP_B, 16);
      salt = new BigInteger(challengeParameters.SALT, 16);
      this.getCachedDeviceKeyAndPassword();

      const hkdf = authenticationHelper.getPasswordAuthenticationKey(
        this.username,
        authDetails.getPassword(),
        serverBValue,
        salt);

      const dateNow = dateHelper.getNowString();

      const signatureString = util.crypto.hmac(hkdf, util.buffer.concat([
        new util.Buffer(this.pool.getUserPoolId().split('_')[1], 'utf8'),
        new util.Buffer(this.username, 'utf8'),
        new util.Buffer(challengeParameters.SECRET_BLOCK, 'base64'),
        new util.Buffer(dateNow, 'utf8'),
      ]), 'base64', 'sha256');

      const challengeResponses = {};

      challengeResponses.USERNAME = this.username;
      challengeResponses.PASSWORD_CLAIM_SECRET_BLOCK = challengeParameters.SECRET_BLOCK;
      challengeResponses.TIMESTAMP = dateNow;
      challengeResponses.PASSWORD_CLAIM_SIGNATURE = signatureString;

      if (this.deviceKey != null) {
        challengeResponses.DEVICE_KEY = this.deviceKey;
      }

      const respondToAuthChallenge = (challenge, challengeCallback) =>
        this.client.makeUnauthenticatedRequest('respondToAuthChallenge', challenge,
          (errChallenge, dataChallenge) => {
            if (errChallenge && errChallenge.code === 'ResourceNotFoundException' &&
                errChallenge.message.toLowerCase().indexOf('device') !== -1) {
              challengeResponses.DEVICE_KEY = null;
              this.deviceKey = null;
              this.randomPassword = null;
              this.deviceGroupKey = null;
              this.clearCachedDeviceKeyAndPassword();
              return respondToAuthChallenge(challenge, challengeCallback);
            }
            return challengeCallback(errChallenge, dataChallenge);
          });

      respondToAuthChallenge({
        ChallengeName: 'PASSWORD_VERIFIER',
        ClientId: this.pool.getClientId(),
        ChallengeResponses: challengeResponses,
        Session: data.Session,
      }, (errAuthenticate, dataAuthenticate) => {
        if (errAuthenticate) {
          return callback.onFailure(errAuthenticate);
        }

        const challengeName = dataAuthenticate.ChallengeName;
        if (challengeName === 'NEW_PASSWORD_REQUIRED') {
          this.Session = dataAuthenticate.Session;
          let userAttributes = null;
          let rawRequiredAttributes = null;
          const requiredAttributes = [];
          const userAttributesPrefix = authenticationHelper
            .getNewPasswordRequiredChallengeUserAttributePrefix();

          if (dataAuthenticate.ChallengeParameters) {
            userAttributes = JSON.parse(
              dataAuthenticate.ChallengeParameters.userAttributes);
            rawRequiredAttributes = JSON.parse(
              dataAuthenticate.ChallengeParameters.requiredAttributes);
          }

          if (rawRequiredAttributes) {
            for (let i = 0; i < rawRequiredAttributes.length; i++) {
              requiredAttributes[i] = rawRequiredAttributes[i].substr(userAttributesPrefix.length);
            }
          }
          return callback.newPasswordRequired(userAttributes, requiredAttributes);
        }
        return this.authenticateUserInternal(dataAuthenticate, authenticationHelper, callback);
      });
      return undefined;
    });
  }
```


## やっぱり無理だな・・・

AuthenticationHelperが重すぎて無理・・・

https://github.com/aws/amazon-cognito-identity-js/blob/master/src/AuthenticationHelper.js