Skip to content

Commit

Permalink
Merge pull request #43 from nevissecurity/feature/NEVISACCESSAPP-6059-…
Browse files Browse the repository at this point in the history
…introduce-authenticator-allowlist

NEVISACCESSAPP-6059: introduce authenticator allowlist
  • Loading branch information
daniel-toth-leeder authored Jul 25, 2024
2 parents 7fc5347 + 0424085 commit c6902ee
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 163 deletions.
14 changes: 13 additions & 1 deletion assets/config_authentication_cloud.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,17 @@
"sdk": {
"hostname": "myinstance.mauth.nevis.cloud",
"facetId": "android:apk-key-hash:ch.nevis.mobile.authentication.sdk.react.example"
}
},
"authenticatorAllowlist": [
"F1D0#0001",
"F1D0#0002",
"F1D0#0003",
"F1D0#0004",
"F1D0#0005",
"F1D0#1001",
"F1D0#1002",
"F1D0#1003",
"F1D0#1004",
"F1D0#1005"
]
}
14 changes: 13 additions & 1 deletion assets/config_identity_suite.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,17 @@
"authenticationResponsePath": "/auth/fidouaf/authenticationresponse/",
"deregistrationRequestPath": "/nevisfido/uaf/1.1/request/deregistration/",
"dispatchTargetResourcePath": "/nevisfido/token/dispatch/targets/"
}
},
"authenticatorAllowlist": [
"F1D0#1001",
"F1D0#1002",
"F1D0#1003",
"F1D0#1004",
"F1D0#1005",
"F1D0#1001",
"F1D0#1002",
"F1D0#1003",
"F1D0#1004",
"F1D0#1005"
]
}
36 changes: 34 additions & 2 deletions src/configuration/AppConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/**
* Copyright © 2023 Nevis Security AG. All rights reserved.
*/
import { Aaid } from '@nevis-security/nevis-mobile-authentication-sdk-react';

import { AuthenticatorUtils } from '../utility/AuthenticatorUtils';

