From 01ac5c143180287743c2a26d5f821a9306083ceb Mon Sep 17 00:00:00 2001 From: Maxim Laikine <40576301+lamaks@users.noreply.github.com> Date: Wed, 11 Oct 2023 09:35:46 -0700 Subject: [PATCH] Navigate to URL for authentication (#2493) #### Details Navigate to URL for authentication when supported authentication was detected. #### Pull request checklist - [ ] Addresses an existing issue: Fixes #0000 - [x] Added relevant unit test for your changes. (`yarn test`) - [ ] Verified code coverage for the changes made. Check coverage report at: `/test-results/unit/coverage` - [ ] Ran precheckin (`yarn precheckin`) - [x] Validated in an Azure resource group --- .gitignore | 1 + packages/axe-result-converter/package.json | 1 + packages/cli/package.json | 3 +- packages/cli/src/package.json.spec.ts | 9 +++ .../scanner-global-library/open-browser.sh | 76 ++++++++++++++++++ .../resource-authenticator.spec.ts | 78 ++++++++++--------- .../authenticator/resource-authenticator.ts | 50 ++++++++++-- .../src/page-navigator.ts | 60 +++++++------- .../scanner-global-library/src/page.spec.ts | 15 +++- packages/scanner-global-library/src/page.ts | 22 +++++- .../src/scanner/page-scan-processor.ts | 2 +- yarn.lock | 2 +- 12 files changed, 240 insertions(+), 79 deletions(-) create mode 100755 packages/scanner-global-library/open-browser.sh diff --git a/.gitignore b/.gitignore index 44efaecd9..8c795e987 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ node_modules* !.yarn/sdks !.yarn/versions +chrome-user-data/ dist/ dist* drop/ diff --git a/packages/axe-result-converter/package.json b/packages/axe-result-converter/package.json index 185d40bc9..b8d9022ea 100644 --- a/packages/axe-result-converter/package.json +++ b/packages/axe-result-converter/package.json @@ -22,6 +22,7 @@ }, "homepage": "https://github.com/Microsoft/accessibility-insights-service#readme", "devDependencies": { + "@types/fingerprint-generator": "1.0.0", "@types/jest": "^29.5.0", "@types/lodash": "^4.14.182", "@types/node": "^16.18.11", diff --git a/packages/cli/package.json b/packages/cli/package.json index 7ce3083fc..ca4ffc86e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "accessibility-insights-scan", - "version": "2.4.3", + "version": "2.4.4", "description": "This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.", "scripts": { "build": "webpack --config ./webpack.config.js \"$@\"", @@ -29,7 +29,6 @@ "standAlonePackage": "This is a stand-alone package. Do NOT add dependencies to any service packages.", "devDependencies": { "@types/escape-html": "^1.0.2", - "@types/fingerprint-generator": "1.0.0", "@types/jest": "^29.5.0", "@types/lodash": "^4.14.182", "@types/node": "^16.18.11", diff --git a/packages/cli/src/package.json.spec.ts b/packages/cli/src/package.json.spec.ts index 884b28c2e..660b2842c 100644 --- a/packages/cli/src/package.json.spec.ts +++ b/packages/cli/src/package.json.spec.ts @@ -2,16 +2,25 @@ // Licensed under the MIT License. import 'reflect-metadata'; + import { listMonorepoPackageNames } from 'common'; import _ from 'lodash'; import * as packageJson from '../package.json'; +const acceptedMonorepoDependencies = ['accessibility-insights-crawler', 'axe-result-converter', 'common']; + describe('package.json dependencies', () => { const monorepoPackageNames = listMonorepoPackageNames(); const isMonorepoPackage = (packageName: string) => monorepoPackageNames.includes(packageName); const monorepoDevDependencies = Object.keys(packageJson.devDependencies).filter(isMonorepoPackage); const monorepoNonDevDependencies = Object.keys(packageJson.dependencies).filter(isMonorepoPackage); + // We do NOT allow to have any dependencies on service monorepo packages + // since cli package is a purely stand-alone package. + it('does not include any dependencies on service monorepo packages', () => { + expect(monorepoDevDependencies).toEqual(acceptedMonorepoDependencies); + }); + // We don't publish other monorepo packages (eg, "common") to npm, so it's important // that we only depend on them as devDependencies, not dependencies, to avoid consumers // trying to pull down non-published packages. diff --git a/packages/scanner-global-library/open-browser.sh b/packages/scanner-global-library/open-browser.sh new file mode 100755 index 000000000..b6cdc865b --- /dev/null +++ b/packages/scanner-global-library/open-browser.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# Open browser in automation mode + +set -eo pipefail + +exitWithUsageInfo() { + echo " +Usage: ${BASH_SOURCE} -b [-p ] +" + exit 1 +} + +while getopts ":b:p:" option; do + case $option in + b) browserPath=${OPTARG} ;; + p) profilePath=${OPTARG} ;; + *) exitWithUsageInfo ;; + esac +done + +if [[ -z ${browserPath} ]]; then + exitWithUsageInfo +fi + +if [[ -z ${profilePath} ]]; then + profilePath="${0%/*}/chrome-user-data" +fi + +result=$( + "${browserPath}" \ + --allow-pre-commit-input \ + --disable-background-networking \ + --disable-background-timer-throttling \ + --disable-backgrounding-occluded-windows \ + --disable-breakpad \ + --disable-client-side-phishing-detection \ + --disable-component-update \ + --disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,Prerender2 \ + --disable-hang-monitor \ + --disable-ipc-flooding-protection \ + --disable-popup-blocking \ + --disable-prompt-on-repost \ + --disable-renderer-backgrounding \ + --disable-search-engine-choice-screen \ + --disable-sync \ + --enable-automation \ + --enable-blink-features=IdleDetection \ + --enable-features=NetworkServiceInProcess2 \ + --export-tagged-pdf \ + --force-color-profile=srgb \ + --metrics-recording-only \ + --no-first-run \ + --password-store=basic \ + --use-mock-keychain \ + --enable-remote-extensions \ + --disable-blink-features=AutomationControlled \ + --remote-debugging-port=0 \ + --flag-switches-begin \ + --flag-switches-end \ + --disable-nacl \ + --user-data-dir="${profilePath}" \ + --disable-dev-shm-usage \ + --no-sandbox \ + --disable-setuid-sandbox \ + --disable-gpu \ + --disable-webgl \ + --disable-webgl2 \ + --disable-features=BackForwardCache \ + --js-flags=--max-old-space-size=8192 \ + --window-size=1920,1080 \ + about:blank +) diff --git a/packages/scanner-global-library/src/authenticator/resource-authenticator.spec.ts b/packages/scanner-global-library/src/authenticator/resource-authenticator.spec.ts index 3a6441dca..bfe988adb 100644 --- a/packages/scanner-global-library/src/authenticator/resource-authenticator.spec.ts +++ b/packages/scanner-global-library/src/authenticator/resource-authenticator.spec.ts @@ -3,62 +3,90 @@ import 'reflect-metadata'; -import { IMock, Mock } from 'typemoq'; +import { IMock, Mock, Times } from 'typemoq'; import * as Puppeteer from 'puppeteer'; import { GlobalLogger } from 'logger'; +import { System } from 'common'; import { NavigationResponse } from '../page-navigator'; +import { PageResponseProcessor } from '../page-response-processor'; +import { puppeteerTimeoutConfig } from '../page-timeout-config'; +import { BrowserError } from '../browser-error'; import { ResourceAuthenticator } from './resource-authenticator'; -import { LoginPageDetector } from './login-page-detector'; import { LoginPageClientFactory } from './login-page-client-factory'; import { LoginPageClient } from './azure-login-page-client'; const url = 'authUrl'; -let loginPageDetectorMock: IMock; let loginPageClientFactoryMock: IMock; let puppeteerPageMock: IMock; let loginPageClientMock: IMock; +let pageResponseProcessorMock: IMock; let loggerMock: IMock; let resourceAuthenticator: ResourceAuthenticator; +let puppeteerGotoResponse: Puppeteer.HTTPResponse; describe(ResourceAuthenticator, () => { beforeEach(() => { loginPageClientMock = Mock.ofType(); - loginPageDetectorMock = Mock.ofType(); loginPageClientFactoryMock = Mock.ofType(); puppeteerPageMock = Mock.ofType(); + pageResponseProcessorMock = Mock.ofType(PageResponseProcessor); loggerMock = Mock.ofType(); - puppeteerPageMock - .setup((o) => o.url()) - .returns(() => url) - .verifiable(); + System.getElapsedTime = () => 100; resourceAuthenticator = new ResourceAuthenticator( - loginPageDetectorMock.object, loginPageClientFactoryMock.object, + pageResponseProcessorMock.object, loggerMock.object, ); }); afterEach(() => { - loginPageDetectorMock.verifyAll(); loginPageClientFactoryMock.verifyAll(); puppeteerPageMock.verifyAll(); loginPageClientMock.verifyAll(); + pageResponseProcessorMock.verifyAll(); loggerMock.verifyAll(); }); + it('should return navigation error', async () => { + const browserError = { statusCode: 404 } as BrowserError; + const gotoError = new Error('404'); + puppeteerPageMock + .setup((o) => o.goto(url, { waitUntil: 'networkidle2', timeout: puppeteerTimeoutConfig.navigationTimeoutMsec })) + .returns(() => Promise.reject(gotoError)) + .verifiable(Times.atLeastOnce()); + pageResponseProcessorMock + .setup((o) => o.getNavigationError(gotoError)) + .returns(() => browserError) + .verifiable(); + const authenticationResult = { + navigationResponse: { + browserError, + pageNavigationTiming: { + goto: 100, + }, + } as NavigationResponse, + authenticationType: 'entraId', + authenticated: false, + }; + + const response = await resourceAuthenticator.authenticate(url, 'entraId', puppeteerPageMock.object); + expect(response).toEqual(authenticationResult); + }); + it('should authenticate resource', async () => { const authenticationResult = { navigationResponse: { httpResponse: { url: () => 'url' } } as NavigationResponse, authenticationType: 'entraId', authenticated: true, }; - loginPageDetectorMock - .setup((o) => o.getAuthenticationType(url)) - .returns(() => 'entraId') - .verifiable(); + puppeteerGotoResponse = { puppeteerResponse: 'goto', url: () => url } as unknown as Puppeteer.HTTPResponse; + puppeteerPageMock + .setup((o) => o.goto(url, { waitUntil: 'networkidle2', timeout: puppeteerTimeoutConfig.navigationTimeoutMsec })) + .returns(() => Promise.resolve(puppeteerGotoResponse)) + .verifiable(Times.atLeastOnce()); loginPageClientMock .setup((o) => o.login(puppeteerPageMock.object)) .returns(() => Promise.resolve(authenticationResult.navigationResponse)) @@ -68,27 +96,7 @@ describe(ResourceAuthenticator, () => { .returns(() => loginPageClientMock.object) .verifiable(); - const response = await resourceAuthenticator.authenticate(puppeteerPageMock.object); + const response = await resourceAuthenticator.authenticate(url, 'entraId', puppeteerPageMock.object); expect(response).toEqual(authenticationResult); }); - - it('should skip if no login page detected', async () => { - loginPageDetectorMock - .setup((o) => o.getAuthenticationType(url)) - .returns(() => undefined) - .verifiable(); - - const response = await resourceAuthenticator.authenticate(puppeteerPageMock.object); - expect(response).toBeUndefined(); - }); - - it('should skip if undetermined authentication detected', async () => { - loginPageDetectorMock - .setup((o) => o.getAuthenticationType(url)) - .returns(() => 'undetermined') - .verifiable(); - - const response = await resourceAuthenticator.authenticate(puppeteerPageMock.object); - expect(response).toBeUndefined(); - }); }); diff --git a/packages/scanner-global-library/src/authenticator/resource-authenticator.ts b/packages/scanner-global-library/src/authenticator/resource-authenticator.ts index a4499ed0c..0ed0467e0 100644 --- a/packages/scanner-global-library/src/authenticator/resource-authenticator.ts +++ b/packages/scanner-global-library/src/authenticator/resource-authenticator.ts @@ -6,8 +6,9 @@ import * as Puppeteer from 'puppeteer'; import { GlobalLogger } from 'logger'; import { AuthenticationType } from 'storage-documents'; import { System } from 'common'; -import { NavigationResponse } from '../page-navigator'; -import { LoginPageDetector } from './login-page-detector'; +import { NavigationResponse, PageOperationResult } from '../page-navigator'; +import { PageNavigationTiming, puppeteerTimeoutConfig } from '../page-timeout-config'; +import { PageResponseProcessor } from '../page-response-processor'; import { LoginPageClientFactory } from './login-page-client-factory'; export interface ResourceAuthenticationResult { @@ -19,15 +20,27 @@ export interface ResourceAuthenticationResult { @injectable() export class ResourceAuthenticator { constructor( - @inject(LoginPageDetector) private readonly loginPageDetector: LoginPageDetector, @inject(LoginPageClientFactory) private readonly loginPageClientFactory: LoginPageClientFactory, + @inject(PageResponseProcessor) public readonly pageResponseProcessor: PageResponseProcessor, @inject(GlobalLogger) @optional() private readonly logger: GlobalLogger, ) {} - public async authenticate(page: Puppeteer.Page): Promise { - const authenticationType = this.loginPageDetector.getAuthenticationType(page.url()); - if (authenticationType === undefined || authenticationType === 'undetermined') { - return undefined; + public async authenticate( + url: string, + authenticationType: AuthenticationType, + page: Puppeteer.Page, + ): Promise { + const operationResult = await this.navigatePage(url, page); + if (operationResult.browserError) { + return { + navigationResponse: { + httpResponse: operationResult.response, + pageNavigationTiming: operationResult.navigationTiming, + browserError: operationResult.browserError, + }, + authenticationType, + authenticated: false, + }; } const loginPageClient = this.loginPageClientFactory.getPageClient(authenticationType); @@ -53,4 +66,27 @@ export class ResourceAuthenticator { authenticated, }; } + + private async navigatePage(url: string, page: Puppeteer.Page): Promise { + const timestamp = System.getTimestamp(); + try { + this.logger?.logInfo('Navigate page to URL for authentication.'); + const response = await page.goto(url, { waitUntil: 'networkidle2', timeout: puppeteerTimeoutConfig.navigationTimeoutMsec }); + + return { response, navigationTiming: { goto: System.getElapsedTime(timestamp) } as PageNavigationTiming }; + } catch (error) { + const browserError = this.pageResponseProcessor.getNavigationError(error as Error); + this.logger?.logError(`Page authenticator navigation error.`, { + error: System.serializeError(error), + browserError: System.serializeError(browserError), + }); + + return { + response: undefined, + navigationTiming: { goto: System.getElapsedTime(timestamp) } as PageNavigationTiming, + browserError, + error, + }; + } + } } diff --git a/packages/scanner-global-library/src/page-navigator.ts b/packages/scanner-global-library/src/page-navigator.ts index bce2551ae..735c5a12d 100644 --- a/packages/scanner-global-library/src/page-navigator.ts +++ b/packages/scanner-global-library/src/page-navigator.ts @@ -65,57 +65,61 @@ export class PageNavigator { public async waitForNavigation(page: Puppeteer.Page): Promise { const pageOperation = this.createPageOperation('wait', page); - const opResult = await this.pageOperationHandler.invoke(pageOperation, page); - if (opResult.error) { - return this.getOperationErrorResult(opResult); + const operationResult = await this.pageOperationHandler.invoke(pageOperation, page); + if (operationResult.error) { + return this.getOperationErrorResult(operationResult); } return { - httpResponse: opResult.response, - pageNavigationTiming: opResult.navigationTiming, - browserError: opResult.browserError, + httpResponse: operationResult.response, + pageNavigationTiming: operationResult.navigationTiming, + browserError: operationResult.browserError, }; } private async navigatePage(pageOperation: PageOperation, page: Puppeteer.Page): Promise { - const opResult = await this.navigatePageImpl(pageOperation, page); + const operationResult = await this.navigatePageImpl(pageOperation, page); - if (opResult.browserError) { + if (operationResult.browserError) { return { httpResponse: undefined, - pageNavigationTiming: opResult.navigationTiming, - browserError: opResult.browserError, + pageNavigationTiming: operationResult.navigationTiming, + browserError: operationResult.browserError, }; } - const postNavigationPageTiming = await this.pageNavigationHooks.postNavigation(page, opResult.response, async (browserError) => { - opResult.browserError = browserError; - }); + const postNavigationPageTiming = await this.pageNavigationHooks.postNavigation( + page, + operationResult.response, + async (browserError) => { + operationResult.browserError = browserError; + }, + ); return { - httpResponse: opResult.response, + httpResponse: operationResult.response, pageNavigationTiming: { - ...opResult.navigationTiming, + ...operationResult.navigationTiming, ...postNavigationPageTiming, } as PageNavigationTiming, - browserError: opResult.browserError, + browserError: operationResult.browserError, }; } private async navigatePageImpl(pageOperation: PageOperation, page: Puppeteer.Page): Promise { - let opResult = await this.pageOperationHandler.invoke(pageOperation, page); - if (opResult.error) { - return this.getOperationErrorResult(opResult); + let operationResult = await this.pageOperationHandler.invoke(pageOperation, page); + if (operationResult.error) { + return this.getOperationErrorResult(operationResult); } - opResult = await this.handleCachedResponse(opResult, page); - if (opResult.error) { - return this.getOperationErrorResult(opResult); + operationResult = await this.handleCachedResponse(operationResult, page); + if (operationResult.error) { + return this.getOperationErrorResult(operationResult); } await this.resetPageSessionHistory(page); - return opResult; + return operationResult; } /** @@ -134,7 +138,7 @@ export class PageNavigator { }); let count = 0; - let opResult; + let operationResult; do { count++; if (count > maxRetryCount - 1) { @@ -155,13 +159,15 @@ export class PageNavigator { // Navigation using page.goto() will not resolve HTTP 304 response // Use of page.goBack() is required with back/forward cache disabled, option --disable-features=BackForwardCache const pageOperation = async () => page.goBack(this.waitForOptions); - opResult = await this.pageOperationHandler.invoke(pageOperation, page); + operationResult = await this.pageOperationHandler.invoke(pageOperation, page); } while ( count < maxRetryCount && - (opResult.error !== undefined || opResult.response?.status() === undefined || opResult.response?.status() === 304) + (operationResult.error !== undefined || + operationResult.response?.status() === undefined || + operationResult.response?.status() === 304) ); - return opResult; + return operationResult; } private createPageOperation(operation: 'goto' | 'reload' | 'wait', page: Puppeteer.Page, url?: string): PageOperation { diff --git a/packages/scanner-global-library/src/page.spec.ts b/packages/scanner-global-library/src/page.spec.ts index 7ae753bb2..eaaa5d39e 100644 --- a/packages/scanner-global-library/src/page.spec.ts +++ b/packages/scanner-global-library/src/page.spec.ts @@ -10,7 +10,7 @@ import { GuidGenerator, System } from 'common'; import { GlobalLogger } from 'logger'; import { AxeScanResults } from './axe-scanner/axe-scan-results'; import { BrowserError } from './browser-error'; -import { Page } from './page'; +import { BrowserStartOptions, Page } from './page'; import { getPromisableDynamicMock } from './test-utilities/promisable-mock'; import { WebDriver } from './web-driver'; import { PageNavigator, NavigationResponse } from './page-navigator'; @@ -54,6 +54,7 @@ let resourceAuthenticatorMock: IMock; let pageAnalyzerMock: IMock; let guidGeneratorMock: IMock; let devToolsSessionMock: IMock; +let browserStartOptions: BrowserStartOptions; describe(Page, () => { beforeEach(() => { @@ -78,6 +79,7 @@ describe(Page, () => { pageAnalyzerMock = Mock.ofType(); guidGeneratorMock = Mock.ofType(); devToolsSessionMock = Mock.ofType(); + browserStartOptions = {} as BrowserStartOptions; scrollToTopMock = jest.fn().mockImplementation(() => Promise.resolve()); puppeteerResponseMock.setup((o) => o.ok()).returns(() => true); @@ -141,6 +143,7 @@ describe(Page, () => { timing[key] = `${navigationResponse.pageNavigationTiming[key]}`; }); loggerMock.setup((o) => o.logInfo('Total page load time 8, msec', { status: 200, ...timing })).verifiable(); + page.browserStartOptions = browserStartOptions; await page.navigate(url); @@ -161,16 +164,19 @@ describe(Page, () => { pageAnalyzerMock.reset(); pageAnalyzerMock .setup((o) => o.analyze(url, puppeteerPageMock.object)) - .returns(() => Promise.resolve({ navigationResponse, authentication: true } as PageAnalysisResult)) + .returns(() => + Promise.resolve({ navigationResponse, authentication: true, authenticationType: 'entraId' } as PageAnalysisResult), + ) .verifiable(); resourceAuthenticatorMock - .setup((o) => o.authenticate(puppeteerPageMock.object)) + .setup((o) => o.authenticate(url, 'entraId', puppeteerPageMock.object)) .returns(() => Promise.resolve(authenticationResult)) .verifiable(); pageNavigatorMock .setup(async (o) => o.navigate('localhost/2', puppeteerPageMock.object)) .returns(() => Promise.resolve(reloadNavigationResponse)) .verifiable(); + page.browserStartOptions = browserStartOptions; await page.navigate(url, { enableAuthentication: true }); @@ -186,6 +192,7 @@ describe(Page, () => { .setup(async (o) => o.trace(url, puppeteerPageMock.object)) .returns(() => Promise.resolve()) .verifiable(); + page.browserStartOptions = browserStartOptions; await page.navigate(url); @@ -203,6 +210,7 @@ describe(Page, () => { .setup((o) => o.setExtraHTTPHeaders({ X_FORWARDED_FOR: '1.1.1.1' })) .returns(() => Promise.resolve()) .verifiable(); + page.browserStartOptions = browserStartOptions; await page.navigate(url); }); @@ -350,6 +358,7 @@ describe(Page, () => { .setup(async (o) => o.close()) .returns(() => Promise.resolve()) .verifiable(); + page.browserStartOptions = browserStartOptions; await page.close(); }); diff --git a/packages/scanner-global-library/src/page.ts b/packages/scanner-global-library/src/page.ts index 15fe9d60a..cc0fe046a 100644 --- a/packages/scanner-global-library/src/page.ts +++ b/packages/scanner-global-library/src/page.ts @@ -64,6 +64,8 @@ export class Page { private readonly enableAuthenticationGlobalFlag: boolean; + private readonly browserWSEndpoint: string; + constructor( @inject(WebDriver) private readonly webDriver: WebDriver, @inject(PageNavigator) private readonly pageNavigator: PageNavigator, @@ -76,6 +78,7 @@ export class Page { private readonly scrollToPageTop: typeof scrollToTop = scrollToTop, ) { this.enableAuthenticationGlobalFlag = process.env.PAGE_AUTH === 'true' ? true : false; + this.browserWSEndpoint = process.env.BROWSER_ENDPOINT; } public get puppeteerPage(): Puppeteer.Page { @@ -88,8 +91,8 @@ export class Page { public async create(options: BrowserStartOptions = { clearBrowserCache: true }): Promise { this.browserStartOptions = options; - if (options?.browserWSEndpoint !== undefined) { - this.browser = await this.webDriver.connect(options?.browserWSEndpoint); + if (!isEmpty(options?.browserWSEndpoint) || !isEmpty(this.browserWSEndpoint)) { + this.browser = await this.webDriver.connect(options?.browserWSEndpoint ?? this.browserWSEndpoint); } else { this.browser = await this.webDriver.launch({ browserExecutablePath: options?.browserExecutablePath, @@ -213,6 +216,10 @@ export class Page { } public async close(): Promise { + if (this.browserStartOptions.browserWSEndpoint || this.browserWSEndpoint) { + return; + } + if (this.webDriver !== undefined) { await this.webDriver.close(); } @@ -267,7 +274,12 @@ export class Page { } // Invoke authentication client - this.authenticationResult = await this.resourceAuthenticator.authenticate(this.page); + this.authenticationResult = await this.resourceAuthenticator.authenticate( + this.requestUrl, + this.pageAnalysisResult.authenticationType, + this.page, + ); + if (this.authenticationResult?.navigationResponse?.browserError !== undefined) { this.setLastNavigationState('auth', this.authenticationResult.navigationResponse); } @@ -297,6 +309,10 @@ export class Page { } private async reopenBrowser(): Promise { + if (this.browserStartOptions.browserWSEndpoint || this.browserWSEndpoint) { + return; + } + await this.close(); await this.create({ ...this.browserStartOptions, clearBrowserCache: false }); // wait for browser to start diff --git a/packages/web-api-scan-runner/src/scanner/page-scan-processor.ts b/packages/web-api-scan-runner/src/scanner/page-scan-processor.ts index af0959633..2c8f5a5a5 100644 --- a/packages/web-api-scan-runner/src/scanner/page-scan-processor.ts +++ b/packages/web-api-scan-runner/src/scanner/page-scan-processor.ts @@ -110,7 +110,7 @@ export class PageScanProcessor { if (authenticationResult !== undefined) { pageScanResult.authentication = { ...pageScanResult.authentication, - detected: authenticationResult.authenticationType, + detected: pageMetadata.authenticationType, state: authenticationResult.authenticated === true ? 'succeeded' : 'failed', }; } else { diff --git a/yarn.lock b/yarn.lock index 666f1a401..b393aecce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4867,7 +4867,6 @@ __metadata: "@opentelemetry/semantic-conventions": ^1.15.0 "@sindresorhus/fnv1a": ^2.0.1 "@types/escape-html": ^1.0.2 - "@types/fingerprint-generator": 1.0.0 "@types/jest": ^29.5.0 "@types/lodash": ^4.14.182 "@types/node": ^16.18.11 @@ -5491,6 +5490,7 @@ __metadata: version: 0.0.0-use.local resolution: "axe-result-converter@workspace:packages/axe-result-converter" dependencies: + "@types/fingerprint-generator": 1.0.0 "@types/jest": ^29.5.0 "@types/lodash": ^4.14.182 "@types/node": ^16.18.11