public async validate()

in src/queue/authentication/QueueSharedKeyAuthenticator.ts [17:169]


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

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

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

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

    const authType = authHeaderValue.split(" ")[0] as
      | "SharedKey"
      | "SharedKeyLite";
    const authValue = authHeaderValue.split(" ")[1];
    const headersToSign = this.getHeadersToSign(authType, req);

    const stringToSign: string =
      headersToSign +
      this.getCanonicalizedResourceString(
        authType,
        req,
        account,
        queueContext.authenticationPath
      );

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

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

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

    if (context.context.isSecondary && queueContext.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 =
      headersToSign +
      this.getCanonicalizedResourceString(
        authType,
        req,
        account,
        // The authenticationPath looks like "/devstoreaccount1/queue", add "-secondary" after account name to "/devstoreaccount1-secondary/queue"
        queueContext.authenticationPath?.replace(account, account + "-secondary")
      );

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

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

      if (accountProperties.key2) {
        const signature2_secondary = computeHMACSHA256(
          stringToSign_secondary,
          accountProperties.key2
        );
        const authValue2_secondary = `${account}:${signature2_secondary}`;
        this.logger.info(
          `QueueSharedKeyAuthenticator:validate() Calculated authentication header based on key2: ${authValue2_secondary}`,
          queueContext.contextID
        );
        if (authValue === authValue2_secondary) {
          this.logger.info(
            `QueueSharedKeyAuthenticator:validate() Signature 2_secondary matched.`,
            queueContext.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(
      `QueueSharedKeyAuthenticator:validate() Validation failed.`,
      queueContext.contextID
    );
    return false;
  }