From 830a907bd1c6546ed74fa969546b37681cc7967f Mon Sep 17 00:00:00 2001 From: Krishna Acondy Date: Sat, 21 Aug 2021 21:36:50 +0100 Subject: [PATCH] feat(login): add redirected login mechanism --- src/SASjs.ts | 30 ++++++++++++++++++++++++++---- src/api/viya/pollJobState.ts | 4 +--- src/auth/AuthManager.ts | 33 ++++++++++++++++++++++++++++++++- src/types/SASjsConfig.ts | 9 +++++++++ src/utils/delay.ts | 2 ++ src/utils/index.ts | 1 + 6 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 src/utils/delay.ts diff --git a/src/SASjs.ts b/src/SASjs.ts index 5924985..2c08f70 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -1,5 +1,11 @@ import { compareTimestamps, asyncForEach } from './utils' -import { SASjsConfig, UploadFile, EditContextInput, PollOptions } from './types' +import { + SASjsConfig, + UploadFile, + EditContextInput, + PollOptions, + LoginMechanism +} from './types' import { SASViyaApiClient } from './SASViyaApiClient' import { SAS9ApiClient } from './SAS9ApiClient' import { FileUploader } from './FileUploader' @@ -29,7 +35,8 @@ const defaultConfig: SASjsConfig = { debug: false, contextName: 'SAS Job Execution compute context', useComputeApi: null, - allowInsecureRequests: false + allowInsecureRequests: false, + loginMechanism: LoginMechanism.Default } /** @@ -526,8 +533,23 @@ export default class SASjs { * @param username - a string representing the username. * @param password - a string representing the password. */ - public async logIn(username: string, password: string) { - return this.authManager!.logIn(username, password) + public async logIn(username?: string, password?: string) { + if (this.sasjsConfig.loginMechanism === LoginMechanism.Default) { + if (!username || !password) { + throw new Error( + 'A username and password are required when using the default login mechanism.' + ) + } + return this.authManager!.logIn(username, password) + } + + if (typeof window === typeof undefined) { + throw new Error( + 'The redirected login mechanism is only available for use in the browser.' + ) + } + + return this.authManager!.redirectedLogIn() } /** diff --git a/src/api/viya/pollJobState.ts b/src/api/viya/pollJobState.ts index c4b05d0..6829611 100644 --- a/src/api/viya/pollJobState.ts +++ b/src/api/viya/pollJobState.ts @@ -4,7 +4,7 @@ import { getTokens } from '../../auth/getTokens' import { RequestClient } from '../../request/RequestClient' import { JobStatePollError } from '../../types/errors' import { Link, WriteStream } from '../../types' -import { isNode } from '../../utils' +import { delay, isNode } from '../../utils' export async function pollJobState( requestClient: RequestClient, @@ -246,5 +246,3 @@ const doPoll = async ( return { state, pollCount } } - -const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) diff --git a/src/auth/AuthManager.ts b/src/auth/AuthManager.ts index 7d29cf9..2747bc9 100644 --- a/src/auth/AuthManager.ts +++ b/src/auth/AuthManager.ts @@ -1,6 +1,6 @@ import { ServerType } from '@sasjs/utils/types' import { RequestClient } from '../request/RequestClient' -import { serialize } from '../utils' +import { delay, serialize } from '../utils' export class AuthManager { public userName = '' @@ -19,6 +19,37 @@ export class AuthManager { : '/SASLogon/logout.do?' } + public async redirectedLogIn() { + await this.logOut() + const loginPopup = window.open( + this.loginUrl.replace('.do', ''), + '_blank', + 'toolbar=0,location=0,menubar=0,width=500,height=500' + ) + let isLoggedIn = false + let startTime = new Date() + let elapsedSeconds = 0 + do { + await delay(1000) + isLoggedIn = + document.cookie.includes('Current-User') && + document.cookie.includes('userId') + elapsedSeconds = (new Date().valueOf() - startTime.valueOf()) / 1000 + } while (!isLoggedIn && elapsedSeconds < 5 * 60) + + let isAuthorized = false + startTime = new Date() + do { + await delay(1000) + isAuthorized = !loginPopup?.window.location.href.includes('SASLogon') + elapsedSeconds = (new Date().valueOf() - startTime.valueOf()) / 1000 + } while (!isAuthorized && elapsedSeconds < 5 * 60) + + loginPopup?.close() + + return { isLoggedIn: isLoggedIn && isAuthorized, userName: 'test' } + } + /** * Logs into the SAS server with the supplied credentials. * @param username - a string representing the username. diff --git a/src/types/SASjsConfig.ts b/src/types/SASjsConfig.ts index 2bdd84c..b562dcb 100644 --- a/src/types/SASjsConfig.ts +++ b/src/types/SASjsConfig.ts @@ -59,4 +59,13 @@ export class SASjsConfig { * Changing this setting is not recommended. */ allowInsecureRequests = false + /** + * Supported login mechanisms are - Redirected and Default + */ + loginMechanism: LoginMechanism = LoginMechanism.Default +} + +export enum LoginMechanism { + Default = 'Default', + Redirected = 'Redirected' } diff --git a/src/utils/delay.ts b/src/utils/delay.ts new file mode 100644 index 0000000..8e83610 --- /dev/null +++ b/src/utils/delay.ts @@ -0,0 +1,2 @@ +export const delay = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)) diff --git a/src/utils/index.ts b/src/utils/index.ts index 2a05d63..0534f25 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,6 +1,7 @@ export * from './asyncForEach' export * from './compareTimestamps' export * from './convertToCsv' +export * from './delay' export * from './isNode' export * from './isRelativePath' export * from './isUri'