public async validate()

in src/table/authentication/TableSharedKeyAuthenticator.ts [17:175]


  public async validate(
    req: IRequest,
    context: Context
  ): Promise<boolean | undefined> {
    const tableContext = new TableStorageContext(context);
    const account = tableContext.account!;

    this.logger.info(
      `TableSharedKeyAuthenticator:validate() Start validation against account shared key authentication.`,
      tableContext.contextID
    );

    const authHeaderValue = req.getHeader(HeaderConstants.AUTHORIZATION);
    if (authHeaderValue === undefined) {
      this.logger.info(
        // tslint:disable-next-line:max-line-length
        `TableSharedKeyAuthenticator:validate() Request doesn't include valid authentication header. Skip shared key authentication.`,
        tableContext.contextID
      );
      return undefined;
    }

    // TODO: Make following async
    const accountProperties = this.dataStore.getAccount(account);
    if (accountProperties === undefined) {
      this.logger.error(
        `TableSharedKeyAuthenticator:validate() Invalid storage account ${account}.`,
        tableContext.contextID
      );
      throw StorageErrorFactory.ResourceNotFound(
        context
      );
    }

    const stringToSign: string =
      [
        req.getMethod().toUpperCase(),
        this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5),
        this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE),
        this.getHeaderValueToSign(req, HeaderConstants.DATE) ||
          this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE)
      ].join("\n") +
      "\n" +
      this.getCanonicalizedResourceString(
        req,
        account,
        tableContext.authenticationPath
      );

    this.logger.info(
      `TableSharedKeyAuthenticator:validate() [STRING TO SIGN]:${JSON.stringify(
        stringToSign
      )}`,
      tableContext.contextID
    );

    const signature1 = computeHMACSHA256(stringToSign, accountProperties.key1);
    const authValue1 = `SharedKey ${account}:${signature1}`;
    this.logger.info(
      `TableSharedKeyAuthenticator:validate() Calculated authentication header based on key1: ${authValue1}`,
      tableContext.contextID
    );
    if (authHeaderValue === authValue1) {
      this.logger.info(
        `TableSharedKeyAuthenticator:validate() Signature 1 matched.`,
        tableContext.contextID
      );
      return true;
    }

    if (accountProperties.key2) {
      const signature2 = computeHMACSHA256(
        stringToSign,
        accountProperties.key2
      );
      const authValue2 = `SharedKey ${account}:${signature2}`;
      this.logger.info(
        `TableSharedKeyAuthenticator:validate() Calculated authentication header based on key2: ${authValue2}`,
        tableContext.contextID
      );
      if (authHeaderValue === authValue2) {
        this.logger.info(
          `TableSharedKeyAuthenticator:validate() Signature 2 matched.`,
          tableContext.contextID
        );
        return true;
      }
    }

    if (context.context.isSecondary && tableContext.authenticationPath?.indexOf(account) === 1)
    {
      // JS/.net Track2 SDK will generate stringToSign from IP style URI with "-secondary" in authenticationPath, so will also compare signature with this kind stringToSign
      const stringToSign_secondary: string =
      [
        req.getMethod().toUpperCase(),
        this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5),
        this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE),
        this.getHeaderValueToSign(req, HeaderConstants.DATE) ||
          this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE)
      ].join("\n") +
      "\n" +
      this.getCanonicalizedResourceString(
        req,
        account,
        // The authenticationPath looks like "/devstoreaccount1/table", add "-secondary" after account name to "/devstoreaccount1-secondary/table"
        tableContext.authenticationPath?.replace(account, account + "-secondary")
      );

      this.logger.info(
        `TableSharedKeyAuthenticator:validate() [STRING TO SIGN_secondary]:${JSON.stringify(
          stringToSign_secondary
        )}`,
        tableContext.contextID
      );

      const signature1_secondary = computeHMACSHA256(stringToSign_secondary, accountProperties.key1);
      const authValue1_secondary = `SharedKey ${account}:${signature1_secondary}`;
      this.logger.info(
        `TableSharedKeyAuthenticator:validate() Calculated authentication header based on key1: ${authValue1_secondary}`,
        tableContext.contextID
      );
      if (authHeaderValue === authValue1_secondary) {
        this.logger.info(
          `TableSharedKeyAuthenticator:validate() Signature 1_secondary matched.`,
          tableContext.contextID
        );
        return true;
      }

      if (accountProperties.key2) {
        const signature2_secondary = computeHMACSHA256(
          stringToSign_secondary,
          accountProperties.key2
        );
        const authValue2_secondary = `SharedKey ${account}:${signature2_secondary}`;
        this.logger.info(
          `TableSharedKeyAuthenticator:validate() Calculated authentication header based on key2: ${authValue2_secondary}`,
          tableContext.contextID
        );
        if (authHeaderValue === authValue2_secondary) {
          this.logger.info(
            `TableSharedKeyAuthenticator:validate() Signature 2_secondary matched.`,
            tableContext.contextID
          );
          return true;
        }
      }
    }

    // this.logger.info(`[URL]:${req.getUrl()}`);
    // this.logger.info(`[HEADERS]:${req.getHeaders().toString()}`);
    // this.logger.info(`[KEY]: ${request.headers.get(HeaderConstants.AUTHORIZATION)}`);

    this.logger.info(
      `TableSharedKeyAuthenticator:validate() Validation failed.`,
      tableContext.contextID
    );
    return false;
  }