From c243f254773677cf24abf5bf0d5e336dbbabbcc1 Mon Sep 17 00:00:00 2001 From: Mihajlo Date: Mon, 9 May 2022 13:26:17 +0200 Subject: [PATCH 1/6] fix: deprecating sasjs client id --- src/SASjs.ts | 2 +- src/SASjsApiClient.ts | 4 ++-- src/auth/AuthManager.ts | 20 +++++--------------- src/auth/getAccessTokenForSasjs.ts | 2 -- src/auth/getAuthCodeForSasjs.ts | 5 ++--- src/auth/spec/getAccessTokenForSasjs.spec.ts | 9 ++------- 6 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/SASjs.ts b/src/SASjs.ts index f554947..3ccbc7f 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -598,7 +598,7 @@ export default class SASjs { 'A username, password and clientId are required when using the default login mechanism with server type SASJS.' ) - return this.authManager!.logInSasjs(username, password, clientId) + return this.authManager!.logInSasjs(username, password) } return this.authManager!.logIn(username, password) diff --git a/src/SASjsApiClient.ts b/src/SASjsApiClient.ts index af17911..3d37f18 100644 --- a/src/SASjsApiClient.ts +++ b/src/SASjsApiClient.ts @@ -104,7 +104,7 @@ export class SASjsApiClient { clientId: string, authCode: string ): Promise { - return getAccessTokenForSasjs(this.requestClient, clientId, authCode) + return getAccessTokenForSasjs(this.requestClient, authCode) } /** @@ -126,7 +126,7 @@ export class SASjsApiClient { password: string, clientId: string ) { - return getAuthCodeForSasjs(this.requestClient, username, password, clientId) + return getAuthCodeForSasjs(this.requestClient, username, password) } } diff --git a/src/auth/AuthManager.ts b/src/auth/AuthManager.ts index 5d69c94..4568af3 100644 --- a/src/auth/AuthManager.ts +++ b/src/auth/AuthManager.ts @@ -92,14 +92,9 @@ export class AuthManager { */ public async logInSasjs( username: string, - password: string, - clientId: string + password: string ): Promise { - const isLoggedIn = await this.sendLoginRequestSasjs( - username, - password, - clientId - ) + const isLoggedIn = await this.sendLoginRequestSasjs(username, password) .then((res) => { this.userName = username this.requestClient.saveLocalStorageToken( @@ -215,18 +210,13 @@ export class AuthManager { return loginResponse } - private async sendLoginRequestSasjs( - username: string, - password: string, - clientId: string - ) { + private async sendLoginRequestSasjs(username: string, password: string) { const authCode = await getAuthCodeForSasjs( this.requestClient, username, - password, - clientId + password ) - return getAccessTokenForSasjs(this.requestClient, clientId, authCode) + return getAccessTokenForSasjs(this.requestClient, authCode) } /** * Checks whether a session is active, or login is required. diff --git a/src/auth/getAccessTokenForSasjs.ts b/src/auth/getAccessTokenForSasjs.ts index 7b080bf..57cc4bd 100644 --- a/src/auth/getAccessTokenForSasjs.ts +++ b/src/auth/getAccessTokenForSasjs.ts @@ -9,12 +9,10 @@ import { RequestClient } from '../request/RequestClient' */ export async function getAccessTokenForSasjs( requestClient: RequestClient, - clientId: string, authCode: string ) { const url = '/SASjsApi/auth/token' const data = { - clientId, code: authCode } diff --git a/src/auth/getAuthCodeForSasjs.ts b/src/auth/getAuthCodeForSasjs.ts index aa6d2b2..4b99414 100644 --- a/src/auth/getAuthCodeForSasjs.ts +++ b/src/auth/getAuthCodeForSasjs.ts @@ -11,11 +11,10 @@ import { RequestClient } from '../request/RequestClient' export const getAuthCodeForSasjs = async ( requestClient: RequestClient, username: string, - password: string, - clientId: string + password: string ) => { const url = '/SASjsApi/auth/authorize' - const data = { username, password, clientId } + const data = { username, password } const { code: authCode } = await requestClient .post<{ code: string }>(url, data, undefined) diff --git a/src/auth/spec/getAccessTokenForSasjs.spec.ts b/src/auth/spec/getAccessTokenForSasjs.spec.ts index 075d9b9..8792a25 100644 --- a/src/auth/spec/getAccessTokenForSasjs.spec.ts +++ b/src/auth/spec/getAccessTokenForSasjs.spec.ts @@ -22,15 +22,11 @@ describe('getAccessTokenForSasjs', () => { Promise.resolve({ result: mockSasjsAuthResponse, etag: '' }) ) - await getAccessTokenForSasjs( - requestClient, - authConfig.client, - authConfig.refresh_token - ) + await getAccessTokenForSasjs(requestClient, authConfig.refresh_token) expect(requestClient.post).toHaveBeenCalledWith( '/SASjsApi/auth/token', - { clientId: authConfig.client, code: authConfig.refresh_token }, + { code: authConfig.refresh_token }, undefined ) }) @@ -51,7 +47,6 @@ describe('getAccessTokenForSasjs', () => { const error = await getAccessTokenForSasjs( requestClient, - authConfig.client, authConfig.refresh_token ).catch((e) => e) From a4cd320272113fc90d6d97851abf3ded45d08ada Mon Sep 17 00:00:00 2001 From: Mihajlo Date: Mon, 9 May 2022 15:47:24 +0200 Subject: [PATCH 2/6] chore: utils import fix --- src/utils/convertToCsv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/convertToCsv.ts b/src/utils/convertToCsv.ts index 2211cd8..62cf613 100644 --- a/src/utils/convertToCsv.ts +++ b/src/utils/convertToCsv.ts @@ -1,4 +1,4 @@ -import { isSpecialMissing } from '@sasjs/utils' +import { isSpecialMissing } from '@sasjs/utils/input/validators' /** * Converts the given JSON object array to a CSV string. From f7bd63ee7f920b05f501240bd732557d2e53f678 Mon Sep 17 00:00:00 2001 From: Mihajlo Date: Mon, 9 May 2022 16:05:50 +0200 Subject: [PATCH 3/6] chore: removing clientid --- src/SASjs.ts | 2 +- src/SASjsApiClient.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/SASjs.ts b/src/SASjs.ts index 3ccbc7f..4fbc183 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -486,7 +486,7 @@ export default class SASjs { ]) if (this.sasjsConfig.serverType === ServerType.Sasjs) - return await this.sasJSApiClient!.getAccessToken(clientId, authCode) + return await this.sasJSApiClient!.getAccessToken(authCode) return await this.sasViyaApiClient!.getAccessToken( clientId, diff --git a/src/SASjsApiClient.ts b/src/SASjsApiClient.ts index 3d37f18..b1cc454 100644 --- a/src/SASjsApiClient.ts +++ b/src/SASjsApiClient.ts @@ -101,7 +101,6 @@ export class SASjsApiClient { * @param authCode - the auth code received from the server. */ public async getAccessToken( - clientId: string, authCode: string ): Promise { return getAccessTokenForSasjs(this.requestClient, authCode) @@ -124,7 +123,6 @@ export class SASjsApiClient { public async getAuthCode( username: string, password: string, - clientId: string ) { return getAuthCodeForSasjs(this.requestClient, username, password) } From 5d2f1d306a04586db989cd9a625ca00f2e9fb32f Mon Sep 17 00:00:00 2001 From: Mihajlo Date: Mon, 9 May 2022 16:08:49 +0200 Subject: [PATCH 4/6] style: lint --- src/SASjsApiClient.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/SASjsApiClient.ts b/src/SASjsApiClient.ts index b1cc454..51ced0f 100644 --- a/src/SASjsApiClient.ts +++ b/src/SASjsApiClient.ts @@ -100,9 +100,7 @@ export class SASjsApiClient { * @param clientId - the client ID to authenticate with. * @param authCode - the auth code received from the server. */ - public async getAccessToken( - authCode: string - ): Promise { + public async getAccessToken(authCode: string): Promise { return getAccessTokenForSasjs(this.requestClient, authCode) } @@ -120,10 +118,7 @@ export class SASjsApiClient { * @param password - a string representing the password. * @param clientId - the client ID to authenticate with. */ - public async getAuthCode( - username: string, - password: string, - ) { + public async getAuthCode(username: string, password: string) { return getAuthCodeForSasjs(this.requestClient, username, password) } } From 10c72e6483392a9b5e90db41ee5afd95d28b379b Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Wed, 11 May 2022 19:07:30 +0500 Subject: [PATCH 5/6] fix(login): making login requet with CSRF for SASJS server --- src/SASjs.ts | 9 ------ src/auth/AuthManager.ts | 65 +++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 50 deletions(-) diff --git a/src/SASjs.ts b/src/SASjs.ts index 4fbc183..59fe1a4 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -592,15 +592,6 @@ export default class SASjs { 'A username and password are required when using the default login mechanism.' ) - if (this.sasjsConfig.serverType === ServerType.Sasjs) { - if (!clientId) - throw new Error( - 'A username, password and clientId are required when using the default login mechanism with server type SASJS.' - ) - - return this.authManager!.logInSasjs(username, password) - } - return this.authManager!.logIn(username, password) } diff --git a/src/auth/AuthManager.ts b/src/auth/AuthManager.ts index 4568af3..b78ecae 100644 --- a/src/auth/AuthManager.ts +++ b/src/auth/AuthManager.ts @@ -83,34 +83,6 @@ export class AuthManager { return { isLoggedIn: false, userName: '' } } - /** - * Logs into the SAS server with the supplied credentials. - * @param userName - a string representing the username. - * @param password - a string representing the password. - * @param clientId - a string representing the client ID. - * @returns - a boolean `isLoggedin` and a string `username` - */ - public async logInSasjs( - username: string, - password: string - ): Promise { - const isLoggedIn = await this.sendLoginRequestSasjs(username, password) - .then((res) => { - this.userName = username - this.requestClient.saveLocalStorageToken( - res.access_token, - res.refresh_token - ) - return true - }) - .catch(() => false) - - return { - isLoggedIn, - userName: this.userName - } - } - /** * Logs into the SAS server with the supplied credentials. * @param username - a string representing the username. @@ -147,7 +119,7 @@ export class AuthManager { let loginResponse = await this.sendLoginRequest(loginForm, loginParams) - let isLoggedIn = isLogInSuccess(loginResponse) + let isLoggedIn = isLogInSuccess(this.serverType, loginResponse) if (!isLoggedIn) { if (isCredentialsVerifyError(loginResponse)) { @@ -191,6 +163,17 @@ export class AuthManager { loginForm: { [key: string]: any }, loginParams: { [key: string]: any } ) { + if (this.serverType === ServerType.Sasjs) { + const { username, password } = loginParams + const { result: loginResponse } = await this.requestClient.post( + this.loginUrl, + { username, password }, + undefined + ) + + return loginResponse + } + for (const key in loginForm) { loginParams[key] = loginForm[key] } @@ -210,14 +193,6 @@ export class AuthManager { return loginResponse } - private async sendLoginRequestSasjs(username: string, password: string) { - const authCode = await getAuthCodeForSasjs( - this.requestClient, - username, - password - ) - return getAccessTokenForSasjs(this.requestClient, authCode) - } /** * Checks whether a session is active, or login is required. * @returns - a promise which resolves with an object containing three values @@ -238,8 +213,7 @@ export class AuthManager { //Residue can happen in case of session expiration await this.logOut() - if (this.serverType !== ServerType.Sasjs) - loginForm = await this.getNewLoginForm() + loginForm = await this.getNewLoginForm() } return Promise.resolve({ @@ -250,6 +224,12 @@ export class AuthManager { } private async getNewLoginForm() { + if (this.serverType === ServerType.Sasjs) { + // server will be sending CSRF cookie, + // http client will use it automatically + return this.requestClient.get('/', undefined) + } + const { result: formResponse } = await this.requestClient.get( this.loginUrl.replace('.do', ''), undefined, @@ -374,5 +354,8 @@ const isCredentialsVerifyError = (response: string): boolean => response ) -const isLogInSuccess = (response: string): boolean => - /You have signed in/gm.test(response) +const isLogInSuccess = (serverType: ServerType, response: any): boolean => { + if (serverType === ServerType.Sasjs) return response?.loggedin + + return /You have signed in/gm.test(response) +} From b8ea618f1eab0cd6b86061c23057af8a5e4db90a Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Wed, 11 May 2022 19:22:01 +0500 Subject: [PATCH 6/6] fix: removed getAuthCode function --- src/SASjs.ts | 2 +- src/SASjsApiClient.ts | 18 ++++-------- src/auth/AuthManager.ts | 2 -- src/auth/getAccessTokenForSasjs.ts | 2 ++ src/auth/getAuthCodeForSasjs.ts | 30 -------------------- src/auth/spec/getAccessTokenForSasjs.spec.ts | 9 ++++-- 6 files changed, 15 insertions(+), 48 deletions(-) delete mode 100644 src/auth/getAuthCodeForSasjs.ts diff --git a/src/SASjs.ts b/src/SASjs.ts index 59fe1a4..01c00b5 100644 --- a/src/SASjs.ts +++ b/src/SASjs.ts @@ -486,7 +486,7 @@ export default class SASjs { ]) if (this.sasjsConfig.serverType === ServerType.Sasjs) - return await this.sasJSApiClient!.getAccessToken(authCode) + return await this.sasJSApiClient!.getAccessToken(clientId, authCode) return await this.sasViyaApiClient!.getAccessToken( clientId, diff --git a/src/SASjsApiClient.ts b/src/SASjsApiClient.ts index 51ced0f..e0d8955 100644 --- a/src/SASjsApiClient.ts +++ b/src/SASjsApiClient.ts @@ -3,7 +3,6 @@ import { ExecutionQuery } from './types' import { RequestClient } from './request/RequestClient' import { getAccessTokenForSasjs } from './auth/getAccessTokenForSasjs' import { refreshTokensForSasjs } from './auth/refreshTokensForSasjs' -import { getAuthCodeForSasjs } from './auth/getAuthCodeForSasjs' import { parseWeboutResponse } from './utils' import { getTokens } from './auth/getTokens' @@ -100,8 +99,11 @@ export class SASjsApiClient { * @param clientId - the client ID to authenticate with. * @param authCode - the auth code received from the server. */ - public async getAccessToken(authCode: string): Promise { - return getAccessTokenForSasjs(this.requestClient, authCode) + public async getAccessToken( + clientId: string, + authCode: string + ): Promise { + return getAccessTokenForSasjs(this.requestClient, clientId, authCode) } /** @@ -111,16 +113,6 @@ export class SASjsApiClient { public async refreshTokens(refreshToken: string): Promise { return refreshTokensForSasjs(this.requestClient, refreshToken) } - - /** - * Performs a login authenticate and returns an auth code for the given client. - * @param username - a string representing the username. - * @param password - a string representing the password. - * @param clientId - the client ID to authenticate with. - */ - public async getAuthCode(username: string, password: string) { - return getAuthCodeForSasjs(this.requestClient, username, password) - } } // todo move to sasjs/utils diff --git a/src/auth/AuthManager.ts b/src/auth/AuthManager.ts index b78ecae..b541c26 100644 --- a/src/auth/AuthManager.ts +++ b/src/auth/AuthManager.ts @@ -2,8 +2,6 @@ import { ServerType } from '@sasjs/utils/types' import { RequestClient } from '../request/RequestClient' import { LoginOptions, LoginResult } from '../types/Login' import { serialize } from '../utils' -import { getAccessTokenForSasjs } from './getAccessTokenForSasjs' -import { getAuthCodeForSasjs } from './getAuthCodeForSasjs' import { openWebPage } from './openWebPage' import { verifySas9Login } from './verifySas9Login' import { verifySasViyaLogin } from './verifySasViyaLogin' diff --git a/src/auth/getAccessTokenForSasjs.ts b/src/auth/getAccessTokenForSasjs.ts index 57cc4bd..7b080bf 100644 --- a/src/auth/getAccessTokenForSasjs.ts +++ b/src/auth/getAccessTokenForSasjs.ts @@ -9,10 +9,12 @@ import { RequestClient } from '../request/RequestClient' */ export async function getAccessTokenForSasjs( requestClient: RequestClient, + clientId: string, authCode: string ) { const url = '/SASjsApi/auth/token' const data = { + clientId, code: authCode } diff --git a/src/auth/getAuthCodeForSasjs.ts b/src/auth/getAuthCodeForSasjs.ts deleted file mode 100644 index 4b99414..0000000 --- a/src/auth/getAuthCodeForSasjs.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { prefixMessage } from '@sasjs/utils/error' -import { RequestClient } from '../request/RequestClient' - -/** - * Performs a login authenticate and returns an auth code for the given client. - * @param requestClient - the pre-configured HTTP request client - * @param username - a string representing the username. - * @param password - a string representing the password. - * @param clientId - the client ID to authenticate with. - */ -export const getAuthCodeForSasjs = async ( - requestClient: RequestClient, - username: string, - password: string -) => { - const url = '/SASjsApi/auth/authorize' - const data = { username, password } - - const { code: authCode } = await requestClient - .post<{ code: string }>(url, data, undefined) - .then((res) => res.result) - .catch((err) => { - throw prefixMessage( - err, - 'Error while authenticating with provided username, password and clientId. ' - ) - }) - - return authCode -} diff --git a/src/auth/spec/getAccessTokenForSasjs.spec.ts b/src/auth/spec/getAccessTokenForSasjs.spec.ts index 8792a25..075d9b9 100644 --- a/src/auth/spec/getAccessTokenForSasjs.spec.ts +++ b/src/auth/spec/getAccessTokenForSasjs.spec.ts @@ -22,11 +22,15 @@ describe('getAccessTokenForSasjs', () => { Promise.resolve({ result: mockSasjsAuthResponse, etag: '' }) ) - await getAccessTokenForSasjs(requestClient, authConfig.refresh_token) + await getAccessTokenForSasjs( + requestClient, + authConfig.client, + authConfig.refresh_token + ) expect(requestClient.post).toHaveBeenCalledWith( '/SASjsApi/auth/token', - { code: authConfig.refresh_token }, + { clientId: authConfig.client, code: authConfig.refresh_token }, undefined ) }) @@ -47,6 +51,7 @@ describe('getAccessTokenForSasjs', () => { const error = await getAccessTokenForSasjs( requestClient, + authConfig.client, authConfig.refresh_token ).catch((e) => e)