Additional logging for unauthenticated calls (#5121)

additional logging for deeper investigation of https://github.com/flutter/flutter/issues/189892 and https://github.com/flutter/flutter/issues/190495
diff --git a/app_dart/lib/src/request_handling/dashboard_authentication.dart b/app_dart/lib/src/request_handling/dashboard_authentication.dart
index 0118ed5..ac1549d 100644
--- a/app_dart/lib/src/request_handling/dashboard_authentication.dart
+++ b/app_dart/lib/src/request_handling/dashboard_authentication.dart
@@ -69,8 +69,11 @@
     for (final provider in _authenticationChain) {
       try {
         return await provider.authenticate(request);
-      } on Unauthenticated {
-        // nothing
+      } on Unauthenticated catch (e) {
+        // nothing but logging
+        log.info(
+          'Authentication failed for provider: ${provider.runtimeType}, error: $e',
+        );
       }
     }
     throw const Unauthenticated('User is not signed in');
diff --git a/app_dart/test/request_handling/dashboard_authentication_test.dart b/app_dart/test/request_handling/dashboard_authentication_test.dart
index a1c1f74..a7b2c2e 100644
--- a/app_dart/test/request_handling/dashboard_authentication_test.dart
+++ b/app_dart/test/request_handling/dashboard_authentication_test.dart
@@ -2,13 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:convert';
+
 import 'package:cocoon_integration_test/testing.dart';
+import 'package:cocoon_server_test/mocks.mocks.dart';
 import 'package:cocoon_server_test/test_logging.dart';
 import 'package:cocoon_service/cocoon_service.dart';
 import 'package:cocoon_service/src/model/firestore/account.dart';
+import 'package:cocoon_service/src/model/google/firebase_jwt_claim.dart';
 import 'package:cocoon_service/src/model/google/token_info.dart';
 import 'package:cocoon_service/src/request_handling/exceptions.dart';
 import 'package:cocoon_service/src/request_handling/http_io.dart';
+import 'package:cocoon_service/src/service/github_service.dart';
+import 'package:github/github.dart';
+import 'package:http/http.dart' as http;
+import 'package:mockito/mockito.dart';
 import 'package:test/test.dart';
 
 void main() {
@@ -99,4 +107,126 @@
       );
     });
   });
+
+  group('ChainOfAuthentication', () {
+    late ChainOfAuthentication auth;
+    late FakeFirestoreService firestore;
+    late FakeClientContext clientContext;
+    late FakeFirebaseJwtValidator validator;
+    late FakeHttpRequest request;
+    late FakeConfig config;
+
+    setUp(() {
+      firestore = FakeFirestoreService();
+      request = FakeHttpRequest();
+      clientContext = FakeClientContext();
+      validator = FakeFirebaseJwtValidator();
+      config = FakeConfig();
+      auth = ChainOfAuthentication.forProviders([
+        DashboardFirebaseAuthentication(
+          cache: CacheService.inMemory(),
+          clientContextProvider: () => clientContext,
+          validator: validator,
+          firestore: firestore,
+        ),
+        GithubAuthentication(
+          cache: CacheService.inMemory(),
+          config: config,
+          validator: validator,
+          clientContextProvider: () => clientContext,
+        ),
+      ]);
+    });
+
+    test('succeeds for github account with write permissions', () async {
+      const id = 'awesome-id';
+      const user = 'awesome-user';
+      const email = 'awesome-email@github.com';
+      final token = TokenInfo(
+        email: email,
+        issued: DateTime.now(),
+        firebase: const FirebaseJwtClaim(
+          identities: {
+            'github.com': [id],
+          },
+        ),
+      );
+      // Chained providers decode the token twice.
+      validator.jwts.addAll([token, token]);
+
+      final mockGitHub = MockGitHub();
+      final mockUsersService = MockUsersService();
+      when(mockGitHub.users).thenReturn(mockUsersService);
+
+      when(
+        mockUsersService.getUser(id),
+      ).thenAnswer((_) async => User(login: user));
+
+      when(
+        // ignore: discarded_futures
+        mockGitHub.request(
+          'GET',
+          '/repos/flutter/flutter/collaborators/$user/permission',
+          fail: anyNamed('fail'),
+        ),
+      ).thenAnswer((_) async {
+        final data = <String, dynamic>{'permission': 'write'};
+        return http.Response(json.encode(data), HttpStatus.ok);
+      });
+      final githubService = GithubService(mockGitHub);
+
+      config.githubService = githubService;
+      request.headers.set('X-Flutter-IdToken', 'trustmebro');
+      final result = await auth.authenticate(request.toRequest());
+      expect(result.email, email);
+      expect(result.githubLogin, user);
+    });
+
+    test(
+      'succeeds for github account with write permissions and with non-allowed non-googler firebase jwt linked account',
+      () async {
+        const id = 'awesome-id';
+        const user = 'awesome-user';
+        const email = 'awesome-email@gmail.com';
+        final token = TokenInfo(
+          email: email,
+          issued: DateTime.now(),
+          firebase: const FirebaseJwtClaim(
+            identities: {
+              'github.com': [id],
+            },
+          ),
+        );
+        // Chained providers decode the token twice.
+        validator.jwts.addAll([token, token]);
+
+        final mockGitHub = MockGitHub();
+        final mockUsersService = MockUsersService();
+        when(mockGitHub.users).thenReturn(mockUsersService);
+
+        when(
+          mockUsersService.getUser(id),
+        ).thenAnswer((_) async => User(login: user));
+
+        when(
+          // ignore: discarded_futures
+          mockGitHub.request(
+            'GET',
+            '/repos/flutter/flutter/collaborators/$user/permission',
+            fail: anyNamed('fail'),
+          ),
+        ).thenAnswer((_) async {
+          final data = <String, dynamic>{'permission': 'write'};
+          return http.Response(json.encode(data), HttpStatus.ok);
+        });
+        final githubService = GithubService(mockGitHub);
+
+        config.githubService = githubService;
+        request.headers.set('X-Flutter-IdToken', 'trustmebro');
+        final result = await auth.authenticate(request.toRequest());
+        expect(result.email, email);
+        expect(result.githubLogin, user);
+      },
+    );
+  });
 }