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);
+ },
+ );
+ });
}