1
0
mirror of https://github.com/sasjs/adapter.git synced 2025-12-11 01:14:36 +00:00

test(AuthManager): improved coverage

This commit is contained in:
Saad Jutt
2021-09-09 04:37:30 +05:00
parent 0ea6e839ac
commit 3ae0809ee5
3 changed files with 515 additions and 48 deletions

View File

@@ -66,12 +66,7 @@ export class AuthManager {
if (isLoggedIn) {
if (this.serverType === ServerType.Sas9) {
const casAuthenticationUrl = `${this.serverUrl}/SASStoredProcess/j_spring_cas_security_check`
await this.requestClient.get<string>(
`/SASLogon/login?service=${casAuthenticationUrl}`,
undefined
)
await this.performCASSecurityCheck()
}
const { userName } = await this.fetchUserName()
@@ -113,7 +108,8 @@ export class AuthManager {
userName: this.userName
}
} else {
this.logOut()
await this.logOut()
loginForm = await this.getNewLoginForm()
}
} else this.userName = ''
@@ -138,12 +134,7 @@ export class AuthManager {
if (isLoggedIn) {
if (this.serverType === ServerType.Sas9) {
const casAuthenticationUrl = `${this.serverUrl}/SASStoredProcess/j_spring_cas_security_check`
await this.requestClient.get<string>(
`/SASLogon/login?service=${casAuthenticationUrl}`,
undefined
)
await this.performCASSecurityCheck()
}
this.loginCallback()
@@ -155,6 +146,15 @@ export class AuthManager {
}
}
private async performCASSecurityCheck() {
const casAuthenticationUrl = `${this.serverUrl}/SASStoredProcess/j_spring_cas_security_check`
await this.requestClient.get<string>(
`/SASLogon/login?service=${casAuthenticationUrl}`,
undefined
)
}
private async sendLoginRequest(
loginForm: { [key: string]: any },
loginParams: { [key: string]: any }
@@ -198,13 +198,7 @@ export class AuthManager {
//Residue can happen in case of session expiration
await this.logOut()
const { result: formResponse } = await this.requestClient.get<string>(
this.loginUrl.replace('.do', ''),
undefined,
'text/plain'
)
loginForm = await this.getLoginForm(formResponse)
loginForm = await this.getNewLoginForm()
}
return Promise.resolve({
@@ -214,6 +208,16 @@ export class AuthManager {
})
}
private async getNewLoginForm() {
const { result: formResponse } = await this.requestClient.get<string>(
this.loginUrl.replace('.do', ''),
undefined,
'text/plain'
)
return await this.getLoginForm(formResponse)
}
private async fetchUserName(): Promise<{
isLoggedIn: boolean
userName: string

View File

@@ -10,6 +10,7 @@ import {
import { serialize } from '../../utils'
import * as openWebPageModule from '../openWebPage'
import * as verifySasViyaLoginModule from '../verifySasViyaLogin'
import * as verifySas9LoginModule from '../verifySas9Login'
import { RequestClient } from '../../request/RequestClient'
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
@@ -83,7 +84,64 @@ describe('AuthManager', () => {
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should post a login request to the server if not logged in', async () => {
it('should post a login request to the server when already logged in with other username', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
Promise.resolve({
isLoggedIn: true,
userName: 'someOtherUsername',
loginForm: null
})
)
jest
.spyOn(authManager, 'logOut')
.mockImplementation(() => Promise.resolve(true))
jest
.spyOn<any, any>(authManager, 'getNewLoginForm')
.mockImplementation(() =>
Promise.resolve({
name: 'test'
})
)
mockedAxios.post.mockImplementation(() =>
Promise.resolve({ data: mockLoginSuccessResponse })
)
const loginResponse = await authManager.logIn(userName, password)
expect(loginResponse.isLoggedIn).toBeTruthy()
expect(loginResponse.userName).toEqual(userName)
const loginParams = serialize({
_service: 'default',
username: userName,
password,
name: 'test'
})
expect(authCallback).toHaveBeenCalledTimes(1)
expect(authManager.logOut).toHaveBeenCalledTimes(1)
expect(authManager['getNewLoginForm']).toHaveBeenCalledTimes(1)
expect(mockedAxios.post).toHaveBeenCalledWith(
`/SASLogon/login`,
loginParams,
{
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: '*/*'
}
}
)
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should post a login request to the server when not logged in', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
@@ -126,6 +184,98 @@ describe('AuthManager', () => {
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should post a login & a cas_security request to the SAS9 server when not logged in', async () => {
const serverType = ServerType.Sas9
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
Promise.resolve({
isLoggedIn: false,
userName: '',
loginForm: { name: 'test' }
})
)
mockedAxios.post.mockImplementation(() =>
Promise.resolve({ data: mockLoginSuccessResponse })
)
mockedAxios.get.mockImplementation(() => Promise.resolve({ status: 200 }))
const loginResponse = await authManager.logIn(userName, password)
expect(loginResponse.isLoggedIn).toBeTruthy()
expect(loginResponse.userName).toEqual(userName)
const loginParams = serialize({
_service: 'default',
username: userName,
password,
name: 'test'
})
expect(mockedAxios.post).toHaveBeenCalledWith(
`/SASLogon/login`,
loginParams,
{
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: '*/*'
}
}
)
const casAuthenticationUrl = `${serverUrl}/SASStoredProcess/j_spring_cas_security_check`
expect(mockedAxios.get).toHaveBeenCalledWith(
`/SASLogon/login?service=${casAuthenticationUrl}`,
getHeadersJson
)
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should return empty username if unable to logged in', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest.spyOn(authManager, 'checkSession').mockImplementation(() =>
Promise.resolve({
isLoggedIn: false,
userName: '',
loginForm: { name: 'test' }
})
)
mockedAxios.post.mockImplementation(() =>
Promise.resolve({ data: 'Not Signed in' })
)
const loginResponse = await authManager.logIn(userName, password)
expect(loginResponse.isLoggedIn).toBeFalsy()
expect(loginResponse.userName).toEqual('')
const loginParams = serialize({
_service: 'default',
username: userName,
password,
name: 'test'
})
expect(mockedAxios.post).toHaveBeenCalledWith(
`/SASLogon/login`,
loginParams,
{
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: '*/*'
}
}
)
})
it('should parse and submit the authorisation form when necessary', async () => {
const authManager = new AuthManager(
serverUrl,
@@ -177,6 +327,10 @@ describe('AuthManager', () => {
jest
.spyOn(verifySasViyaLoginModule, 'verifySasViyaLogin')
.mockImplementation(() => Promise.resolve({ isLoggedIn: true }))
jest.mock('../verifySas9Login')
jest
.spyOn(verifySas9LoginModule, 'verifySas9Login')
.mockImplementation(() => Promise.resolve({ isLoggedIn: true }))
})
it('should call the auth callback and return when already logged in', async () => {
@@ -202,7 +356,7 @@ describe('AuthManager', () => {
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should open pop up if not logged in', async () => {
it('should perform login via pop up if not logged in', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
@@ -239,37 +393,282 @@ describe('AuthManager', () => {
undefined
)
expect(authManager['fetchUserName']).toHaveBeenCalledTimes(2)
expect(verifySasViyaLoginModule.verifySasViyaLogin).toHaveBeenCalledTimes(
1
)
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should perform login via pop up if not logged in with server sas9', async () => {
const serverType = ServerType.Sas9
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest
.spyOn<any, any>(authManager, 'fetchUserName')
.mockImplementationOnce(() =>
Promise.resolve({
isLoggedIn: false,
userName: ''
})
)
.mockImplementationOnce(() =>
Promise.resolve({
isLoggedIn: true,
userName
})
)
const loginResponse = await authManager.redirectedLogIn({})
expect(loginResponse.isLoggedIn).toBeTruthy()
expect(loginResponse.userName).toEqual(userName)
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
`/SASLogon/home`,
'SASLogon',
{
width: 500,
height: 600
},
undefined
)
expect(authManager['fetchUserName']).toHaveBeenCalledTimes(2)
expect(verifySas9LoginModule.verifySas9Login).toHaveBeenCalledTimes(1)
expect(authCallback).toHaveBeenCalledTimes(1)
})
it('should return empty username if user unable to re-login via pop up', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest
.spyOn<any, any>(authManager, 'fetchUserName')
.mockImplementationOnce(() =>
Promise.resolve({
isLoggedIn: false,
userName: ''
})
)
.mockImplementationOnce(() =>
Promise.resolve({
isLoggedIn: true,
userName
})
)
jest
.spyOn(verifySasViyaLoginModule, 'verifySasViyaLogin')
.mockImplementation(() => Promise.resolve({ isLoggedIn: false }))
const loginResponse = await authManager.redirectedLogIn({})
expect(loginResponse.isLoggedIn).toBeFalsy()
expect(loginResponse.userName).toEqual('')
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
`/SASLogon/home`,
'SASLogon',
{
width: 500,
height: 600
},
undefined
)
expect(authManager['fetchUserName']).toHaveBeenCalledTimes(1)
expect(authCallback).toHaveBeenCalledTimes(0)
})
it('should return empty username if user rejects to re-login', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
jest
.spyOn<any, any>(authManager, 'fetchUserName')
.mockImplementationOnce(() =>
Promise.resolve({
isLoggedIn: false,
userName: ''
})
)
.mockImplementationOnce(() =>
Promise.resolve({
isLoggedIn: true,
userName
})
)
jest
.spyOn(openWebPageModule, 'openWebPage')
.mockImplementation(() => Promise.resolve(null))
const loginResponse = await authManager.redirectedLogIn({})
expect(loginResponse.isLoggedIn).toBeFalsy()
expect(loginResponse.userName).toEqual('')
expect(openWebPageModule.openWebPage).toHaveBeenCalledWith(
`/SASLogon/home`,
'SASLogon',
{
width: 500,
height: 600
},
undefined
)
expect(authManager['fetchUserName']).toHaveBeenCalledTimes(1)
expect(authCallback).toHaveBeenCalledTimes(0)
})
})
it('should check and return session information if logged in', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
mockedAxios.get.mockImplementation(() =>
Promise.resolve({ data: mockedCurrentUserApi(userName) })
)
describe('checkSession', () => {
it('return session information when logged in', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
mockedAxios.get.mockImplementation(() =>
Promise.resolve({ data: mockedCurrentUserApi(userName) })
)
const response = await authManager.checkSession()
expect(response.isLoggedIn).toBeTruthy()
expect(response.userName).toEqual(userName)
expect(mockedAxios.get).toHaveBeenNthCalledWith(
1,
`http://test-server.com/identities/users/@currentUser`,
{
withCredentials: true,
responseType: 'text',
transformResponse: undefined,
headers: {
Accept: '*/*',
'Content-Type': 'text/plain'
const response = await authManager.checkSession()
expect(response.isLoggedIn).toBeTruthy()
expect(response.userName).toEqual(userName)
expect(mockedAxios.get).toHaveBeenNthCalledWith(
1,
`http://test-server.com/identities/users/@currentUser`,
{
withCredentials: true,
responseType: 'text',
transformResponse: undefined,
headers: {
Accept: '*/*',
'Content-Type': 'text/plain'
}
}
}
)
)
})
it('return session information when logged in - SAS9', async () => {
// username cannot have `-` and cannot be uppercased
const username = 'testusername'
const serverType = ServerType.Sas9
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
mockedAxios.get.mockImplementation(() =>
Promise.resolve({
data: `"title":"Log Off ${username}","url":"javascript: clearFrame(\"/SASStoredProcess/do?_action=logoff\")"' })`
})
)
const response = await authManager.checkSession()
expect(response.isLoggedIn).toBeTruthy()
expect(response.userName).toEqual(username)
expect(mockedAxios.get).toHaveBeenNthCalledWith(
1,
`http://test-server.com/SASStoredProcess`,
{
withCredentials: true,
responseType: 'text',
transformResponse: undefined,
headers: {
Accept: '*/*',
'Content-Type': 'text/plain'
}
}
)
})
it('return session information when logged in - SAS9 - having full name in html', async () => {
const fullname = 'FirstName LastName'
const username = 'firlas'
const serverType = ServerType.Sas9
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
mockedAxios.get.mockImplementation(() =>
Promise.resolve({
data: `"title":"Log Off ${fullname}","url":"javascript: clearFrame(\"/SASStoredProcess/do?_action=logoff\")"' })`
})
)
const response = await authManager.checkSession()
expect(response.isLoggedIn).toBeTruthy()
expect(response.userName).toEqual(username)
expect(mockedAxios.get).toHaveBeenNthCalledWith(
1,
`http://test-server.com/SASStoredProcess`,
{
withCredentials: true,
responseType: 'text',
transformResponse: undefined,
headers: {
Accept: '*/*',
'Content-Type': 'text/plain'
}
}
)
})
it('perform logout when not logged in', async () => {
const authManager = new AuthManager(
serverUrl,
serverType,
requestClient,
authCallback
)
mockedAxios.get
.mockImplementationOnce(() => Promise.resolve({ status: 401 }))
.mockImplementation(() => Promise.resolve({}))
const response = await authManager.checkSession()
expect(response.isLoggedIn).toBeFalsy()
expect(response.userName).toEqual('')
expect(mockedAxios.get).toHaveBeenNthCalledWith(
1,
`http://test-server.com/identities/users/@currentUser`,
{
withCredentials: true,
responseType: 'text',
transformResponse: undefined,
headers: {
Accept: '*/*',
'Content-Type': 'text/plain'
}
}
)
expect(mockedAxios.get).toHaveBeenNthCalledWith(
2,
`/SASLogon/logout.do?`,
getHeadersJson
)
})
})
})
const getHeadersJson = {
withCredentials: true,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
responseType: 'json'
}

View File

@@ -0,0 +1,64 @@
/**
* @jest-environment jsdom
*/
import { openWebPage } from '../openWebPage'
import * as loginPromptModule from '../../utils/loginPrompt'
describe('openWebPage', () => {
const serverUrl = 'http://test-server.com'
describe('window.open is not blocked', () => {
const mockedOpen = jest
.fn()
.mockImplementation(() => ({} as unknown as Window))
const originalOpen = window.open
beforeAll(() => {
window.open = mockedOpen
})
afterAll(() => {
window.open = originalOpen
})
it(`should return new Window popup - using default adapter's dialog`, async () => {
await expect(openWebPage(serverUrl)).resolves.toBeDefined()
expect(mockedOpen).toBeCalled()
})
})
describe('window.open is blocked', () => {
const mockedOpen = jest.fn().mockImplementation(() => null)
const originalOpen = window.open
beforeAll(() => {
window.open = mockedOpen
})
afterAll(() => {
window.open = originalOpen
})
it(`should return new Window popup - using default adapter's dialog`, async () => {
jest.mock('../../utils/loginPrompt')
jest
.spyOn(loginPromptModule, 'openLoginPrompt')
.mockImplementation(() => Promise.resolve(true))
await expect(openWebPage(serverUrl)).resolves.toBeDefined()
expect(loginPromptModule.openLoginPrompt).toBeCalled()
expect(mockedOpen).toBeCalled()
})
it(`should return new Window popup - using frontend's provided onloggedOut`, async () => {
const onLoggedOut = jest
.fn()
.mockImplementation(() => Promise.resolve(true))
await expect(
openWebPage(serverUrl, undefined, undefined, onLoggedOut)
).resolves.toBeDefined()
expect(onLoggedOut).toBeCalled()
expect(mockedOpen).toBeCalled()
})
})
})