mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 01:14:36 +00:00
Merge pull request #761 from sasjs/introduced-user-long-name
Introduced user long name
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import { ServerType } from '@sasjs/utils/types'
|
||||
import { RequestClient } from '../request/RequestClient'
|
||||
import { LoginOptions, LoginResult } from '../types/Login'
|
||||
import { LoginOptions, LoginResult, LoginResultInternal } from '../types/Login'
|
||||
import { serialize } from '../utils'
|
||||
import { extractUserNameSas9 } from '../utils/sas9/extractUserNameSas9'
|
||||
import { extractUserLongNameSas9 } from '../utils/sas9/extractUserLongNameSas9'
|
||||
import { openWebPage } from './openWebPage'
|
||||
import { verifySas9Login } from './verifySas9Login'
|
||||
import { verifySasViyaLogin } from './verifySasViyaLogin'
|
||||
|
||||
export class AuthManager {
|
||||
public userName = ''
|
||||
public userLongName = ''
|
||||
private loginUrl: string
|
||||
private logoutUrl: string
|
||||
private redirectedLoginUrl = `/SASLogon/home`
|
||||
@@ -34,15 +35,19 @@ export class AuthManager {
|
||||
public async redirectedLogIn({
|
||||
onLoggedOut
|
||||
}: LoginOptions): Promise<LoginResult> {
|
||||
const { isLoggedIn: isLoggedInAlready, userName: currentSessionUsername } =
|
||||
await this.fetchUserName()
|
||||
const {
|
||||
isLoggedIn: isLoggedInAlready,
|
||||
userName: currentSessionUserName,
|
||||
userLongName: currentSessionUserLongName
|
||||
} = await this.fetchUserName()
|
||||
|
||||
if (isLoggedInAlready) {
|
||||
await this.loginCallback()
|
||||
|
||||
return {
|
||||
isLoggedIn: true,
|
||||
userName: currentSessionUsername
|
||||
userName: currentSessionUserName,
|
||||
userLongName: currentSessionUserLongName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +62,7 @@ export class AuthManager {
|
||||
)
|
||||
|
||||
if (!loginPopup) {
|
||||
return { isLoggedIn: false, userName: '' }
|
||||
return { isLoggedIn: false, userName: '', userLongName: '' }
|
||||
}
|
||||
|
||||
const { isLoggedIn } =
|
||||
@@ -72,14 +77,14 @@ export class AuthManager {
|
||||
await this.performCASSecurityCheck()
|
||||
}
|
||||
|
||||
const { userName } = await this.fetchUserName()
|
||||
const { userName, userLongName } = await this.fetchUserName()
|
||||
|
||||
await this.loginCallback()
|
||||
|
||||
return { isLoggedIn: true, userName }
|
||||
return { isLoggedIn: true, userName, userLongName }
|
||||
}
|
||||
|
||||
return { isLoggedIn: false, userName: '' }
|
||||
return { isLoggedIn: false, userName: '', userLongName: '' }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,27 +99,26 @@ export class AuthManager {
|
||||
username,
|
||||
password
|
||||
}
|
||||
this.userName = ''
|
||||
this.userLongName = ''
|
||||
|
||||
let {
|
||||
isLoggedIn: isLoggedInAlready,
|
||||
loginForm,
|
||||
userName: currentSessionUsername
|
||||
userLongName: currentSessionUserLongName
|
||||
} = await this.checkSession()
|
||||
|
||||
if (isLoggedInAlready) {
|
||||
if (currentSessionUsername === loginParams.username) {
|
||||
await this.loginCallback()
|
||||
await this.loginCallback()
|
||||
|
||||
this.userName = currentSessionUsername!
|
||||
return {
|
||||
isLoggedIn: true,
|
||||
userName: this.userName
|
||||
}
|
||||
} else {
|
||||
await this.logOut()
|
||||
loginForm = await this.getNewLoginForm()
|
||||
this.userName = loginParams.username
|
||||
this.userLongName = currentSessionUserLongName
|
||||
return {
|
||||
isLoggedIn: true,
|
||||
userName: this.userName,
|
||||
userLongName: this.userLongName
|
||||
}
|
||||
} else this.userName = ''
|
||||
}
|
||||
|
||||
let loginResponse = await this.sendLoginRequest(loginForm, loginParams)
|
||||
|
||||
@@ -129,10 +133,7 @@ export class AuthManager {
|
||||
|
||||
const res = await this.checkSession()
|
||||
isLoggedIn = res.isLoggedIn
|
||||
|
||||
if (isLoggedIn) this.userName = res.userName
|
||||
} else {
|
||||
this.userName = loginParams.username
|
||||
this.userLongName = res.userLongName
|
||||
}
|
||||
|
||||
if (isLoggedIn) {
|
||||
@@ -141,11 +142,13 @@ export class AuthManager {
|
||||
}
|
||||
|
||||
this.loginCallback()
|
||||
} else this.userName = ''
|
||||
this.userName = loginParams.username
|
||||
}
|
||||
|
||||
return {
|
||||
isLoggedIn,
|
||||
userName: this.userName
|
||||
userName: this.userName,
|
||||
userLongName: this.userLongName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,15 +199,12 @@ export class AuthManager {
|
||||
* Checks whether a session is active, or login is required.
|
||||
* @returns - a promise which resolves with an object containing three values
|
||||
* - a boolean `isLoggedIn`
|
||||
* - a string `userName` and
|
||||
* - a string `userName`,
|
||||
* - a string `userFullName` and
|
||||
* - a form `loginForm` if not loggedin.
|
||||
*/
|
||||
public async checkSession(): Promise<{
|
||||
isLoggedIn: boolean
|
||||
userName: string
|
||||
loginForm?: any
|
||||
}> {
|
||||
const { isLoggedIn, userName } = await this.fetchUserName()
|
||||
public async checkSession(): Promise<LoginResultInternal> {
|
||||
const { isLoggedIn, userName, userLongName } = await this.fetchUserName()
|
||||
let loginForm = null
|
||||
|
||||
if (!isLoggedIn) {
|
||||
@@ -217,7 +217,8 @@ export class AuthManager {
|
||||
|
||||
return Promise.resolve({
|
||||
isLoggedIn,
|
||||
userName: userName.toLowerCase(),
|
||||
userName,
|
||||
userLongName,
|
||||
loginForm
|
||||
})
|
||||
}
|
||||
@@ -246,10 +247,7 @@ export class AuthManager {
|
||||
return await this.getLoginForm(formResponse)
|
||||
}
|
||||
|
||||
private async fetchUserName(): Promise<{
|
||||
isLoggedIn: boolean
|
||||
userName: string
|
||||
}> {
|
||||
private async fetchUserName(): Promise<LoginResult> {
|
||||
const url =
|
||||
this.serverType === ServerType.SasViya
|
||||
? `${this.serverUrl}/identities/users/@currentUser`
|
||||
@@ -264,15 +262,19 @@ export class AuthManager {
|
||||
})
|
||||
|
||||
const isLoggedIn = loginResponse !== 'authErr'
|
||||
const userName = isLoggedIn ? this.extractUserName(loginResponse) : ''
|
||||
|
||||
if (!isLoggedIn) {
|
||||
//We will logout to make sure cookies are removed and login form is presented
|
||||
//Residue can happen in case of session expiration
|
||||
await this.logOut()
|
||||
return { isLoggedIn, userName: '', userLongName: '' }
|
||||
}
|
||||
|
||||
return { isLoggedIn, userName }
|
||||
return {
|
||||
isLoggedIn,
|
||||
userName: this.extractUserName(loginResponse),
|
||||
userLongName: this.extractUserLongName(loginResponse)
|
||||
}
|
||||
}
|
||||
|
||||
private extractUserName = (response: any): string => {
|
||||
@@ -281,7 +283,7 @@ export class AuthManager {
|
||||
return response?.id
|
||||
|
||||
case ServerType.Sas9:
|
||||
return extractUserNameSas9(response)
|
||||
return ''
|
||||
|
||||
case ServerType.Sasjs:
|
||||
return response?.username
|
||||
@@ -292,6 +294,23 @@ export class AuthManager {
|
||||
}
|
||||
}
|
||||
|
||||
private extractUserLongName = (response: any): string => {
|
||||
switch (this.serverType) {
|
||||
case ServerType.SasViya:
|
||||
return response?.name
|
||||
|
||||
case ServerType.Sas9:
|
||||
return extractUserLongNameSas9(response)
|
||||
|
||||
case ServerType.Sasjs:
|
||||
return response?.displayName
|
||||
|
||||
default:
|
||||
console.error('Server Type not found in extractUserName function')
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
private getLoginForm(response: any) {
|
||||
const pattern: RegExp = /<form.+action="(.*Logon[^"]*).*>/
|
||||
const matches = pattern.exec(response)
|
||||
|
||||
@@ -20,6 +20,7 @@ describe('AuthManager', () => {
|
||||
const serverUrl = 'http://test-server.com'
|
||||
const serverType = ServerType.SasViya
|
||||
const userName = 'test-username'
|
||||
const userLongName = 'test-user long name'
|
||||
const password = 'test-password'
|
||||
const requestClient = new RequestClient(serverUrl)
|
||||
|
||||
@@ -73,6 +74,7 @@ describe('AuthManager', () => {
|
||||
Promise.resolve({
|
||||
isLoggedIn: true,
|
||||
userName,
|
||||
userLongName,
|
||||
loginForm: 'test'
|
||||
})
|
||||
)
|
||||
@@ -95,49 +97,24 @@ describe('AuthManager', () => {
|
||||
Promise.resolve({
|
||||
isLoggedIn: true,
|
||||
userName: 'someOtherUsername',
|
||||
userLongName: 'someOtherUser Long name',
|
||||
loginForm: null
|
||||
})
|
||||
)
|
||||
jest
|
||||
.spyOn(authManager, 'logOut')
|
||||
.mockImplementation(() => Promise.resolve(true))
|
||||
jest.spyOn(authManager, 'logOut')
|
||||
|
||||
jest
|
||||
.spyOn<any, any>(authManager, 'getNewLoginForm')
|
||||
.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
name: 'test'
|
||||
})
|
||||
)
|
||||
mockedAxios.post.mockImplementation(() =>
|
||||
Promise.resolve({ data: mockLoginSuccessResponse })
|
||||
)
|
||||
jest.spyOn<any, any>(authManager, 'getNewLoginForm')
|
||||
jest.spyOn<any, any>(authManager, 'sendLoginRequest')
|
||||
|
||||
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(authManager.logOut).toHaveBeenCalledTimes(0)
|
||||
expect(authManager['getNewLoginForm']).toHaveBeenCalledTimes(0)
|
||||
expect(authManager['sendLoginRequest']).toHaveBeenCalledTimes(0)
|
||||
expect(authCallback).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
@@ -152,6 +129,7 @@ describe('AuthManager', () => {
|
||||
Promise.resolve({
|
||||
isLoggedIn: false,
|
||||
userName: '',
|
||||
userLongName: '',
|
||||
loginForm: { name: 'test' }
|
||||
})
|
||||
)
|
||||
@@ -196,6 +174,7 @@ describe('AuthManager', () => {
|
||||
Promise.resolve({
|
||||
isLoggedIn: false,
|
||||
userName: '',
|
||||
userLongName: '',
|
||||
loginForm: { name: 'test' }
|
||||
})
|
||||
)
|
||||
@@ -245,6 +224,7 @@ describe('AuthManager', () => {
|
||||
Promise.resolve({
|
||||
isLoggedIn: false,
|
||||
userName: '',
|
||||
userLongName: '',
|
||||
loginForm: { name: 'test' }
|
||||
})
|
||||
)
|
||||
@@ -290,6 +270,7 @@ describe('AuthManager', () => {
|
||||
Promise.resolve({
|
||||
isLoggedIn: false,
|
||||
userName: 'test',
|
||||
userLongName: 'test Long name',
|
||||
loginForm: { name: 'test' }
|
||||
})
|
||||
)
|
||||
@@ -560,43 +541,8 @@ describe('AuthManager', () => {
|
||||
)
|
||||
})
|
||||
|
||||
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,
|
||||
@@ -612,7 +558,8 @@ describe('AuthManager', () => {
|
||||
|
||||
const response = await authManager.checkSession()
|
||||
expect(response.isLoggedIn).toBeTruthy()
|
||||
expect(response.userName).toEqual(username)
|
||||
expect(response.userName).toEqual('')
|
||||
expect(response.userLongName).toEqual(fullname)
|
||||
expect(mockedAxios.get).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
`http://test-server.com/SASStoredProcess`,
|
||||
|
||||
@@ -5,4 +5,11 @@ export interface LoginOptions {
|
||||
export interface LoginResult {
|
||||
isLoggedIn: boolean
|
||||
userName: string
|
||||
userLongName: string
|
||||
}
|
||||
export interface LoginResultInternal {
|
||||
isLoggedIn: boolean
|
||||
userName: string
|
||||
userLongName: string
|
||||
loginForm?: any
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
const dictionary = ['Log Off']
|
||||
|
||||
/**
|
||||
* Extracts username assuming the first word after "title" means log off if not found otherwise in the dictionary
|
||||
* Extracts user full name assuming the first word after "title" means log off if not found otherwise in the dictionary
|
||||
* @param response SAS response content
|
||||
* @returns username
|
||||
* @returns user full name
|
||||
*/
|
||||
export const extractUserNameSas9 = (response: string) => {
|
||||
export const extractUserLongNameSas9 = (response: string) => {
|
||||
const regex = /"title":\s?".*?"/
|
||||
|
||||
const matched = response?.match(regex)
|
||||
@@ -27,17 +27,5 @@ export const extractUserNameSas9 = (response: string) => {
|
||||
})
|
||||
|
||||
//Cut only name
|
||||
let username = fullName.slice(breakIndex, -1).trim()
|
||||
|
||||
//Create username by SAS method - first 3 chars of every word lowercase
|
||||
const usernameSplit = username.split(' ')
|
||||
username = usernameSplit
|
||||
.map((name: string) =>
|
||||
usernameSplit.length > 1
|
||||
? name.slice(0, 3).toLowerCase()
|
||||
: name.toLowerCase()
|
||||
)
|
||||
.join('')
|
||||
|
||||
return username
|
||||
return fullName.slice(breakIndex, -1).trim()
|
||||
}
|
||||
@@ -1,32 +1,32 @@
|
||||
import { extractUserNameSas9 } from '../sas9/extractUserNameSas9'
|
||||
import { extractUserLongNameSas9 } from '../sas9/extractUserLongNameSas9'
|
||||
|
||||
describe('Extract username SAS9 English - two word logout handled language', () => {
|
||||
const logoutWord = 'Log Off'
|
||||
|
||||
it('should return username with space after colon', () => {
|
||||
const response = ` "title": "${logoutWord} SAS User One",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('sasuseone')
|
||||
expect(username).toEqual('SAS User One')
|
||||
})
|
||||
|
||||
it('should return username without space after colon', () => {
|
||||
const response = ` "title":"${logoutWord} SAS User One",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('sasuseone')
|
||||
expect(username).toEqual('SAS User One')
|
||||
})
|
||||
|
||||
it('should return username with one word user name', () => {
|
||||
const response = ` "title": "${logoutWord} SasUserOne",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('sasuserone')
|
||||
expect(username).toEqual('SasUserOne')
|
||||
})
|
||||
|
||||
it('should return username unknown', () => {
|
||||
const response = ` invalid",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('unknown')
|
||||
})
|
||||
@@ -37,28 +37,28 @@ describe('Extract username SAS9 two word logout unhandled language', () => {
|
||||
|
||||
it('should return username with space after colon', () => {
|
||||
const response = ` "title": "${logoutWord} SAS User One",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('outsasuseone')
|
||||
expect(username).toEqual('out SAS User One')
|
||||
})
|
||||
|
||||
it('should return username without space after colon', () => {
|
||||
const response = ` "title":"${logoutWord} SAS User One",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('outsasuseone')
|
||||
expect(username).toEqual('out SAS User One')
|
||||
})
|
||||
|
||||
it('should return username with one word user name', () => {
|
||||
const response = ` "title": "${logoutWord} SasUserOne",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('outsas')
|
||||
expect(username).toEqual('out SasUserOne')
|
||||
})
|
||||
|
||||
it('should return username unknown', () => {
|
||||
const response = ` invalid",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('unknown')
|
||||
})
|
||||
@@ -69,28 +69,28 @@ describe('Extract username SAS9 Spanish - one word logout languages', () => {
|
||||
|
||||
it('should return username with space after colon', () => {
|
||||
const response = ` "title": "${logoutWord} SAS User One",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('sasuseone')
|
||||
expect(username).toEqual('SAS User One')
|
||||
})
|
||||
|
||||
it('should return username without space after colon', () => {
|
||||
const response = ` "title":"${logoutWord} SAS User One",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('sasuseone')
|
||||
expect(username).toEqual('SAS User One')
|
||||
})
|
||||
|
||||
it('should return username with one word user name', () => {
|
||||
const response = ` "title": "${logoutWord} SasUserOne",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('sasuserone')
|
||||
expect(username).toEqual('SasUserOne')
|
||||
})
|
||||
|
||||
it('should return username unknown', () => {
|
||||
const response = ` invalid",`
|
||||
const username = extractUserNameSas9(response)
|
||||
const username = extractUserLongNameSas9(response)
|
||||
|
||||
expect(username).toEqual('unknown')
|
||||
})
|
||||
Reference in New Issue
Block a user