TF-624 Implement logout oidc on browser

This commit is contained in:
dab246
2022-06-07 20:53:09 +07:00
committed by Dat H. Pham
parent dcaa340fa1
commit 9c9e12dedc
13 changed files with 86 additions and 72 deletions
@@ -13,6 +13,8 @@ import 'package:tmail_ui_user/features/login/domain/state/get_credential_state.d
import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart';
import 'package:tmail_ui_user/features/login/domain/usecases/get_credential_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_credential_interactor.dart';
import 'package:tmail_ui_user/features/login/presentation/login_form_type.dart';
import 'package:tmail_ui_user/features/login/presentation/model/login_arguments.dart';
import 'package:tmail_ui_user/features/manage_account/domain/state/log_out_oidc_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/log_out_oidc_state.dart';
import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart';
import 'package:tmail_ui_user/features/session/domain/state/get_session_state.dart'; import 'package:tmail_ui_user/features/session/domain/state/get_session_state.dart';
@@ -41,7 +43,7 @@ abstract class ReloadableController extends BaseController {
viewState.value.fold( viewState.value.fold(
(failure) { (failure) {
if (failure is GetCredentialFailure) { if (failure is GetCredentialFailure) {
goToLogin(); _goToLogin();
} else if (failure is GetSessionFailure) { } else if (failure is GetSessionFailure) {
_handleGetSessionFailure(); _handleGetSessionFailure();
} else if (failure is LogoutOidcFailure) { } else if (failure is LogoutOidcFailure) {
@@ -71,8 +73,8 @@ abstract class ReloadableController extends BaseController {
consumeState(_getCredentialInteractor.execute().asStream()); consumeState(_getCredentialInteractor.execute().asStream());
} }
void goToLogin() { void _goToLogin({LoginArguments? arguments}) {
pushAndPopAll(AppRoutes.LOGIN); pushAndPopAll(AppRoutes.LOGIN, arguments: arguments);
} }
void _setUpInterceptors(GetCredentialViewState credentialViewState) { void _setUpInterceptors(GetCredentialViewState credentialViewState) {
@@ -92,13 +94,12 @@ abstract class ReloadableController extends BaseController {
consumeState(_getSessionInteractor.execute().asStream()); consumeState(_getSessionInteractor.execute().asStream());
} }
void _handleGetSessionFailure() { void _handleGetSessionFailure() async {
_deleteCredentialAction(); await Future.wait([
goToLogin(); _deleteCredentialInteractor.execute(),
} _cachingManager.clearAll(),
]);
void _deleteCredentialAction() async { _goToLogin();
await _deleteCredentialInteractor.execute();
} }
void _handleGetSessionSuccess(GetSessionSuccess success) { void _handleGetSessionSuccess(GetSessionSuccess success) {
@@ -118,7 +119,8 @@ abstract class ReloadableController extends BaseController {
]); ]);
_authorizationInterceptors.clear(); _authorizationInterceptors.clear();
goToLogin(); await HiveCacheConfig().closeHive();
_goToLogin();
} }
} }
@@ -131,6 +133,7 @@ abstract class ReloadableController extends BaseController {
]); ]);
_authorizationInterceptors.clear(); _authorizationInterceptors.clear();
goToLogin(); await HiveCacheConfig().closeHive();
_goToLogin(arguments: LoginArguments(LoginFormType.ssoForm));
} }
} }
@@ -99,15 +99,11 @@ class AccountCacheClient extends HiveCacheClient<AccountCache> {
} }
@override @override
Future<Box<AccountCache>> openBox() { Future<Box<AccountCache>> openBox() async {
return Future.sync(() async { if (Hive.isBoxOpen(tableName)) {
if (Hive.isBoxOpen(tableName)) { return Hive.box<AccountCache>(tableName);
return Hive.box<AccountCache>(tableName); }
} return Hive.openBox<AccountCache>(tableName);
return await Hive.openBox<AccountCache>(tableName);
}).catchError((error) {
throw error;
});
} }
@override @override
+5 -9
View File
@@ -11,15 +11,11 @@ class EmailCacheClient extends HiveCacheClient<EmailCache> {
String get tableName => 'EmailCache'; String get tableName => 'EmailCache';
@override @override
Future<Box<EmailCache>> openBox() { Future<Box<EmailCache>> openBox() async {
return Future.sync(() async { if (Hive.isBoxOpen(tableName)) {
if (Hive.isBoxOpen(tableName)) { return Hive.box<EmailCache>(tableName);
return Hive.box<EmailCache>(tableName); }
} return Hive.openBox<EmailCache>(tableName);
return await Hive.openBox<EmailCache>(tableName);
}).catchError((error) {
throw error;
});
} }
@override @override
@@ -9,15 +9,11 @@ class MailboxCacheClient extends HiveCacheClient<MailboxCache> {
String get tableName => 'MailboxCache'; String get tableName => 'MailboxCache';
@override @override
Future<Box<MailboxCache>> openBox() { Future<Box<MailboxCache>> openBox() async {
return Future.sync(() async { if (Hive.isBoxOpen(tableName)) {
if (Hive.isBoxOpen(tableName)) { return Hive.box<MailboxCache>(tableName);
return Hive.box<MailboxCache>(tableName); }
} return Hive.openBox<MailboxCache>(tableName);
return await Hive.openBox<MailboxCache>(tableName);
}).catchError((error) {
throw error;
});
} }
@override @override
@@ -88,15 +88,11 @@ class RecentSearchCacheClient extends HiveCacheClient<RecentSearchCache> {
} }
@override @override
Future<Box<RecentSearchCache>> openBox() { Future<Box<RecentSearchCache>> openBox() async {
return Future.sync(() async { if (Hive.isBoxOpen(tableName)) {
if (Hive.isBoxOpen(tableName)) { return Hive.box<RecentSearchCache>(tableName);
return Hive.box<RecentSearchCache>(tableName); }
} return Hive.openBox<RecentSearchCache>(tableName);
return await Hive.openBox<RecentSearchCache>(tableName);
}).catchError((error) {
throw error;
});
} }
@override @override
+5 -9
View File
@@ -9,15 +9,11 @@ class StateCacheClient extends HiveCacheClient<StateCache> {
String get tableName => 'StateCache'; String get tableName => 'StateCache';
@override @override
Future<Box<StateCache>> openBox() { Future<Box<StateCache>> openBox() async {
return Future.sync(() async { if (Hive.isBoxOpen(tableName)) {
if (Hive.isBoxOpen(tableName)) { return Hive.box<StateCache>(tableName);
return Hive.box<StateCache>(tableName); }
} return Hive.openBox<StateCache>(tableName);
return await Hive.openBox<StateCache>(tableName);
}).catchError((error) {
throw error;
});
} }
@override @override
@@ -97,15 +97,11 @@ class TokenOidcCacheClient extends HiveCacheClient<TokenOidcCache> {
} }
@override @override
Future<Box<TokenOidcCache>> openBox() { Future<Box<TokenOidcCache>> openBox() async {
return Future.sync(() async { if (Hive.isBoxOpen(tableName)) {
if (Hive.isBoxOpen(tableName)) { return Hive.box<TokenOidcCache>(tableName);
return Hive.box<TokenOidcCache>(tableName); }
} return Hive.openBox<TokenOidcCache>(tableName);
return await Hive.openBox<TokenOidcCache>(tableName);
}).catchError((error) {
throw error;
});
} }
@override @override
@@ -47,12 +47,12 @@ class AuthenticationOIDCDataSourceImpl extends AuthenticationOIDCDataSource {
} }
@override @override
Future<TokenOIDC> getStoredTokenOIDC(String tokenIdHash) async { Future<TokenOIDC> getStoredTokenOIDC(String tokenIdHash) {
return _tokenOidcCacheManager.getTokenOidc(tokenIdHash); return _tokenOidcCacheManager.getTokenOidc(tokenIdHash);
} }
@override @override
Future<void> persistTokenOIDC(TokenOIDC tokenOidc) async { Future<void> persistTokenOIDC(TokenOIDC tokenOidc) {
return _tokenOidcCacheManager.persistOneTokenOidc(tokenOidc); return _tokenOidcCacheManager.persistOneTokenOidc(tokenOidc);
} }
@@ -45,7 +45,7 @@ class AuthenticationClientMobile implements AuthenticationClientBase {
Future<bool> logoutOidc(TokenId tokenId, OIDCConfiguration config) async { Future<bool> logoutOidc(TokenId tokenId, OIDCConfiguration config) async {
final endSession = await _appAuth.endSession(EndSessionRequest( final endSession = await _appAuth.endSession(EndSessionRequest(
idTokenHint: tokenId.uuid, idTokenHint: tokenId.uuid,
postLogoutRedirectUrl: config.redirectUrl, postLogoutRedirectUrl: config.logoutRedirectUrl,
discoveryUrl: config.discoveryUrl discoveryUrl: config.discoveryUrl
)); ));
log('AuthenticationClientMobile::logoutOidc(): ${endSession?.state}'); log('AuthenticationClientMobile::logoutOidc(): ${endSession?.state}');
@@ -44,8 +44,13 @@ class AuthenticationClientWeb implements AuthenticationClientBase {
} }
@override @override
Future<bool> logoutOidc(TokenId tokenId, OIDCConfiguration config) { Future<bool> logoutOidc(TokenId tokenId, OIDCConfiguration config) async {
throw UnimplementedError(); final endSession = await _appAuthWeb.endSession(EndSessionRequest(
idTokenHint: tokenId.uuid,
postLogoutRedirectUrl: config.logoutRedirectUrl,
discoveryUrl: config.discoveryUrl
));
return endSession != null;
} }
@override @override
@@ -21,7 +21,7 @@ class LogoutOidcInteractor {
Stream<Either<Failure, Success>> execute() async* { Stream<Either<Failure, Success>> execute() async* {
try { try {
final currentAccount = await _accountRepository.getCurrentAccount(); final currentAccount = await _accountRepository.getCurrentAccount();
log('LogoutOidcInteractor::execute(): currentAccount: $currentAccount');
if (currentAccount.authenticationType == AuthenticationType.oidc) { if (currentAccount.authenticationType == AuthenticationType.oidc) {
final result = await Future.wait([ final result = await Future.wait([
_authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id), _authenticationOIDCRepository.getStoredTokenOIDC(currentAccount.id),
@@ -29,6 +29,8 @@ class LogoutOidcInteractor {
]).then((result) async { ]).then((result) async {
final tokenOidc = result.first as TokenOIDC; final tokenOidc = result.first as TokenOIDC;
final oidcConfig = result.last as OIDCConfiguration; final oidcConfig = result.last as OIDCConfiguration;
log('LogoutOidcInteractor::execute(): tokenOidc: ${tokenOidc.tokenId.uuid}');
log('LogoutOidcInteractor::execute(): oidcConfig: $oidcConfig');
return await _authenticationOIDCRepository.logout(tokenOidc.tokenId, oidcConfig); return await _authenticationOIDCRepository.logout(tokenOidc.tokenId, oidcConfig);
}); });
log('LogoutOidcInteractor::execute(): statusSuccess: $result'); log('LogoutOidcInteractor::execute(): statusSuccess: $result');
+3
View File
@@ -5,6 +5,7 @@ import 'package:equatable/equatable.dart';
class OIDCConfiguration with EquatableMixin { class OIDCConfiguration with EquatableMixin {
static const redirectOidcMobile = 'teammail.mobile://oauthredirect'; static const redirectOidcMobile = 'teammail.mobile://oauthredirect';
static const redirectOidcWeb = 'http://localhost:3000/login-callback.html'; static const redirectOidcWeb = 'http://localhost:3000/login-callback.html';
static const logoutRedirectOidcWeb = 'http://localhost:3000/logout-callback.html';
static const wellKnownOpenId = '.well-known/openid-configuration'; static const wellKnownOpenId = '.well-known/openid-configuration';
final String authority; final String authority;
@@ -27,6 +28,8 @@ class OIDCConfiguration with EquatableMixin {
String get redirectUrl => BuildUtils.isWeb ? redirectOidcWeb : redirectOidcMobile; String get redirectUrl => BuildUtils.isWeb ? redirectOidcWeb : redirectOidcMobile;
String get logoutRedirectUrl => BuildUtils.isWeb ? logoutRedirectOidcWeb : redirectOidcMobile;
String get clientIdHash => clientId.hashCode.toString(); String get clientIdHash => clientId.hashCode.toString();
@override @override
+25
View File
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<script>
const AUTH_RESPONSE_KEY = "auth_info";
const CODE_VERIFIER_KEY = "auth_code_verifier";
window.onload = function () {
localStorage.removeItem(AUTH_RESPONSE_KEY);
localStorage.removeItem(CODE_VERIFIER_KEY);
const params = new URLSearchParams(window.location.search)
if (params.has('redirect_uri')) {
const redirect = params.get('redirect_uri');
window.location.replace(redirect);
} else {
window.location.assign("/");
}
}
</script>
</head>
<body>
</body>
</html>