LCOV - code coverage report
Current view: top level - lib/network - apptive_grid_authenticator.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 80 81 98.8 %
Date: 2021-10-19 14:11:19 Functions: 0 0 -

          Line data    Source code
       1             : part of apptive_grid_network;
       2             : 
       3             : /// Class for handling authentication related methods for ApptiveGrid
       4             : class ApptiveGridAuthenticator {
       5             :   /// Create a new [ApptiveGridAuthenticator] for [apptiveGridClient]
       6           3 :   ApptiveGridAuthenticator({
       7             :     this.options = const ApptiveGridOptions(),
       8             :     this.httpClient,
       9             :   }) {
      10             :     if (!kIsWeb) {
      11           6 :       _authCallbackSubscription = uni_links.uriLinkStream
      12           3 :           .where(
      13           1 :             (event) =>
      14             :                 event != null &&
      15           2 :                 event.scheme ==
      16           4 :                     options.authenticationOptions.redirectScheme?.toLowerCase(),
      17             :           )
      18           5 :           .listen((event) => _handleAuthRedirect(event!));
      19             :     }
      20             :   }
      21             : 
      22             :   /// [ApptiveGridOptions] used for getting the correct [ApptiveGridEnvironment.authRealm]
      23             :   /// and checking if authentication should automatically be handled
      24             :   ApptiveGridOptions options;
      25             : 
      26           2 :   Uri get _uri => Uri.parse(
      27           4 :         'https://iam.zweidenker.de/auth/realms/${options.environment.authRealm}',
      28             :       );
      29             : 
      30             :   /// Http Client that should be used for Auth Requests
      31             :   final http.Client? httpClient;
      32             : 
      33             :   Client? _authClient;
      34             : 
      35             :   TokenResponse? _token;
      36             :   Credential? _credential;
      37             : 
      38             :   /// Override the token for testing purposes
      39           1 :   @visibleForTesting
      40           1 :   void setToken(TokenResponse token) => _token = token;
      41             : 
      42             :   /// Override the Credential for testing purposes
      43           1 :   @visibleForTesting
      44           1 :   void setCredential(Credential credential) => _credential = credential;
      45             : 
      46             :   /// Override the [Client] for testing purposes
      47           1 :   @visibleForTesting
      48           1 :   void setAuthClient(Client client) => _authClient = client;
      49             : 
      50             :   /// Override the [Authenticator] for testing purposes
      51             :   @visibleForTesting
      52             :   Authenticator? testAuthenticator;
      53             : 
      54             :   late final StreamSubscription<Uri?>? _authCallbackSubscription;
      55             : 
      56           1 :   Future<Client> get _client async {
      57           1 :     Future<Client> createClient() async {
      58           4 :       final issuer = await Issuer.discover(_uri, httpClient: httpClient);
      59           2 :       return Client(issuer, 'app', httpClient: httpClient, clientSecret: '');
      60             :     }
      61             : 
      62           2 :     return _authClient ??= await createClient();
      63             :   }
      64             : 
      65             :   /// Used to test implementation of get _client
      66           1 :   @visibleForTesting
      67           1 :   Future<Client> get authClient => _client;
      68             : 
      69             :   /// Open the Authentication Webpage
      70             :   ///
      71             :   /// Returns [Credential] from the authentication call
      72           1 :   Future<Credential?> authenticate() async {
      73           2 :     final client = await _client;
      74             : 
      75           1 :     final authenticator = testAuthenticator ??
      76           1 :         Authenticator(
      77             :           client,
      78           1 :           scopes: [],
      79           1 :           urlLauncher: _launchUrl,
      80           3 :           redirectUri: options.authenticationOptions.redirectScheme != null
      81           1 :               ? Uri(
      82           3 :                   scheme: options.authenticationOptions.redirectScheme,
      83           5 :                   host: Uri.parse(options.environment.url).host,
      84             :                 )
      85             :               : null,
      86             :         );
      87           3 :     _credential = await authenticator.authorize();
      88             : 
      89           4 :     _token = await _credential?.getTokenResponse();
      90             : 
      91             :     try {
      92           2 :       await closeWebView();
      93           1 :     } on MissingPluginException {
      94           1 :       debugPrint('closeWebView is not available on this platform');
      95           1 :     } on UnimplementedError {
      96           1 :       debugPrint('closeWebView is not available on this platform');
      97             :     }
      98             : 
      99           1 :     return _credential;
     100             :   }
     101             : 
     102           1 :   Future<void> _handleAuthRedirect(Uri uri) async {
     103           2 :     final client = await _client;
     104           2 :     client.createCredential(refreshToken: _token?.refreshToken);
     105           1 :     final authenticator = testAuthenticator ??
     106           1 :         Authenticator(
     107             :           client, // coverage:ignore-line
     108           3 :           redirectUri: options.authenticationOptions.redirectScheme != null
     109           1 :               ? Uri(
     110           3 :                   scheme: options.authenticationOptions.redirectScheme,
     111           5 :                   host: Uri.parse(options.environment.url).host,
     112             :                 )
     113             :               : null,
     114           1 :           urlLauncher: _launchUrl,
     115             :         );
     116             : 
     117           3 :     await authenticator.processResult(uri.queryParameters);
     118             :   }
     119             : 
     120             :   /// Dispose any resources in the Authenticator
     121           3 :   void dispose() {
     122           6 :     _authCallbackSubscription?.cancel();
     123             :   }
     124             : 
     125             :   /// Checks the authentication status and performs actions depending on the status
     126             :   ///
     127             :   /// If there is a [ApptiveGridAuthenticationOptions.apiKey] is set in [options] this will return without any Action
     128             :   ///
     129             :   /// If the User is not authenticated and [ApptiveGridAuthenticationOptions.autoAuthenticate] is true this will call [authenticate]
     130             :   ///
     131             :   /// If the token is expired it will refresh the token using the refresh token
     132           2 :   Future<void> checkAuthentication() async {
     133           2 :     if (_token == null) {
     134           6 :       if (options.authenticationOptions.apiKey != null) {
     135             :         // User has ApiKey provided
     136             :         return;
     137           6 :       } else if (options.authenticationOptions.autoAuthenticate) {
     138           2 :         await authenticate();
     139             :       }
     140           6 :     } else if ((_token?.expiresAt?.difference(DateTime.now()).inSeconds ?? 0) <
     141             :         70) {
     142           4 :       _token = await _credential?.getTokenResponse(true);
     143             :     }
     144             :   }
     145             : 
     146             :   /// Performs a call to Logout the User
     147             :   ///
     148             :   /// even if the Call Fails the token and credential will be cleared
     149           2 :   Future<http.Response?> logout() async {
     150           3 :     final logoutUrl = _credential?.generateLogoutUrl();
     151             :     http.Response? response;
     152             :     if (logoutUrl != null) {
     153           3 :       response = await (httpClient ?? http.Client()).get(
     154             :         logoutUrl,
     155           1 :         headers: {
     156           1 :           HttpHeaders.authorizationHeader: header!,
     157             :         },
     158             :       );
     159             :     }
     160           2 :     _token = null;
     161           2 :     _credential = null;
     162           2 :     _authClient = null;
     163             : 
     164             :     return response;
     165             :   }
     166             : 
     167             :   /// If there is a authenticated User this will return the authentication header
     168             :   ///
     169             :   /// User Authentication is prioritized over ApiKey Authentication
     170           2 :   String? get header {
     171           2 :     if (_token != null) {
     172           1 :       final token = _token!;
     173           3 :       return '${token.tokenType} ${token.accessToken}';
     174             :     }
     175           6 :     if (options.authenticationOptions.apiKey != null) {
     176           3 :       final apiKey = options.authenticationOptions.apiKey!;
     177           6 :       return 'Basic ${base64Encode(utf8.encode('${apiKey.authKey}:${apiKey.password}'))}';
     178             :     }
     179             :   }
     180             : 
     181           1 :   Future<void> _launchUrl(String url) async {
     182           2 :     if (await canLaunch(url)) {
     183             :       try {
     184           2 :         await launch(url);
     185           0 :       } on PlatformException {
     186             :         // Could not launch Url
     187             :       }
     188             :     }
     189             :   }
     190             : 
     191             :   /// Checks if the User is Authenticated
     192           1 :   bool get isAuthenticated =>
     193           4 :       options.authenticationOptions.apiKey != null || _token != null;
     194             : }
     195             : 
     196             : /// Interface to provide common functionality for authorization operations
     197             : abstract class IAuthenticator {
     198             :   /// Authorizes the User against the Auth Server
     199             :   Future<Credential?> authorize();
     200             : }

Generated by: LCOV version 1.15