TF-4049 Pre-fill OIDC login form

This commit is contained in:
dab246
2025-10-13 14:40:25 +07:00
committed by Dat H. Pham
parent 7d80557582
commit 51b85c8b79
12 changed files with 112 additions and 30 deletions
@@ -8,7 +8,13 @@ abstract class AuthenticationOIDCDataSource {
Future<OIDCDiscoveryResponse> discoverOIDC(OIDCConfiguration oidcConfiguration);
Future<TokenOIDC> getTokenOIDC(String clientId, String redirectUrl, String discoveryUrl, List<String> scopes);
Future<TokenOIDC> getTokenOIDC(
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes, {
String? loginHint,
});
Future<void> persistTokenOIDC(TokenOIDC tokenOidc);
@@ -56,9 +56,21 @@ class AuthenticationOIDCDataSourceImpl extends AuthenticationOIDCDataSource {
}
@override
Future<TokenOIDC> getTokenOIDC(String clientId, String redirectUrl, String discoveryUrl, List<String> scopes) {
Future<TokenOIDC> getTokenOIDC(
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes, {
String? loginHint,
}) {
return Future.sync(() async {
return await _authenticationClient.getTokenOIDC(clientId, redirectUrl, discoveryUrl, scopes);
return await _authenticationClient.getTokenOIDC(
clientId,
redirectUrl,
discoveryUrl,
scopes,
loginHint: loginHint,
);
}).catchError(_exceptionThrower.throwException);
}
@@ -13,10 +13,12 @@ abstract class AuthenticationClientBase {
List<String> scopes);
Future<TokenOIDC> getTokenOIDC(
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes);
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes, {
String? loginHint,
});
Future<TokenOIDC> refreshingTokensOIDC(
String clientId,
@@ -59,14 +59,16 @@ mixin AuthenticationClientInteractionMixin {
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes,
) {
List<String> scopes, {
String? loginHint,
}) {
return AuthorizationTokenRequest(
clientId,
redirectUrl,
discoveryUrl: discoveryUrl,
scopes: scopes,
externalUserAgent: getExternalUserAgent(),
loginHint: loginHint,
);
}
@@ -27,13 +27,15 @@ class AuthenticationClientMobile with AuthenticationClientInteractionMixin
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes,
) async {
List<String> scopes, {
String? loginHint,
}) async {
final authorizationTokenRequest = getAuthorizationTokenRequest(
clientId,
redirectUrl,
discoveryUrl,
scopes,
loginHint: loginHint,
);
final authorizationTokenResponse = await _appAuth.authorizeAndExchangeCode(
authorizationTokenRequest,
@@ -25,13 +25,15 @@ class AuthenticationClientWeb with AuthenticationClientInteractionMixin
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes,
) async {
List<String> scopes, {
String? loginHint,
}) async {
final authorizationTokenRequest = getAuthorizationTokenRequest(
clientId,
redirectUrl,
discoveryUrl,
scopes,
loginHint: loginHint,
);
final authorizationTokenResponse = await _appAuthWeb.authorizeAndExchangeCode(
authorizationTokenRequest,
@@ -28,8 +28,20 @@ class AuthenticationOIDCRepositoryImpl extends AuthenticationOIDCRepository {
}
@override
Future<TokenOIDC> getTokenOIDC(String clientId, String redirectUrl, String discoveryUrl, List<String> scopes) {
return _oidcDataSource.getTokenOIDC(clientId, redirectUrl, discoveryUrl, scopes);
Future<TokenOIDC> getTokenOIDC(
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes, {
String? loginHint,
}) {
return _oidcDataSource.getTokenOIDC(
clientId,
redirectUrl,
discoveryUrl,
scopes,
loginHint: loginHint,
);
}
@override
@@ -8,7 +8,13 @@ abstract class AuthenticationOIDCRepository {
Future<OIDCDiscoveryResponse> discoverOIDC(OIDCConfiguration oidcConfiguration);
Future<TokenOIDC> getTokenOIDC(String clientId, String redirectUrl, String discoveryUrl, List<String> scopes);
Future<TokenOIDC> getTokenOIDC(
String clientId,
String redirectUrl,
String discoveryUrl,
List<String> scopes, {
String? loginHint,
});
Future<void> persistTokenOIDC(TokenOIDC tokenOidc);
@@ -2,6 +2,7 @@ import 'package:core/presentation/state/failure.dart';
import 'package:core/presentation/state/success.dart';
import 'package:core/utils/app_logger.dart';
import 'package:dartz/dartz.dart';
import 'package:model/oidc/oidc_configuration.dart';
import 'package:model/oidc/response/oidc_response.dart';
import 'package:tmail_ui_user/features/login/domain/model/base_url_oidc_response.dart';
import 'package:tmail_ui_user/features/login/domain/repository/authentication_oidc_repository.dart';
@@ -12,12 +13,20 @@ class GetOIDCConfigurationInteractor {
GetOIDCConfigurationInteractor(this._oidcRepository);
Stream<Either<Failure, Success>> execute(OIDCResponse oidcResponse) async* {
Stream<Either<Failure, Success>> execute(
OIDCResponse oidcResponse, {
String? loginHint,
}) async* {
try {
yield Right<Failure, Success>(GetOIDCConfigurationLoading());
final oidcConfiguration = await _oidcRepository.getOIDCConfiguration(oidcResponse);
await _oidcRepository.persistOidcConfiguration(oidcConfiguration);
yield Right<Failure, Success>(GetOIDCConfigurationSuccess(oidcConfiguration));
final configWithLoginHint = oidcConfiguration.copyWidth(
loginHint: loginHint,
);
await _oidcRepository.persistOidcConfiguration(configWithLoginHint);
yield Right<Failure, Success>(
GetOIDCConfigurationSuccess(configWithLoginHint),
);
} catch (e) {
logError('$runtimeType::execute():oidcResponse = ${oidcResponse.runtimeType} | Exception = $e');
if (oidcResponse is BaseUrlOidcResponse) {
@@ -27,10 +27,12 @@ class GetTokenOIDCInteractor {
try {
yield Right<Failure, Success>(GetTokenOIDCLoading());
final tokenOIDC = await authenticationOIDCRepository.getTokenOIDC(
config.clientId,
config.redirectUrl,
config.discoveryUrl,
config.scopes);
config.clientId,
config.redirectUrl,
config.discoveryUrl,
config.scopes,
loginHint: config.loginHint,
);
await Future.wait([
_credentialRepository.saveBaseUrl(baseUri),
@@ -188,7 +188,7 @@ class LoginController extends ReloadableController {
} else if (success is CheckOIDCIsAvailableSuccess) {
getOIDCConfiguration(success.oidcResponse);
} else if (success is GetOIDCConfigurationSuccess) {
_getOIDCConfigurationSuccess(success);
_getOIDCConfigurationSuccess(success.oidcConfiguration);
} else if (success is GetTokenOIDCSuccess) {
_getTokenOIDCSuccess(success);
} else if (success is AuthenticationUserSuccess) {
@@ -413,16 +413,23 @@ class LoginController extends ReloadableController {
}
void getOIDCConfiguration(OIDCResponse oidcResponse) {
consumeState(_getOIDCConfigurationInteractor.execute(oidcResponse));
final loginHint = PlatformInfo.isMobile ? _username?.value : null;
log('$runtimeType::getOIDCConfiguration:loginHint = $loginHint');
consumeState(
_getOIDCConfigurationInteractor.execute(
oidcResponse,
loginHint: loginHint,
),
);
}
void _getOIDCConfigurationSuccess(GetOIDCConfigurationSuccess success) {
void _getOIDCConfigurationSuccess(OIDCConfiguration config) {
if (PlatformInfo.isWeb) {
_authenticateOidcOnBrowserAction(success.oidcConfiguration);
} else if (success.oidcConfiguration.authority == AppConfig.saasRegistrationUrl) {
_getTokenOIDCOnSaaSPlatform(success.oidcConfiguration);
_authenticateOidcOnBrowserAction(config);
} else if (config.authority == AppConfig.saasRegistrationUrl) {
_getTokenOIDCOnSaaSPlatform(config);
} else {
_getTokenOIDCAction(success.oidcConfiguration);
_getTokenOIDCAction(config);
}
}
+20
View File
@@ -8,12 +8,14 @@ class OIDCConfiguration with EquatableMixin {
final String clientId;
final List<String> scopes;
final bool isTWP;
final String? loginHint;
OIDCConfiguration({
required this.authority,
required this.clientId,
required this.scopes,
this.isTWP = false,
this.loginHint,
});
String get discoveryUrl {
@@ -30,5 +32,23 @@ class OIDCConfiguration with EquatableMixin {
clientId,
scopes,
isTWP,
loginHint,
];
}
extension OIDCConfigurationExtension on OIDCConfiguration {
OIDCConfiguration copyWidth({
String? authority,
String? clientId,
List<String>? scopes,
bool? isTWP,
String? loginHint,
}) =>
OIDCConfiguration(
authority: authority ?? this.authority,
clientId: clientId ?? this.clientId,
scopes: scopes ?? this.scopes,
isTWP: isTWP ?? this.isTWP,
loginHint: loginHint ?? this.loginHint,
);
}