| // Copyright 2019 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:io'; |
| |
| import 'package:cocoon_service/src/request_handling/authentication.dart' show AuthenticatedContext; |
| import 'package:cocoon_service/src/request_handling/exceptions.dart'; |
| import 'package:cocoon_service/src/request_handling/pubsub_authentication.dart'; |
| import 'package:cocoon_service/src/service/config.dart'; |
| import 'package:http/http.dart' as http; |
| import 'package:http/testing.dart'; |
| import 'package:test/test.dart'; |
| |
| import '../src/datastore/fake_config.dart'; |
| import '../src/request_handling/fake_authentication.dart'; |
| import '../src/request_handling/fake_http.dart'; |
| |
| void main() { |
| group('PubsubAuthenticationProvider', () { |
| late FakeConfig config; |
| late FakeClientContext clientContext; |
| late FakeHttpRequest request; |
| late PubsubAuthenticationProvider auth; |
| late MockClient httpClient; |
| |
| setUp(() { |
| config = FakeConfig(); |
| clientContext = FakeClientContext(); |
| request = FakeHttpRequest(); |
| auth = PubsubAuthenticationProvider( |
| config: config, |
| clientContextProvider: () => clientContext, |
| httpClientProvider: () => httpClient, |
| ); |
| }); |
| |
| for (String allowedAccount in Config.allowedPubsubServiceAccounts) { |
| test('auth succeeds for $allowedAccount', () async { |
| httpClient = MockClient( |
| (_) async => http.Response( |
| _generateTokenResponse(allowedAccount), |
| HttpStatus.ok, |
| headers: <String, String>{ |
| HttpHeaders.contentTypeHeader: 'application/json', |
| }, |
| ), |
| ); |
| auth = PubsubAuthenticationProvider( |
| config: config, |
| clientContextProvider: () => clientContext, |
| httpClientProvider: () => httpClient, |
| ); |
| |
| request.headers.add(HttpHeaders.authorizationHeader, 'Bearer token'); |
| |
| final AuthenticatedContext result = await auth.authenticate(request); |
| expect(result.clientContext, same(clientContext)); |
| }); |
| } |
| |
| test('auth fails with unauthorized service account', () async { |
| httpClient = MockClient( |
| (_) async => http.Response( |
| _generateTokenResponse('unauthorized@gmail.com'), |
| HttpStatus.ok, |
| headers: <String, String>{ |
| HttpHeaders.contentTypeHeader: 'application/json', |
| }, |
| ), |
| ); |
| auth = PubsubAuthenticationProvider( |
| config: config, |
| clientContextProvider: () => clientContext, |
| httpClientProvider: () => httpClient, |
| ); |
| |
| request.headers.add(HttpHeaders.authorizationHeader, 'Bearer token'); |
| |
| expect(auth.authenticate(request), throwsA(isA<Unauthenticated>())); |
| }); |
| |
| test('auth fails with invalid token', () async { |
| httpClient = MockClient( |
| (_) async => http.Response( |
| 'Invalid token', |
| HttpStatus.unauthorized, |
| headers: <String, String>{ |
| HttpHeaders.contentTypeHeader: 'application/json', |
| }, |
| ), |
| ); |
| auth = PubsubAuthenticationProvider( |
| config: config, |
| clientContextProvider: () => clientContext, |
| httpClientProvider: () => httpClient, |
| ); |
| |
| request.headers.add(HttpHeaders.authorizationHeader, 'Bearer token'); |
| |
| expect(auth.authenticate(request), throwsA(isA<FormatException>())); |
| }); |
| |
| test('auth fails with expired token', () async { |
| httpClient = MockClient( |
| (_) async => http.Response( |
| _generateTokenResponse( |
| Config.allowedPubsubServiceAccounts.first, |
| expiresIn: -1, |
| ), |
| HttpStatus.ok, |
| headers: <String, String>{ |
| HttpHeaders.contentTypeHeader: 'application/json', |
| }, |
| ), |
| ); |
| auth = PubsubAuthenticationProvider( |
| config: config, |
| clientContextProvider: () => clientContext, |
| httpClientProvider: () => httpClient, |
| ); |
| |
| request.headers.add(HttpHeaders.authorizationHeader, 'Bearer token'); |
| |
| expect(auth.authenticate(request), throwsA(isA<Unauthenticated>())); |
| }); |
| }); |
| } |
| |
| /// Return Google's OAuth response. |
| String _generateTokenResponse( |
| String email, { |
| int expiresIn = 123, |
| }) { |
| return '''{ |
| "issued_to": "456", |
| "audience": "https://flutter-dashboard.appspot.com/api/luci-status-handler", |
| "user_id": "789", |
| "expires_in": $expiresIn, |
| "email": "$email", |
| "verified_email": true, |
| "issuer": "https://accounts.google.com", |
| "issued_at": 412321 |
| }'''; |
| } |