Skip to content

Commit

Permalink
Merge pull request #1155 from AzureAD/authorization-code-flow-logger
Browse files Browse the repository at this point in the history
Authorization Code Flow for Single Page Applications: Adding Logger class
  • Loading branch information
Prithvi Kanherkar committed Dec 19, 2019
2 parents 8b46822 + 2467f45 commit 2c111f2
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 27 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@
],
"eslint.quiet": true,
"files.eol": "\n",
"github-pr.targetBranch": "dev"
"github-pr.targetBranch": "dev",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
42 changes: 38 additions & 4 deletions lib/msal-browser/src/app/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

// import { Logger } from "./Logger";
import { AuthOptions, INetworkModule } from "msal-common";
import { AuthOptions, INetworkModule, ILoggerCallback, LogLevel } from "msal-common";
import { BrowserUtils } from "../utils/BrowserUtils";
import { BrowserConstants } from "../utils/BrowserConstants";
// import { TelemetryEmitter } from "./telemetry/TelemetryTypes";
Expand Down Expand Up @@ -48,14 +48,25 @@ export type TelemetryOptions = {
* - navigateFrameWait - sets the wait time for hidden iFrame navigation
*/
export type SystemOptions = {
// logger?: Logger;
loggerOptions?: BrowserLoggerOptions;
networkClient?: INetworkModule;
loadFrameTimeout?: number;
tokenRenewalOffsetSeconds?: number;
navigateFrameWait?: number;
telemetry?: TelemetryOptions
};

/**
* Logger options
*
* - piiLoggingEnabled - Used to configure whether piiLogging is enabled. Defaults to false.
* - loggerCallback - Callback for logger that determines how message is broadcast. Defaults to console.
*/
export type BrowserLoggerOptions = {
piiLoggingEnabled?: boolean,
loggerCallback?: ILoggerCallback
};

/**
* Use the configuration object to configure MSAL and initialize the UserAgentApplication.
*
Expand All @@ -66,7 +77,7 @@ export type SystemOptions = {
* - framework: this is where you can configure the running mode of angular. More to come here soon.
*/
export type Configuration = {
auth: AuthOptions,
auth?: AuthOptions,
cache?: CacheOptions,
system?: SystemOptions
};
Expand All @@ -86,8 +97,31 @@ const DEFAULT_CACHE_OPTIONS: CacheOptions = {
storeAuthStateInCookie: false
};

const DEFAULT_LOGGER_OPTIONS: BrowserLoggerOptions = {
loggerCallback: (level: LogLevel, message: string, containsPii: boolean): void => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
}
},
piiLoggingEnabled: false
};

