Skip to content

Commit

Permalink
Merge commit 'dbfc19ff6f264f2f4c5f7c0be234228f676bd34d'
Browse files Browse the repository at this point in the history
# Conflicts:
#	composer.json
#	dev/Command/AuthenticationCommand.php
  • Loading branch information
pmeulen committed Nov 29, 2024
2 parents 25d6a70 + dbfc19f commit 7363c65
Show file tree
Hide file tree
Showing 39 changed files with 1,480 additions and 84 deletions.
3 changes: 3 additions & 0 deletions assets/typescript/AuthenticationPageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ export class AuthenticationPageService {
case 'needs-refresh':
this.reloadPage();
break;
default:
this.switchToStatusRequestError();
break;
}
};

Expand Down
15 changes: 12 additions & 3 deletions assets/typescript/Client/StatusClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@ export interface PendingRequest {
}

export class StatusClient {
constructor(private apiUrl: string) {

constructor(
private apiUrl: string,
private correlationLoggingId: string,
) {
}

/**
* Request status form the API.
*/
public request(callback: (status: string) => void, errorCallback: (error: unknown) => void): PendingRequest {
return jQuery.get(this.apiUrl, callback).fail(errorCallback);
let url;
if(this.correlationLoggingId !== ''){
url = this.apiUrl + (this.apiUrl.includes('?') ? '&' : '?') + 'correlation-id=' + this.correlationLoggingId;
}else{
url = this.apiUrl;
}

return jQuery.get(url, callback).fail(errorCallback);
}
}
6 changes: 6 additions & 0 deletions assets/typescript/Component/RegistrationStatusComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export class RegistrationStatusComponent {
public showUnknownErrorHappened() {
this.show('div.status.error');
}
/**
* Unknown error happened. Please try again by refreshing your browser.
*/
public showTimeoutHappened() {
this.show('div.status.timeout');
}

private hideAll() {
jQuery('.status-container >').hide();
Expand Down
8 changes: 8 additions & 0 deletions assets/typescript/RegistrationStateMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export class RegistrationStateMachine {
* Client-side only status.
*/
public static readonly ERROR = 'ERROR';
public static readonly TIMEOUT = 'TIMEOUT';

private previousStatus = RegistrationStateMachine.IDLE;

constructor(private statusPollingService: StatusPollService,
Expand Down Expand Up @@ -62,6 +64,12 @@ export class RegistrationStateMachine {
this.qrCode.hide();
document.location.replace(this.finalizedUrl);
break;
case RegistrationStateMachine.TIMEOUT:
this.qrCode.hide();
this.statusUi.showTimeoutHappened();
this.statusPollingService.stop();
this.previousStatus = RegistrationStateMachine.ERROR;
break;
default:
this.unknownError();
return;
Expand Down
8 changes: 8 additions & 0 deletions assets/typescript/__test__/AuthenticationPageService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ describe('AuthenticationPageService', () => {
successCallback('challenge-expired');
expect(spy).toBeCalled();
});
it('Should handle authn error (invalid request)', () => {
if (!successCallback || !errorCallback) {
throw new Error('Should have started status request');
}
const spy = jest.spyOn(context.authenticationPageService, 'switchToStatusRequestError');
successCallback('invalid-request');
expect(spy).toBeCalled();
});

it('Should handle challenge expired', () => {
if (!successCallback || !errorCallback) {
Expand Down
23 changes: 23 additions & 0 deletions assets/typescript/__test__/RegistrationPageService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,28 @@ describe('RegistrationPageService', () => {
});
});

describe('When timeout', () => {
beforeEach(() => {
context.authenticationPageService.start();
if (!statusCallback || !errorCallback) {
throw new Error('Should have started status request');
}
statusCallback(RegistrationStateMachine.TIMEOUT);
});

it('The qr code should be hidden', () => {
expect(context.qrComponent.isVisible()).toBeFalsy();
});

it('Polling should be disabled', () => {
expect(context.pollingService.enabled).toBeFalsy();
});

it('Show finalized', () => {
expect(context.statusUi.showTimeoutHappened).toBeCalled();
});
});

describe('When connection error occurred', () => {
beforeEach(() => {
context.authenticationPageService.start();
Expand Down Expand Up @@ -227,6 +249,7 @@ describe('RegistrationPageService', () => {
showAccountActivationHelp:jest.fn(),
showOneMomentPlease: jest.fn(),
showFinalized: jest.fn(),
showTimeoutHappened: jest.fn(),
showUnknownErrorHappened: jest.fn(),
};

Expand Down
6 changes: 3 additions & 3 deletions assets/typescript/authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import jQuery from 'jquery';

declare global {
interface Window {
bootstrapAuthentication: (statusApiUrl: string, notificationApiUrl: string) => AuthenticationPageService;
bootstrapAuthentication: (statusApiUrl: string, notificationApiUrl: string, correlationLoggingId: string) => AuthenticationPageService;
}
}

window.bootstrapAuthentication = (statusApiUrl: string, notificationApiUrl: string) => {
const statusClient = new StatusClient(statusApiUrl);
window.bootstrapAuthentication = (statusApiUrl: string, notificationApiUrl: string, correlationLoggingId: string) => {
const statusClient = new StatusClient(statusApiUrl, correlationLoggingId);
const notificationClient = new NotificationClient(notificationApiUrl);
const pollingService = new StatusPollService(statusClient);

Expand Down
10 changes: 7 additions & 3 deletions assets/typescript/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import jQuery from 'jquery';

declare global {
interface Window {
bootstrapRegistration: (statusApiUrl: string, notificationApiUrl: string) => RegistrationStateMachine;
bootstrapRegistration: (
statusApiUrl: string,
notificationApiUrl: string,
correlationLoggingId: string
) => RegistrationStateMachine;
}
}

window.bootstrapRegistration = (statusApiUrl: string, finalizedUrl: string) => {
const statusClient = new StatusClient(statusApiUrl);
window.bootstrapRegistration = (statusApiUrl: string, finalizedUrl: string, correlationLoggingId: string) => {
const statusClient = new StatusClient(statusApiUrl, correlationLoggingId);
const pollingService = new StatusPollService(statusClient);
const machine = new RegistrationStateMachine(
pollingService,
Expand Down
195 changes: 195 additions & 0 deletions ci/qa/phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,200 @@
parameters:
ignoreErrors:
-
message: "#^Cannot access offset 'authenticationUrl' on mixed\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset 'id' on mixed\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset 'identities' on mixed\\.$#"
count: 2
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset 'ocraSuite' on mixed\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset 'secret' on mixed\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset int\\|string\\|false on mixed\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset string on mixed\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#1 \\$array of function array_keys expects array, mixed given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#1 \\$file of method Surfnet\\\\Tiqr\\\\Dev\\\\Command\\\\AuthenticationCommand\\:\\:readAuthenticationLinkFromFile\\(\\) expects string, mixed given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#1 \\$ocraSuite of static method OCRA\\:\\:generateOCRA\\(\\) expects string, mixed given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#1 \\$uri of method GuzzleHttp\\\\Client\\:\\:post\\(\\) expects Psr\\\\Http\\\\Message\\\\UriInterface\\|string, mixed given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#2 \\$key of static method OCRA\\:\\:generateOCRA\\(\\) expects string, mixed given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#"
count: 1
path: ../../dev/Command/AuthenticationCommand.php

-
message: "#^Cannot access offset 'authenticationUrl' on mixed\\.$#"
count: 1
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Cannot access offset 'identities' on mixed\\.$#"
count: 2
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Cannot access offset 'ocraSuite' on mixed\\.$#"
count: 1
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Cannot access offset mixed on mixed\\.$#"
count: 5
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Cannot access property \\$service on mixed\\.$#"
count: 2
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Method Surfnet\\\\Tiqr\\\\Dev\\\\Command\\\\RegistrationCommand\\:\\:storeIdentity\\(\\) has parameter \\$metadata with no type specified\\.$#"
count: 1
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Method Surfnet\\\\Tiqr\\\\Dev\\\\Command\\\\RegistrationCommand\\:\\:storeIdentity\\(\\) has parameter \\$secret with no type specified\\.$#"
count: 1
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Parameter \\#1 \\$file of method Surfnet\\\\Tiqr\\\\Dev\\\\Command\\\\RegistrationCommand\\:\\:readRegistrationUrlFromFile\\(\\) expects string, mixed given\\.$#"
count: 1
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
count: 1
path: ../../dev/Command/RegistrationCommand.php

-
message: "#^Call to an undefined method SAML2\\\\Message\\:\\:getStatus\\(\\)\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Cannot call method getValue\\(\\) on SAML2\\\\XML\\\\saml\\\\Issuer\\|null\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Cannot cast mixed to string\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Method Surfnet\\\\Tiqr\\\\Dev\\\\Controller\\\\SPController\\:\\:signRequestQuery\\(\\) has parameter \\$queryParams with no value type specified in iterable type array\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^PHPDoc tag @var has invalid value \\(\\$securityKey\\)\\: Unexpected token \"\\$securityKey\", expected type at offset 10$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#1 \\$key of method SAML2\\\\Certificate\\\\PrivateKeyLoader\\:\\:loadPrivateKey\\(\\) expects SAML2\\\\Configuration\\\\PrivateKey, mixed given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#1 \\$nameId of method Surfnet\\\\SamlBundle\\\\SAML2\\\\AuthnRequest\\:\\:setSubject\\(\\) expects string, mixed given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#1 \\$source of method DOMDocument\\:\\:loadXML\\(\\) expects string, bool\\|string given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#1 \\$string of function base64_decode expects string, bool\\|float\\|int\\|string\\|null given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#1 \\$string of function base64_encode expects string, string\\|false given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#1 \\$xml of static method SAML2\\\\Message\\:\\:fromXML\\(\\) expects DOMElement, DOMElement\\|null given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Parameter \\#2 \\$values of method Symfony\\\\Component\\\\HttpFoundation\\\\ResponseHeaderBag\\:\\:set\\(\\) expects array\\<string\\>\\|string\\|null, mixed given\\.$#"
count: 1
path: ../../dev/Controller/SPController.php

-
message: "#^Method Surfnet\\\\Tiqr\\\\Dev\\\\FileLogger\\:\\:getLogs\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: ../../dev/FileLogger.php

-
message: "#^Method Surfnet\\\\Tiqr\\\\Dev\\\\FileLogger\\:\\:log\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: ../../dev/FileLogger.php

-
message: "#^Parameter \\#1 \\$record of method League\\\\Csv\\\\Writer\\:\\:insertOne\\(\\) expects array\\<float\\|int\\|string\\|Stringable\\|null\\>, array\\<int, mixed\\> given\\.$#"
count: 1
path: ../../dev/FileLogger.php

-
message: "#^Parameter \\#1 \\$stream of static method League\\\\Csv\\\\AbstractCsv\\:\\:createFromStream\\(\\) expects resource, resource\\|false given\\.$#"
count: 1
path: ../../dev/FileLogger.php

-
message: "#^Parameter \\#3 \\$response of method Surfnet\\\\Tiqr\\\\Tiqr\\\\AuthenticationRateLimitServiceInterface\\:\\:authenticate\\(\\) expects string, mixed given\\.$#"
count: 1
Expand Down
1 change: 1 addition & 0 deletions ci/qa/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ parameters:
level: 9
paths:
- ../../src
- ../../dev
3 changes: 3 additions & 0 deletions config/openconext/parameters.yaml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ parameters:
# A secret key that's used to generate certain security-related tokens
app_secret: ThisTokenIsNotSoSecretChangeIt

# A secret salt used to hash the correlationId for logging based on the session_id
correlation_id_salt: 'changeMeToAtLeast16CharsOfRandomString'

# All locales supported by the application
default_locale: en_GB
locales:
Expand Down
4 changes: 3 additions & 1 deletion config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ framework:
# Remove or comment this section to explicitly disable session support.
session:
handler_id: null
cookie_secure: auto
cookie_secure: true
cookie_samesite: none
name: sess_tiqr
cookie_httponly: true
router:
strict_requirements: null
utf8: true
Expand Down
2 changes: 2 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ services:
$locales: '%locales%'
$tiqrConfiguration: '%tiqr_library_options%'
$appSecret: '%app_secret%'
$sessionOptions: '%session.storage.options%'
$correlationIdSalt: '%correlation_id_salt%'

# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
Expand Down
Loading

0 comments on commit 7363c65

Please sign in to comment.