export class SdkConfiguration {
baseUrl: string;
Expand All @@ -13,7 +16,7 @@ export class SdkConfiguration {
deregistrationRequestPath?: string;
dispatchTargetResourcePath?: string;

constructor(
private constructor(
baseUrl: string,
hostname: string,
facetId: string,
Expand All @@ -34,13 +37,42 @@ export class SdkConfiguration {
this.deregistrationRequestPath = deregistrationRequestPath;
this.dispatchTargetResourcePath = dispatchTargetResourcePath;
}

static fromJson(json: any): SdkConfiguration {
return new SdkConfiguration(
json.baseUrl,
json.hostname,
json.facetId,
json.registrationRequestPath,
json.registrationResponsePath,
json.authenticationRequestPath,
json.authenticationResponsePath,
json.deregistrationRequestPath,
json.dispatchTargetResourcePath
);
}
}
export class AppConfiguration {
sdk: SdkConfiguration;
loginRequestURL?: string;
authenticatorAllowlist: Array<Aaid>;

constructor(sdk: SdkConfiguration, loginRequestURL?: string) {
private constructor(
sdk: SdkConfiguration,
authenticatorAllowList: Array<Aaid>,
loginRequestURL?: string
) {
this.sdk = sdk;
this.authenticatorAllowlist = authenticatorAllowList;
this.loginRequestURL = loginRequestURL;
}

static fromJson(json: any): AppConfiguration {
const sdk = SdkConfiguration.fromJson(json.sdk);
const data = json.authenticatorAllowlist;
const authenticatorAllowlist = data.flatMap((allowedAuthenticator: string) => {
return AuthenticatorUtils.getAaidFromRawValue(allowedAuthenticator) || [];
});
return new AppConfiguration(sdk, authenticatorAllowlist, json.loginRequestURL);
}
}
4 changes: 2 additions & 2 deletions src/configuration/ConfigurationLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export class ConfigurationLoader {
return this._appConfiguration;
}

const json = this.configJson();
this._appConfiguration = Object.assign(AppConfiguration.prototype, json);
this._appConfiguration = AppConfiguration.fromJson(this.configJson());

if (!this._appConfiguration) {
ErrorHandler.handle(
OperationType.unknown,
Expand Down
9 changes: 7 additions & 2 deletions src/screens/AuthCloudApiRegistrationViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import type { RootStackParamList } from './RootStackParamList';
import { ErrorHandler } from '../error/ErrorHandler';
import { OperationType } from '../model/OperationType';
import {
AuthenticatorSelectorImpl,
AuthenticatorSelectorOperation,
} from '../userInteraction/AuthenticatorSelectorImpl';
import { BiometricUserVerifierImpl } from '../userInteraction/BiometricUserVerifierImpl';
import { DevicePasscodeUserVerifierImpl } from '../userInteraction/DevicePasscodeUserVerifierImpl';
import { FingerprintUserVerifierImpl } from '../userInteraction/FingerprintUserVerifierImpl';
import { PasswordEnrollerImpl } from '../userInteraction/PasswordEnrollerImpl';
import { PinEnrollerImpl } from '../userInteraction/PinEnrollerImpl';
import { RegistrationAuthenticatorSelectorImpl } from '../userInteraction/RegistrationAuthenticatorSelectorImpl';
import { ClientProvider } from '../utility/ClientProvider';
import { DeviceInformationUtils } from '../utility/DeviceInformationUtils';

Expand All @@ -29,7 +32,9 @@ const useAuthCloudApiRegistrationViewModel = () => {
const client = ClientProvider.getInstance().client;
const authCloudApiRegistration = client?.operations.authCloudApiRegistration
.deviceInformation(DeviceInformationUtils.create())
.authenticatorSelector(new RegistrationAuthenticatorSelectorImpl())
.authenticatorSelector(
new AuthenticatorSelectorImpl(AuthenticatorSelectorOperation.registration)
)
.pinEnroller(new PinEnrollerImpl())
.passwordEnroller(new PasswordEnrollerImpl())
.biometricUserVerifier(new BiometricUserVerifierImpl())
Expand Down
9 changes: 7 additions & 2 deletions src/screens/SelectAccountViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import type { RootStackParamList } from './RootStackParamList';
import { AppErrorAuthorizationProviderNotFound, AppErrorUnknownError } from '../error/AppError';
import { ErrorHandler } from '../error/ErrorHandler';
import { OperationType } from '../model/OperationType';
import { AuthenticationAuthenticatorSelectorImpl } from '../userInteraction/AuthenticationAuthenticatorSelectorImpl';
import {
AuthenticatorSelectorImpl,
AuthenticatorSelectorOperation,
} from '../userInteraction/AuthenticatorSelectorImpl';
import { BiometricUserVerifierImpl } from '../userInteraction/BiometricUserVerifierImpl';
import { DevicePasscodeUserVerifierImpl } from '../userInteraction/DevicePasscodeUserVerifierImpl';
import { FingerprintUserVerifierImpl } from '../userInteraction/FingerprintUserVerifierImpl';
Expand Down Expand Up @@ -71,7 +74,9 @@ const useSelectAccountViewModel = () => {
const client = ClientProvider.getInstance().client;
client?.operations.authentication
.username(username)
.authenticatorSelector(new AuthenticationAuthenticatorSelectorImpl())
.authenticatorSelector(
new AuthenticatorSelectorImpl(AuthenticatorSelectorOperation.authentication)
)
.pinUserVerifier(new PinUserVerifierImpl())
.passwordUserVerifier(new PasswordUserVerifierImpl())
.biometricUserVerifier(new BiometricUserVerifierImpl())
Expand Down
9 changes: 7 additions & 2 deletions src/screens/UsernamePasswordLoginViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ import {
} from '../error/AppError';
import { ErrorHandler } from '../error/ErrorHandler';
import { OperationType } from '../model/OperationType';
import {
AuthenticatorSelectorImpl,
AuthenticatorSelectorOperation,
} from '../userInteraction/AuthenticatorSelectorImpl';
import { BiometricUserVerifierImpl } from '../userInteraction/BiometricUserVerifierImpl';
import { DevicePasscodeUserVerifierImpl } from '../userInteraction/DevicePasscodeUserVerifierImpl';
import { FingerprintUserVerifierImpl } from '../userInteraction/FingerprintUserVerifierImpl';
import { PasswordEnrollerImpl } from '../userInteraction/PasswordEnrollerImpl';
import { PinEnrollerImpl } from '../userInteraction/PinEnrollerImpl';
import { RegistrationAuthenticatorSelectorImpl } from '../userInteraction/RegistrationAuthenticatorSelectorImpl';
import { ClientProvider } from '../utility/ClientProvider';
import { DeviceInformationUtils } from '../utility/DeviceInformationUtils';

Expand All @@ -51,7 +54,9 @@ const useUsernamePasswordLoginViewModel = () => {
.username(usernameToRegister)
.deviceInformation(DeviceInformationUtils.create())
.authorizationProvider(authorizationProvider)
.authenticatorSelector(new RegistrationAuthenticatorSelectorImpl())
.authenticatorSelector(
new AuthenticatorSelectorImpl(AuthenticatorSelectorOperation.registration)
)
.pinEnroller(new PinEnrollerImpl())
.passwordEnroller(new PasswordEnrollerImpl())
.biometricUserVerifier(new BiometricUserVerifierImpl())
Expand Down
45 changes: 0 additions & 45 deletions src/userInteraction/AuthenticationAuthenticatorSelectorImpl.ts

This file was deleted.

70 changes: 70 additions & 0 deletions src/userInteraction/AuthenticatorSelectorImpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Copyright © 2023 Nevis Security AG. All rights reserved.
*/

import {
Authenticator,
AuthenticatorSelectionContext,
AuthenticatorSelectionHandler,
AuthenticatorSelector,
} from '@nevis-security/nevis-mobile-authentication-sdk-react';

import { ConfigurationLoader } from '../configuration/ConfigurationLoader';
import { AuthenticatorItem } from '../model/AuthenticatorItem';
import * as RootNavigation from '../utility/RootNavigation';
import { AuthenticatorValidator } from '../utility/validation/AuthenticatorValidator';

export enum AuthenticatorSelectorOperation {
registration,
authentication,
}

export class AuthenticatorSelectorImpl extends AuthenticatorSelector {
operation: AuthenticatorSelectorOperation;
constructor(operation: AuthenticatorSelectorOperation) {
super();
this.operation = operation;
}

async selectAuthenticator(
context: AuthenticatorSelectionContext,
handler: AuthenticatorSelectionHandler
): Promise<void> {
console.log('Please select one of the received available authenticators!');
const configuration = ConfigurationLoader.getInstance().appConfiguration;
const username = context.account.username;
let authenticators: Array<Authenticator> = [];
switch (this.operation) {
case AuthenticatorSelectorOperation.registration:
authenticators = await AuthenticatorValidator.validateForRegistration(
context,
configuration.authenticatorAllowlist
);
break;
case AuthenticatorSelectorOperation.authentication:
authenticators = AuthenticatorValidator.validateForAuthentication(
context,
configuration.authenticatorAllowlist
);
break;
}

if (authenticators.length === 0) {
console.log('No available authenticators found. Cancelling authenticator selection.');
return handler.cancel();
}

const items: AuthenticatorItem[] = [];
for (const authenticator of authenticators) {
items.push(
new AuthenticatorItem(
authenticator,
await context.isPolicyCompliant(authenticator.aaid),
authenticator.userEnrollment.isEnrolled(username)
)
);
}

RootNavigation.navigate('SelectAuthenticator', { items: items, handler: handler });
}
}
14 changes: 10 additions & 4 deletions src/userInteraction/OutOfBandOperationHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ import {
} from '@nevis-security/nevis-mobile-authentication-sdk-react';

import { AccountSelectorImpl } from './AccountSelectorImpl';
import { AuthenticationAuthenticatorSelectorImpl } from './AuthenticationAuthenticatorSelectorImpl';
import {
AuthenticatorSelectorImpl,
AuthenticatorSelectorOperation,
} from './AuthenticatorSelectorImpl';
import { BiometricUserVerifierImpl } from './BiometricUserVerifierImpl';
import { DevicePasscodeUserVerifierImpl } from './DevicePasscodeUserVerifierImpl';
import { FingerprintUserVerifierImpl } from './FingerprintUserVerifierImpl';
import { PasswordEnrollerImpl } from './PasswordEnrollerImpl';
import { PasswordUserVerifierImpl } from './PasswordUserVerifierImpl';
import { PinEnrollerImpl } from './PinEnrollerImpl';
import { PinUserVerifierImpl } from './PinUserVerifierImpl';
import { RegistrationAuthenticatorSelectorImpl } from './RegistrationAuthenticatorSelectorImpl';
import { AppErrorPayloadDecodeError, AppErrorQrCodeError } from '../error/AppError';
import { ErrorHandler } from '../error/ErrorHandler';
import { OperationType } from '../model/OperationType';
Expand All @@ -31,7 +33,9 @@ import * as RootNavigation from '../utility/RootNavigation';
async function handleRegistration(registration: OutOfBandRegistration) {
await registration
.deviceInformation(DeviceInformationUtils.create())
.authenticatorSelector(new RegistrationAuthenticatorSelectorImpl())
.authenticatorSelector(
new AuthenticatorSelectorImpl(AuthenticatorSelectorOperation.registration)
)
.pinEnroller(new PinEnrollerImpl())
.passwordEnroller(new PasswordEnrollerImpl())
.biometricUserVerifier(new BiometricUserVerifierImpl())
Expand All @@ -50,7 +54,9 @@ async function handleRegistration(registration: OutOfBandRegistration) {
async function handleAuthentication(authentication: OutOfBandAuthentication) {
await authentication
.accountSelector(new AccountSelectorImpl())
.authenticatorSelector(new AuthenticationAuthenticatorSelectorImpl())
.authenticatorSelector(
new AuthenticatorSelectorImpl(AuthenticatorSelectorOperation.authentication)
)
.pinUserVerifier(new PinUserVerifierImpl())
.passwordUserVerifier(new PasswordUserVerifierImpl())
.biometricUserVerifier(new BiometricUserVerifierImpl())
Expand Down
Loading

0 comments on commit c6902ee

Please sign in to comment.