const DEFAULT_SYSTEM_OPTIONS: SystemOptions = {
// logger: new Logger(null),
loggerOptions: DEFAULT_LOGGER_OPTIONS,
networkClient: BrowserUtils.getBrowserNetworkClient(),
loadFrameTimeout: FRAME_TIMEOUT,
tokenRenewalOffsetSeconds: OFFSET,
Expand Down
14 changes: 9 additions & 5 deletions lib/msal-browser/src/app/PublicClientApplication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { CryptoOps } from "../crypto/CryptoOps";
* @param authErr error created for failure cases
* @param response response containing token strings in success cases, or just state value in error cases
*/
export type authCallback = (authErr: AuthError, response?: AuthResponse) => void;
export type AuthCallback = (authErr: AuthError, response?: AuthResponse) => void;

/**
* Key-Value type to support queryParams, extraQueryParams and claims
Expand All @@ -34,7 +34,7 @@ export class PublicClientApplication {
private authModule: AuthorizationCodeModule;

// callback for error/token response
private authCallback: authCallback = null;
private authCallback: AuthCallback = null;

// Crypto interface implementation
private browserCrypto: CryptoOps;
Expand Down Expand Up @@ -81,6 +81,10 @@ export class PublicClientApplication {
// Create auth module
this.authModule = new AuthorizationCodeModule({
auth: this.config.auth,
loggerOptions: {
loggerCallbackInterface: this.config.system.loggerOptions.loggerCallback,
piiLoggingEnabled: this.config.system.loggerOptions.piiLoggingEnabled
},
cryptoInterface: this.browserCrypto,
networkInterface: this.networkClient,
storageInterface: this.browserStorage
Expand All @@ -91,12 +95,12 @@ export class PublicClientApplication {

/**
* Set the callback functions for the redirect flow to send back the success or error object.
* @param {@link (authCallback:type)} authCallback - Callback which contains
* @param {@link (AuthCallback:type)} authCallback - Callback which contains
* an AuthError object, containing error data from either the server
* or the library, depending on the origin of the error, or the AuthResponse object
* containing data from the server (returned with a null or non-blocking error).
*/
handleRedirectCallback(authCallback: authCallback): void {
handleRedirectCallback(authCallback: AuthCallback): void {
throw new Error("Method not implemented.");
}

Expand All @@ -107,7 +111,7 @@ export class PublicClientApplication {
*/
loginRedirect(request: AuthenticationParameters): void {
this.authModule.createLoginUrl(request).then((urlNavigate) => {
console.log(urlNavigate);
this.authModule.logger.info(urlNavigate);
});
}

Expand Down
34 changes: 21 additions & 13 deletions lib/msal-common/src/app/config/ModuleConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,86 +6,93 @@ import { ICacheStorage } from "../../cache/ICacheStorage";
import { INetworkModule, NetworkRequestOptions } from "../../network/INetworkModule";
import { ICrypto, PkceCodes } from "../../crypto/ICrypto";
import { AuthError } from "../../error/AuthError";
import { ILoggerCallback, LogLevel } from "../../logger/Logger";

/**
* Use the configuration object to configure MSAL Modules and initialize the base interfaces for MSAL.
*
* This object allows you to configure important elements of MSAL functionality:
* - logger: logging for application
* - storage: this is where you configure storage implementation.
* - network: this is where you can configure network implementation.
* - crypto: implementation of crypto functions
*/
export type ModuleConfiguration = {
loggerOptions?: LoggerOptions,
storageInterface?: ICacheStorage,
networkInterface?: INetworkModule,
cryptoInterface?: ICrypto
};

/**
* Logger options to configure the logging that MSAL does.
*/
export type LoggerOptions = {
loggerCallbackInterface?: ILoggerCallback,
piiLoggingEnabled?: boolean
};

const DEFAULT_LOGGER_IMPLEMENTATION: LoggerOptions = {
loggerCallbackInterface: () => {
const notImplErr = "Logger - loggerCallbackInterface() has not been implemented.";
throw AuthError.createUnexpectedError(notImplErr);
},
piiLoggingEnabled: false
};

const DEFAULT_STORAGE_IMPLEMENTATION: ICacheStorage = {
clear: () => {
const notImplErr = "Storage interface - clear() has not been implemented for the cacheStorage interface.";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
containsKey: (key: string): boolean => {
const notImplErr = "Storage interface - containsKey() has not been implemented for the cacheStorage interface.";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
getItem: (key: string): string => {
const notImplErr = "Storage interface - getItem() has not been implemented for the cacheStorage interface.";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
getKeys: (): string[] => {
const notImplErr = "Storage interface - getKeys() has not been implemented for the cacheStorage interface.";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
removeItem: (key: string) => {
const notImplErr = "Storage interface - removeItem() has not been implemented for the cacheStorage interface.";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
setItem: (key: string, value: string) => {
const notImplErr = "Storage interface - setItem() has not been implemented for the cacheStorage interface.";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
}
};

const DEFAULT_NETWORK_IMPLEMENTATION: INetworkModule = {
async sendGetRequestAsync(url: string, options?: NetworkRequestOptions): Promise<any> {
const notImplErr = "Network interface - sendGetRequestAsync() has not been implemented";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
async sendPostRequestAsync(url: string, options?: NetworkRequestOptions): Promise<any> {
const notImplErr = "Network interface - sendPostRequestAsync() has not been implemented";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
}
};

const DEFAULT_CRYPTO_IMPLEMENTATION: ICrypto = {
createNewGuid: (): string => {
const notImplErr = "Crypto interface - createNewGuid() has not been implemented";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
base64Decode: (input: string): string => {
const notImplErr = "Crypto interface - base64Decode() has not been implemented";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
base64Encode: (input: string): string => {
const notImplErr = "Crypto interface - base64Encode() has not been implemented";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
},
async generatePkceCodes(): Promise<PkceCodes> {
const notImplErr = "Crypto interface - generatePkceCodes() has not been implemented";
console.warn(notImplErr);
throw AuthError.createUnexpectedError(notImplErr);
}
};
Expand All @@ -99,8 +106,9 @@ const DEFAULT_CRYPTO_IMPLEMENTATION: ICrypto = {
*
* @returns MsalConfiguration object
*/
export function buildModuleConfiguration({ storageInterface: storageImplementation, networkInterface: networkImplementation, cryptoInterface: cryptoImplementation }: ModuleConfiguration): ModuleConfiguration {
export function buildModuleConfiguration({ loggerOptions: userLoggerOption, storageInterface: storageImplementation, networkInterface: networkImplementation, cryptoInterface: cryptoImplementation }: ModuleConfiguration): ModuleConfiguration {
const overlayedConfig: ModuleConfiguration = {
loggerOptions: userLoggerOption || DEFAULT_LOGGER_IMPLEMENTATION,
storageInterface: storageImplementation || DEFAULT_STORAGE_IMPLEMENTATION,
networkInterface: networkImplementation || DEFAULT_NETWORK_IMPLEMENTATION,
cryptoInterface: cryptoImplementation || DEFAULT_CRYPTO_IMPLEMENTATION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ const DEFAULT_AUTH_OPTIONS: AuthOptions = {
*
* @returns TConfiguration object
*/
export function buildPublicClientSPAConfiguration({ auth, storageInterface, networkInterface, cryptoInterface }: PublicClientSPAConfiguration): PublicClientSPAConfiguration {
const baseConfig = buildModuleConfiguration({storageInterface, networkInterface, cryptoInterface});
export function buildPublicClientSPAConfiguration({ auth, loggerOptions, storageInterface, networkInterface, cryptoInterface }: PublicClientSPAConfiguration): PublicClientSPAConfiguration {
const baseConfig = buildModuleConfiguration({loggerOptions, storageInterface, networkInterface, cryptoInterface});
const overlayedConfig: PublicClientSPAConfiguration = {
auth: { ...DEFAULT_AUTH_OPTIONS, ...auth },
...baseConfig
Expand Down
7 changes: 7 additions & 0 deletions lib/msal-common/src/app/module/AuthModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { StringUtils } from "../../utils/StringUtils";
import { IdToken } from "../../auth/IdToken";
import { buildClientInfo } from "../../auth/ClientInfo";
import { CacheHelpers } from "../../cache/CacheHelpers";
import { Logger } from "../../logger/Logger";

/**
* @hidden
Expand All @@ -40,6 +41,9 @@ export type ResponseStateInfo = {
*/
export abstract class AuthModule {

// Logger object
public logger: Logger;

// Application config
private config: ModuleConfiguration;

Expand All @@ -65,6 +69,9 @@ export abstract class AuthModule {
// Set the configuration
this.config = buildModuleConfiguration(configuration);

// Initialize the logger
this.logger = new Logger(configuration.loggerOptions.loggerCallbackInterface, configuration.loggerOptions.piiLoggingEnabled);

// Initialize crypto
this.cryptoObj = this.config.cryptoInterface;

Expand Down
1 change: 1 addition & 0 deletions lib/msal-common/src/app/module/AuthorizationCodeModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class AuthorizationCodeModule extends AuthModule {

constructor(configuration: PublicClientSPAConfiguration) {
super({
loggerOptions: configuration.loggerOptions,
storageInterface: configuration.storageInterface,
networkInterface: configuration.networkInterface,
cryptoInterface: configuration.cryptoInterface
Expand Down
5 changes: 4 additions & 1 deletion lib/msal-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ export { TokenExchangeParameters } from "./request/TokenExchangeParameters";
export { AuthResponse, buildResponseStateOnly } from "./response/AuthResponse";
export { TokenResponse } from "./response/TokenResponse";
export { CodeResponse } from "./response/CodeResponse";
// Logger Callback
export { ILoggerCallback, LogLevel } from "./logger/Logger";
// Errors
export { AuthError, AuthErrorMessage } from "./error/AuthError";
export { ClientAuthError, ClientAuthErrorMessage } from "./error/ClientAuthError";
export { ClientConfigurationError, ClientConfigurationErrorMessage } from "./error/ClientConfigurationError";
// Constants
// Constants and Utils
export { Constants, TemporaryCacheKeys, PersistentCacheKeys, ErrorCacheKeys } from "./utils/Constants";
export { StringUtils } from "./utils/StringUtils";

0 comments on commit 2c111f2

Please sign in to comment.