diff --git a/android/Gemfile.lock b/android/Gemfile.lock index 679869d..a596c8a 100644 --- a/android/Gemfile.lock +++ b/android/Gemfile.lock @@ -10,16 +10,16 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.1006.0) - aws-sdk-core (3.212.0) + aws-partitions (1.1031.0) + aws-sdk-core (3.214.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.95.0) + aws-sdk-kms (1.96.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.170.1) + aws-sdk-s3 (1.177.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -58,8 +58,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) @@ -67,8 +67,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.3.1) - fastlane (2.225.0) + fastimage (2.4.0) + fastlane (2.226.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -108,7 +108,7 @@ GEM tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) + xcpretty (~> 0.4.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) fastlane-plugin-firebase_app_distribution (0.9.1) google-apis-firebaseappdistribution_v1 (~> 0.3.0) @@ -157,12 +157,12 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.7) + http-cookie (1.0.8) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.2) - json (2.8.2) - jwt (2.9.3) + json (2.9.1) + jwt (2.10.1) base64 mini_magick (4.13.2) mini_mime (1.1.5) @@ -173,7 +173,7 @@ GEM nkf (0.2.0) optparse (0.6.0) os (1.1.4) - plist (3.7.1) + plist (3.7.2) public_suffix (6.0.1) rake (13.2.1) representable (3.2.0) @@ -181,10 +181,10 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.3.9) - rouge (2.0.7) + rexml (3.4.0) + rouge (3.28.0) ruby2_keywords (0.0.5) - rubyzip (2.3.2) + rubyzip (2.4.1) security (0.1.5) signet (0.19.0) addressable (~> 2.8) @@ -213,8 +213,8 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) + xcpretty (0.4.0) + rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) @@ -228,4 +228,4 @@ DEPENDENCIES fastlane-plugin-firebase_app_distribution BUNDLED WITH - 2.5.23 + 2.6.2 diff --git a/assets/config_authentication_cloud.json b/assets/config_authentication_cloud.json index 2df41a9..d118467 100644 --- a/assets/config_authentication_cloud.json +++ b/assets/config_authentication_cloud.json @@ -5,11 +5,7 @@ }, "sdk": { "hostname": "myinstance.mauth.nevis.cloud", - "facetId": "android:apk-key-hash:ch.nevis.mobile.authentication.sdk.flutter.example", - "networkTimeoutInSeconds": "60", - "authenticationMaxRetries": 3, - "authenticationRetryIntervalInSeconds": "1", - "userInteractionTimeoutInSeconds": "240" + "facetId": "android:apk-key-hash:ch.nevis.mobile.authentication.sdk.flutter.example" }, "authenticatorAllowlist": [ "F1D0#0001", diff --git a/assets/config_identity_suite.json b/assets/config_identity_suite.json index b061fae..7d71f47 100644 --- a/assets/config_identity_suite.json +++ b/assets/config_identity_suite.json @@ -12,11 +12,7 @@ "authenticationResponsePath": "/auth/fidouaf/authenticationresponse/", "deregistrationRequestPath": "/nevisfido/uaf/1.1/request/deregistration/", "dispatchTargetResourcePath": "/nevisfido/token/dispatch/targets/", - "deviceResourcePath": "/nevisfido/devices/", - "networkTimeoutInSeconds": "60", - "authenticationMaxRetries": 3, - "authenticationRetryIntervalInSeconds": "1", - "userInteractionTimeoutInSeconds": "240" + "deviceResourcePath": "/nevisfido/devices/" }, "authenticatorAllowlist": [ "F1D0#0001", diff --git a/ios/Gemfile.lock b/ios/Gemfile.lock index 7394adf..35a44bb 100644 --- a/ios/Gemfile.lock +++ b/ios/Gemfile.lock @@ -5,7 +5,7 @@ GEM base64 nkf rexml - activesupport (7.2.2) + activesupport (7.2.2.1) base64 benchmark (>= 0.3) bigdecimal @@ -25,16 +25,16 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.1006.0) - aws-sdk-core (3.212.0) + aws-partitions (1.1031.0) + aws-sdk-core (3.214.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.95.0) + aws-sdk-kms (1.96.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.170.1) + aws-sdk-s3 (1.177.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) @@ -43,7 +43,7 @@ GEM babosa (1.0.4) base64 (0.2.0) benchmark (0.4.0) - bigdecimal (3.1.8) + bigdecimal (3.1.9) claide (1.1.0) cocoapods (1.16.2) addressable (~> 2.8) @@ -118,8 +118,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) @@ -127,8 +127,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.3.1) - fastlane (2.225.0) + fastimage (2.4.0) + fastlane (2.226.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -168,16 +168,16 @@ GEM tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) + xcpretty (~> 0.4.0) xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) fastlane-plugin-firebase_app_distribution (0.9.1) google-apis-firebaseappdistribution_v1 (~> 0.3.0) google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) fastlane-sirp (1.0.0) sysrandom (~> 1.0) - ffi (1.17.0) - ffi (1.17.0-arm64-darwin) - ffi (1.17.0-x86_64-darwin) + ffi (1.17.1) + ffi (1.17.1-arm64-darwin) + ffi (1.17.1-x86_64-darwin) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -222,19 +222,19 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.7) + http-cookie (1.0.8) domain_name (~> 0.5) httpclient (2.8.3) i18n (1.14.6) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.8.2) - jwt (2.9.3) + json (2.9.1) + jwt (2.10.1) base64 - logger (1.6.1) + logger (1.6.4) mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.1) + minitest (5.25.4) molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.4.1) @@ -245,7 +245,7 @@ GEM nkf (0.2.0) optparse (0.6.0) os (1.1.4) - plist (3.7.1) + plist (3.7.2) public_suffix (4.0.7) rake (13.2.1) representable (3.2.0) @@ -253,12 +253,12 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.3.9) - rouge (2.0.7) + rexml (3.4.0) + rouge (3.28.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) - rubyzip (2.3.2) - securerandom (0.3.2) + rubyzip (2.4.1) + securerandom (0.4.1) security (0.1.5) signet (0.19.0) addressable (~> 2.8) @@ -291,8 +291,8 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) + xcpretty (0.4.0) + rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) @@ -307,4 +307,4 @@ DEPENDENCIES fastlane-plugin-firebase_app_distribution BUNDLED WITH - 2.5.23 + 2.6.2 diff --git a/lib/configuration/configuration_loader.dart b/lib/configuration/configuration_loader.dart index 534ee58..7c6ce9b 100644 --- a/lib/configuration/configuration_loader.dart +++ b/lib/configuration/configuration_loader.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:injectable/injectable.dart'; +import 'package:nevis_mobile_authentication_sdk/nevis_mobile_authentication_sdk.dart'; import 'package:nevis_mobile_authentication_sdk_example_app_flutter/configuration/model/app_configuration.dart'; import 'package:nevis_mobile_authentication_sdk_example_app_flutter/configuration/model/app_environment.dart'; @@ -13,16 +14,55 @@ const identitySuite = Environment('identitySuite'); abstract class ConfigurationLoader { AppEnvironment get environment; - AppConfiguration? configuration; - Future load() async { - if (configuration != null) return Future.value(configuration); + AppConfiguration? _appConfiguration; + Configuration? _sdkConfiguration; + + Future appConfiguration() async { + if (_appConfiguration != null) { + return Future.value(_appConfiguration); + } final configFile = environment.configFileName; final jsonString = await rootBundle.loadString('assets/$configFile'); final dynamic jsonMap = jsonDecode(jsonString); - configuration = AppConfiguration.fromJson(jsonMap); - return Future.value(configuration); + _appConfiguration = AppConfiguration.fromJson(jsonMap); + return Future.value(_appConfiguration); + } + + Future sdkConfiguration() async { + if (_sdkConfiguration != null) { + return Future.value(_sdkConfiguration); + } + + final appConfiguration = await this.appConfiguration(); + switch (environment) { + case AppEnvironment.authenticationCloud: + _sdkConfiguration = Configuration.authCloudBuilder() + .hostname(appConfiguration.sdk.hostname!) + .facetId(appConfiguration.sdk.facetId!) + .build(); + case AppEnvironment.identitySuite: + _sdkConfiguration = Configuration.builder() + .baseUrl(appConfiguration.sdk.baseUrl!) + .facetId(appConfiguration.sdk.facetId!) + .registrationRequestPath( + appConfiguration.sdk.registrationRequestPath!) + .registrationResponsePath( + appConfiguration.sdk.registrationResponsePath!) + .authenticationRequestPath( + appConfiguration.sdk.authenticationRequestPath!) + .authenticationResponsePath( + appConfiguration.sdk.authenticationResponsePath!) + .deregistrationRequestPath( + appConfiguration.sdk.deregistrationRequestPath!) + .dispatchTargetResourcePath( + appConfiguration.sdk.dispatchTargetResourcePath!) + .deviceResourcePath(appConfiguration.sdk.deviceResourcePath!) + .build(); + } + + return Future.value(_sdkConfiguration!); } } diff --git a/lib/configuration/model/app_configuration.dart b/lib/configuration/model/app_configuration.dart index 3ad2834..28044b5 100644 --- a/lib/configuration/model/app_configuration.dart +++ b/lib/configuration/model/app_configuration.dart @@ -1,8 +1,8 @@ // Copyright © 2022 Nevis Security AG. All rights reserved. import 'package:json_annotation/json_annotation.dart'; -import 'package:nevis_mobile_authentication_sdk/nevis_mobile_authentication_sdk.dart'; import 'package:nevis_mobile_authentication_sdk_example_app_flutter/configuration/model/login_configuration.dart'; +import 'package:nevis_mobile_authentication_sdk_example_app_flutter/configuration/model/sdk_configuration.dart'; part 'app_configuration.g.dart'; @@ -32,13 +32,13 @@ class AppConfiguration { LoginConfiguration loginConfiguration; @JsonKey(name: "sdk") - Configuration sdkConfiguration; + SdkConfiguration sdk; AppConfiguration({ required this.allowClass2Sensors, required this.authenticatorAllowlist, required this.loginConfiguration, - required this.sdkConfiguration, + required this.sdk, }); factory AppConfiguration.fromJson(Map json) => diff --git a/lib/configuration/model/app_configuration.g.dart b/lib/configuration/model/app_configuration.g.dart index 2690a5e..09c0077 100644 --- a/lib/configuration/model/app_configuration.g.dart +++ b/lib/configuration/model/app_configuration.g.dart @@ -14,8 +14,7 @@ AppConfiguration _$AppConfigurationFromJson(Map json) => .toList(), loginConfiguration: LoginConfiguration.fromJson(json['login'] as Map), - sdkConfiguration: - Configuration.fromJson(json['sdk'] as Map), + sdk: SdkConfiguration.fromJson(json['sdk'] as Map), ); Map _$AppConfigurationToJson(AppConfiguration instance) => @@ -23,5 +22,5 @@ Map _$AppConfigurationToJson(AppConfiguration instance) => 'allowClass2Sensors': instance.allowClass2Sensors, 'authenticatorAllowlist': instance.authenticatorAllowlist, 'login': instance.loginConfiguration.toJson(), - 'sdk': instance.sdkConfiguration.toJson(), + 'sdk': instance.sdk.toJson(), }; diff --git a/lib/configuration/model/sdk_configuration.dart b/lib/configuration/model/sdk_configuration.dart new file mode 100644 index 0000000..b36f8c0 --- /dev/null +++ b/lib/configuration/model/sdk_configuration.dart @@ -0,0 +1,40 @@ +// Copyright © 2024 Nevis Security AG. All rights reserved. + +import 'package:json_annotation/json_annotation.dart'; + +part 'sdk_configuration.g.dart'; + +@JsonSerializable() +class SdkConfiguration { + String? baseUrl; + String? hostname; + String? facetId; + String? registrationRequestPath; + String? registrationResponsePath; + String? authenticationRequestPath; + String? authenticationResponsePath; + String? deregistrationRequestPath; + String? dispatchTargetResourcePath; + String? deviceResourcePath; + + SdkConfiguration( + this.baseUrl, + this.hostname, + this.facetId, + this.registrationRequestPath, + this.registrationResponsePath, + this.authenticationRequestPath, + this.authenticationResponsePath, + this.deregistrationRequestPath, + this.dispatchTargetResourcePath, + this.deviceResourcePath, + ); + + factory SdkConfiguration.fromJson(Map json) => + _$SdkConfigurationFromJson(json); + + SdkConfiguration fromJson(Map json) => + SdkConfiguration.fromJson(json); + + Map toJson() => _$SdkConfigurationToJson(this); +} diff --git a/lib/configuration/model/sdk_configuration.g.dart b/lib/configuration/model/sdk_configuration.g.dart new file mode 100644 index 0000000..facd525 --- /dev/null +++ b/lib/configuration/model/sdk_configuration.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sdk_configuration.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SdkConfiguration _$SdkConfigurationFromJson(Map json) => + SdkConfiguration( + json['baseUrl'] as String?, + json['hostname'] as String?, + json['facetId'] as String?, + json['registrationRequestPath'] as String?, + json['registrationResponsePath'] as String?, + json['authenticationRequestPath'] as String?, + json['authenticationResponsePath'] as String?, + json['deregistrationRequestPath'] as String?, + json['dispatchTargetResourcePath'] as String?, + json['deviceResourcePath'] as String?, + ); + +Map _$SdkConfigurationToJson(SdkConfiguration instance) => + { + 'baseUrl': instance.baseUrl, + 'hostname': instance.hostname, + 'facetId': instance.facetId, + 'registrationRequestPath': instance.registrationRequestPath, + 'registrationResponsePath': instance.registrationResponsePath, + 'authenticationRequestPath': instance.authenticationRequestPath, + 'authenticationResponsePath': instance.authenticationResponsePath, + 'deregistrationRequestPath': instance.deregistrationRequestPath, + 'dispatchTargetResourcePath': instance.dispatchTargetResourcePath, + 'deviceResourcePath': instance.deviceResourcePath, + }; diff --git a/lib/domain/interaction/authenticator_selector_impl.dart b/lib/domain/interaction/authenticator_selector_impl.dart index ea8f5e4..c51c291 100644 --- a/lib/domain/interaction/authenticator_selector_impl.dart +++ b/lib/domain/interaction/authenticator_selector_impl.dart @@ -31,18 +31,18 @@ abstract class AuthenticatorSelectorImpl implements AuthenticatorSelector { ) async { debugPrint('Please select one of the received available authenticators!'); - final configuration = await configurationLoader.load(); + final appConfiguration = await configurationLoader.appConfiguration(); Set authenticators = {}; switch (operation) { case Operation.registration: authenticators = await authenticatorValidator.validateForRegistration( context, - configuration.authenticatorAllowlist, + appConfiguration.authenticatorAllowlist, ); case Operation.authentication: authenticators = authenticatorValidator.validateForAuthentication( context, - configuration.authenticatorAllowlist, + appConfiguration.authenticatorAllowlist, ); } @@ -61,7 +61,7 @@ abstract class AuthenticatorSelectorImpl implements AuthenticatorSelector { isPolicyCompliant: await context.isPolicyCompliant(item.aaid), isUserEnrolled: item.isEnrolled( context.account.username, - configuration.allowClass2Sensors, + appConfiguration.allowClass2Sensors, ), ), ); diff --git a/lib/ui/app_state/app_bloc.dart b/lib/ui/app_state/app_bloc.dart index 3204a32..9f99b14 100644 --- a/lib/ui/app_state/app_bloc.dart +++ b/lib/ui/app_state/app_bloc.dart @@ -142,24 +142,24 @@ class AppBloc extends Bloc { Future _handleAuthenticationSucceeded( DomainAuthenticationSucceededState state, ) async { - // based on current backend configuration FIDO UAF authentication is needed for deregistration - // and dispatch target deletion in the Identity Suite environment. - // The result of the authentication is handled (username + auth provider) and based on the requested operation type - // the corresponding use case will be executed. + // based on current backend configuration FIDO UAF authentication is needed + // for deregistration and dispatch target deletion in the Identity Suite environment. + // The result of the authentication is handled (username + auth provider) and + // based on the requested operation type the corresponding use case will be executed. final username = state.username; AuthorizationProvider? authorizationProvider = state.authorizationProvider; if (authorizationProvider is CookieAuthorizationProvider) { // if a cookie auth provider is received, we need to fill in the correct uri - final configuration = await _configurationLoader.load(); + final sdkConfiguration = await _configurationLoader.sdkConfiguration(); String? path; if (state.operationType == OperationType.deregistration) { - path = configuration.sdkConfiguration.deregistrationRequestPath; + path = sdkConfiguration.deregistrationRequestPath; } else { _errorHandler.handle(BusinessException.invalidState()); return; } - final uri = Uri.parse(configuration.sdkConfiguration.baseUrl + path); + final uri = Uri.parse(sdkConfiguration.baseUrl + path); for (CookieContainer container in authorizationProvider.cookieContainers) { container.uri = uri; diff --git a/lib/ui/screens/home/home_bloc.dart b/lib/ui/screens/home/home_bloc.dart index a433e7a..d0e2092 100644 --- a/lib/ui/screens/home/home_bloc.dart +++ b/lib/ui/screens/home/home_bloc.dart @@ -125,8 +125,8 @@ class HomeBloc extends Bloc { } Future _initClient(Emitter emit) async { - final configuration = await _configurationLoader.load(); - return await _clientProvider.init(configuration.sdkConfiguration, () async { + final sdkConfiguration = await _configurationLoader.sdkConfiguration(); + return await _clientProvider.init(sdkConfiguration, () async { add(ClientInitializedEvent()); }).catchError((error) { _yieldBasedOnCurrentState(emit); diff --git a/lib/ui/screens/legacy_login/legacy_login_bloc.dart b/lib/ui/screens/legacy_login/legacy_login_bloc.dart index 26d804c..1013f80 100644 --- a/lib/ui/screens/legacy_login/legacy_login_bloc.dart +++ b/lib/ui/screens/legacy_login/legacy_login_bloc.dart @@ -31,8 +31,8 @@ class LegacyLoginBloc extends Bloc { ConfirmEvent event, Emitter emit, ) async { - final configuration = await _configurationLoader.load(); - final uri = Uri.parse(configuration.loginConfiguration.loginRequestURL); + final appConfiguration = await _configurationLoader.appConfiguration(); + final uri = Uri.parse(appConfiguration.loginConfiguration.loginRequestURL); final loginRequest = LoginRequest( username: event.username, password: event.password,