File

src/auth/executable-response.ts

Description

An error thrown by the ExecutableResponse class.

Extends

Error

Constructor

constructor(message: string)
Parameters :
Name Type Optional
message string No
const SAML_SUBJECT_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:saml2';
const OIDC_SUBJECT_TOKEN_TYPE1 = 'urn:ietf:params:oauth:token-type:id_token';
const OIDC_SUBJECT_TOKEN_TYPE2 = 'urn:ietf:params:oauth:token-type:jwt';

/**
 * Interface defining the JSON formatted response of a 3rd party executable
 * used by the pluggable auth client.
 */
export interface ExecutableResponseJson {
  /**
   * The version of the JSON response. Only version 1 is currently supported.
   * Always required.
   */
  version: number;
  /**
   * Whether the executable ran successfully. Always required.
   */
  success: boolean;
  /**
   * The epoch time for expiration of the token in seconds, required for
   * successful responses.
   */
  expiration_time?: number;
  /**
   * The type of subject token in the response, currently supported values are:
   * urn:ietf:params:oauth:token-type:saml2
   * urn:ietf:params:oauth:token-type:id_token
   * urn:ietf:params:oauth:token-type:jwt
   */
  token_type?: string;
  /**
   * The error code from the executable, required when unsuccessful.
   */
  code?: string;
  /**
   * The error message from the executable, required when unsuccessful.
   */
  message?: string;
  /**
   * The ID token to be used as a subject token when token_type is id_token or jwt.
   */
  id_token?: string;
  /**
   * The response to be used as a subject token when token_type is saml2.
   */
  saml_response?: string;
}

/**
 * Defines the response of a 3rd party executable run by the pluggable auth client.
 */
export class ExecutableResponse {
  /**
   * The version of the Executable response. Only version 1 is currently supported.
   */
  readonly version: number;
  /**
   * Whether the executable ran successfully.
   */
  readonly success: boolean;
  /**
   * The epoch time for expiration of the token in seconds.
   */
  readonly expirationTime?: number;
  /**
   * The type of subject token in the response, currently supported values are:
   * urn:ietf:params:oauth:token-type:saml2
   * urn:ietf:params:oauth:token-type:id_token
   * urn:ietf:params:oauth:token-type:jwt
   */
  readonly tokenType?: string;
  /**
   * The error code from the executable.
   */
  readonly errorCode?: string;
  /**
   * The error message from the executable.
   */
  readonly errorMessage?: string;
  /**
   * The subject token from the executable, format depends on tokenType.
   */
  readonly subjectToken?: string;

  /**
   * Instantiates an ExecutableResponse instance using the provided JSON object
   * from the output of the executable.
   * @param responseJson Response from a 3rd party executable, loaded from a
   * run of the executable or a cached output file.
   */
  constructor(responseJson: ExecutableResponseJson) {
    // Check that the required fields exist in the json response.
    if (!responseJson.version) {
      throw new InvalidVersionFieldError(
        "Executable response must contain a 'version' field."
      );
    }
    if (responseJson.success === undefined) {
      throw new InvalidSuccessFieldError(
        "Executable response must contain a 'success' field."
      );
    }

    this.version = responseJson.version;
    this.success = responseJson.success;

    // Validate required fields for a successful response.
    if (this.success) {
      this.expirationTime = responseJson.expiration_time;
      this.tokenType = responseJson.token_type;

      // Validate token type field.
      if (
        this.tokenType !== SAML_SUBJECT_TOKEN_TYPE &&
        this.tokenType !== OIDC_SUBJECT_TOKEN_TYPE1 &&
        this.tokenType !== OIDC_SUBJECT_TOKEN_TYPE2
      ) {
        throw new InvalidTokenTypeFieldError(
          "Executable response must contain a 'token_type' field when successful " +
            `and it must be one of ${OIDC_SUBJECT_TOKEN_TYPE1}, ${OIDC_SUBJECT_TOKEN_TYPE2}, or ${SAML_SUBJECT_TOKEN_TYPE}.`
        );
      }

      // Validate subject token.
      if (this.tokenType === SAML_SUBJECT_TOKEN_TYPE) {
        if (!responseJson.saml_response) {
          throw new InvalidSubjectTokenError(
            `Executable response must contain a 'saml_response' field when token_type=${SAML_SUBJECT_TOKEN_TYPE}.`
          );
        }
        this.subjectToken = responseJson.saml_response;
      } else {
        if (!responseJson.id_token) {
          throw new InvalidSubjectTokenError(
            "Executable response must contain a 'id_token' field when " +
              `token_type=${OIDC_SUBJECT_TOKEN_TYPE1} or ${OIDC_SUBJECT_TOKEN_TYPE2}.`
          );
        }
        this.subjectToken = responseJson.id_token;
      }
    } else {
      // Both code and message must be provided for unsuccessful responses.
      if (!responseJson.code) {
        throw new InvalidCodeFieldError(
          "Executable response must contain a 'code' field when unsuccessful."
        );
      }
      if (!responseJson.message) {
        throw new InvalidMessageFieldError(
          "Executable response must contain a 'message' field when unsuccessful."
        );
      }
      this.errorCode = responseJson.code;
      this.errorMessage = responseJson.message;
    }
  }

  /**
   * @return A boolean representing if the response has a valid token. Returns
   * true when the response was successful and the token is not expired.
   */
  isValid(): boolean {
    return !this.isExpired() && this.success;
  }

  /**
   * @return A boolean representing if the response is expired. Returns true if the
   * provided timeout has passed.
   */
  isExpired(): boolean {
    return (
      this.expirationTime !== undefined &&
      this.expirationTime < Math.round(Date.now() / 1000)
    );
  }
}

/**
 * An error thrown by the ExecutableResponse class.
 */
export class ExecutableResponseError extends Error {
  constructor(message: string) {
    super(message);
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

/**
 * An error thrown when the 'version' field in an executable response is missing or invalid.
 */
export class InvalidVersionFieldError extends ExecutableResponseError {}

/**
 * An error thrown when the 'success' field in an executable response is missing or invalid.
 */
export class InvalidSuccessFieldError extends ExecutableResponseError {}

/**
 * An error thrown when the 'expiration_time' field in an executable response is missing or invalid.
 */
export class InvalidExpirationTimeFieldError extends ExecutableResponseError {}

/**
 * An error thrown when the 'token_type' field in an executable response is missing or invalid.
 */
export class InvalidTokenTypeFieldError extends ExecutableResponseError {}

/**
 * An error thrown when the 'code' field in an executable response is missing or invalid.
 */
export class InvalidCodeFieldError extends ExecutableResponseError {}

/**
 * An error thrown when the 'message' field in an executable response is missing or invalid.
 */
export class InvalidMessageFieldError extends ExecutableResponseError {}

/**
 * An error thrown when the subject token in an executable response is missing or invalid.
 */
export class InvalidSubjectTokenError extends ExecutableResponseError {}

results matching ""

    No results matching ""