tokenCredentialsBase.ts 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See License.txt in the project root for license information.
  3. import { Constants as MSRestConstants, WebResource } from "@azure/ms-rest-js";
  4. import { Environment } from "@azure/ms-rest-azure-env";
  5. import { TokenAudience } from "../util/authConstants";
  6. import { TokenClientCredentials } from "./tokenClientCredentials";
  7. import { TokenResponse, AuthenticationContext, MemoryCache, ErrorResponse, TokenCache } from "adal-node";
  8. export abstract class TokenCredentialsBase implements TokenClientCredentials {
  9. public readonly authContext: AuthenticationContext;
  10. public constructor(
  11. public readonly clientId: string,
  12. public domain: string,
  13. public readonly tokenAudience?: TokenAudience,
  14. public readonly environment: Environment = Environment.AzureCloud,
  15. public tokenCache: TokenCache = new MemoryCache()) {
  16. if (!clientId || typeof clientId.valueOf() !== "string") {
  17. throw new Error("clientId must be a non empty string.");
  18. }
  19. if (!domain || typeof domain.valueOf() !== "string") {
  20. throw new Error("domain must be a non empty string.");
  21. }
  22. if (this.tokenAudience === "graph" && this.domain.toLowerCase() === "common") {
  23. throw new Error(`${"If the tokenAudience is specified as \"graph\" then \"domain\" cannot be defaulted to \"commmon\" tenant.\
  24. It must be the actual tenant (preferrably a string in a guid format)."}`);
  25. }
  26. const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
  27. this.authContext = new AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
  28. }
  29. protected getActiveDirectoryResourceId(): string {
  30. let resource = this.environment.activeDirectoryResourceId;
  31. if (this.tokenAudience) {
  32. resource = this.tokenAudience;
  33. if (this.tokenAudience.toLowerCase() === "graph") {
  34. resource = this.environment.activeDirectoryGraphResourceId as string;
  35. } else if (this.tokenAudience.toLowerCase() === "batch") {
  36. resource = this.environment.batchResourceId as string;
  37. }
  38. }
  39. return resource;
  40. }
  41. protected getTokenFromCache(username?: string): Promise<TokenResponse> {
  42. const self = this;
  43. const resource = this.getActiveDirectoryResourceId();
  44. return new Promise<TokenResponse>((resolve, reject) => {
  45. self.authContext.acquireToken(resource, username!, self.clientId, (error: Error, tokenResponse: TokenResponse | ErrorResponse) => {
  46. if (error) {
  47. return reject(error);
  48. }
  49. if (tokenResponse.error || tokenResponse.errorDescription) {
  50. return reject(tokenResponse);
  51. }
  52. return resolve(tokenResponse as TokenResponse);
  53. });
  54. });
  55. }
  56. /**
  57. * Tries to get the token from cache initially. If that is unsuccessful then it tries to get the token from ADAL.
  58. * @returns {Promise<TokenResponse>}
  59. * {object} [tokenResponse] The tokenResponse (tokenType and accessToken are the two important properties).
  60. * @memberof TokenCredentialsBase
  61. */
  62. public async abstract getToken(): Promise<TokenResponse>;
  63. /**
  64. * Signs a request with the Authentication header.
  65. *
  66. * @param {webResource} The WebResource to be signed.
  67. * @param {function(error)} callback The callback function.
  68. * @return {undefined}
  69. */
  70. public async signRequest(webResource: WebResource): Promise<WebResource> {
  71. const tokenResponse = await this.getToken();
  72. webResource.headers.set(MSRestConstants.HeaderConstants.AUTHORIZATION, `${tokenResponse.tokenType} ${tokenResponse.accessToken}`);
  73. return Promise.resolve(webResource);
  74. }
  75. }