Skip to content

Commit

Permalink
refactor(googleapis_auth): rename AuthProvider to AuthEndpoints (#1755)
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanoltman authored Feb 26, 2024
1 parent 67a06e7 commit a330d52
Show file tree
Hide file tree
Showing 25 changed files with 128 additions and 125 deletions.
44 changes: 22 additions & 22 deletions packages/shorebird_cli/lib/src/auth/auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'package:http/http.dart' as http;
import 'package:jwt/jwt.dart';
import 'package:path/path.dart' as p;
import 'package:scoped/scoped.dart';
import 'package:shorebird_cli/src/auth/providers/providers.dart';
import 'package:shorebird_cli/src/auth/endpoints/endpoints.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/command_runner.dart';
import 'package:shorebird_cli/src/http_client/http_client.dart';
Expand All @@ -30,15 +30,15 @@ const googleJwtIssuer = 'https://accounts.google.com';
const microsoftJwtIssuerPrefix = 'https://login.microsoftonline.com/';

typedef ObtainAccessCredentials = Future<oauth2.AccessCredentials> Function(
oauth2.AuthProvider authProvider,
oauth2.AuthEndpoints authEndpoints,
oauth2.ClientId clientId,
List<String> scopes,
http.Client client,
void Function(String) userPrompt,
);

typedef RefreshCredentials = Future<oauth2.AccessCredentials> Function(
oauth2.AuthProvider authProvider,
oauth2.AuthEndpoints authEndpoints,
oauth2.ClientId clientId,
oauth2.AccessCredentials credentials,
http.Client client,
Expand Down Expand Up @@ -98,7 +98,7 @@ class AuthenticatedClient extends http.BaseClient {
if (credentials == null) {
final token = _token!;
final jwt = Jwt.parse(token);
final authProvider = jwt.authProvider;
final authProvider = jwt.authEndpoints;
credentials = _credentials = await _refreshCredentials(
authProvider,
authProvider.clientId,
Expand All @@ -115,7 +115,7 @@ class AuthenticatedClient extends http.BaseClient {

if (credentials.accessToken.hasExpired && credentials.idToken != null) {
final jwt = Jwt.parse(credentials.idToken!);
final authProvider = jwt.authProvider;
final authProvider = jwt.authEndpoints;

credentials = _credentials = await _refreshCredentials(
authProvider,
Expand Down Expand Up @@ -176,15 +176,15 @@ class Auth {
}

Future<AccessCredentials> loginCI(
oauth2.AuthProvider authProvider, {
oauth2.AuthEndpoints authEndpoints, {
required void Function(String) prompt,
}) async {
final client = http.Client();
try {
final credentials = await _obtainAccessCredentials(
authProvider,
authProvider.clientId,
authProvider.scopes,
authEndpoints,
authEndpoints.clientId,
authEndpoints.scopes,
client,
prompt,
);
Expand All @@ -206,7 +206,7 @@ class Auth {
}

Future<void> login(
oauth2.AuthProvider authProvider, {
oauth2.AuthEndpoints authEndpoints, {
required void Function(String) prompt,
}) async {
if (_credentials != null) {
Expand All @@ -216,9 +216,9 @@ class Auth {
final client = http.Client();
try {
_credentials = await _obtainAccessCredentials(
authProvider,
authProvider.clientId,
authProvider.scopes,
authEndpoints,
authEndpoints.clientId,
authEndpoints.scopes,
client,
prompt,
);
Expand Down Expand Up @@ -326,22 +326,22 @@ class UserNotFoundException implements Exception {
final String email;
}

extension OauthAuthProvider on Jwt {
oauth2.AuthProvider get authProvider {
extension OauthAuthEndpoints on Jwt {
oauth2.AuthEndpoints get authEndpoints {
if (payload.iss == googleJwtIssuer) {
return oauth2.GoogleAuthProvider();
return oauth2.GoogleAuthEndpoints();
} else if (payload.iss.startsWith(microsoftJwtIssuerPrefix)) {
return MicrosoftAuthProvider();
return MicrosoftAuthEndpoints();
}

throw Exception('Unknown jwt issuer: ${payload.iss}');
}
}

extension OauthValues on oauth2.AuthProvider {
extension OauthValues on oauth2.AuthEndpoints {
oauth2.ClientId get clientId {
switch (runtimeType) {
case oauth2.GoogleAuthProvider:
case oauth2.GoogleAuthEndpoints:
return oauth2.ClientId(
/// Shorebird CLI's OAuth 2.0 identifier for GCP,
'''523302233293-eia5antm0tgvek240t46orctktiabrek.apps.googleusercontent.com''',
Expand All @@ -358,7 +358,7 @@ extension OauthValues on oauth2.AuthProvider {
/// For more info see: https://developers.google.com/identity/protocols/oauth2/native-app
'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',
);
case MicrosoftAuthProvider:
case MicrosoftAuthEndpoints:
return oauth2.ClientId(
/// Shorebird CLI's OAuth 2.0 identifier for Azure/Entra.
'0ff83897-ec85-4642-a250-48d5f595137c',
Expand All @@ -370,9 +370,9 @@ extension OauthValues on oauth2.AuthProvider {

List<String> get scopes {
switch (runtimeType) {
case oauth2.GoogleAuthProvider:
case oauth2.GoogleAuthEndpoints:
return ['openid', 'https://www.googleapis.com/auth/userinfo.email'];
case MicrosoftAuthProvider:
case MicrosoftAuthEndpoints:
return ['openid'];
}

Expand Down
2 changes: 2 additions & 0 deletions packages/shorebird_cli/lib/src/auth/endpoints/endpoints.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'package:googleapis_auth/auth_io.dart' show GoogleAuthEndpoints;
export 'microsoft_auth_endpoints.dart';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:googleapis_auth/googleapis_auth.dart';

/// Endpoints for OAuth authentication with Azure/Entra/Microsoft.
class MicrosoftAuthProvider extends AuthProvider {
class MicrosoftAuthEndpoints extends AuthEndpoints {
@override
Uri get authorizationEndpoint =>
Uri.https('login.microsoftonline.com', 'common/oauth2/v2.0/authorize');
Expand Down
2 changes: 0 additions & 2 deletions packages/shorebird_cli/lib/src/auth/providers/providers.dart

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class LoginCiCommand extends ShorebirdCommand {
final AccessCredentials credentials;

try {
credentials = await auth.loginCI(GoogleAuthProvider(), prompt: prompt);
credentials = await auth.loginCI(GoogleAuthEndpoints(), prompt: prompt);
} on UserNotFoundException catch (error) {
logger
..err(
Expand Down
3 changes: 2 additions & 1 deletion packages/shorebird_cli/lib/src/commands/login_command.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:googleapis_auth/auth_io.dart';
import 'package:mason_logger/mason_logger.dart';
import 'package:shorebird_cli/src/auth/auth.dart';
import 'package:shorebird_cli/src/auth/endpoints/endpoints.dart';
import 'package:shorebird_cli/src/command.dart';
import 'package:shorebird_cli/src/logger.dart';

Expand All @@ -18,7 +19,7 @@ class LoginCommand extends ShorebirdCommand {
@override
Future<int> run() async {
try {
await auth.login(GoogleAuthProvider(), prompt: prompt);
await auth.login(GoogleAuthEndpoints(), prompt: prompt);
} on UserAlreadyLoggedInException catch (error) {
logger
..info('You are already logged in as <${error.email}>.')
Expand Down
60 changes: 30 additions & 30 deletions packages/shorebird_cli/test/src/auth/auth_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:path/path.dart' as p;
import 'package:platform/platform.dart';
import 'package:scoped/scoped.dart';
import 'package:shorebird_cli/src/auth/auth.dart';
import 'package:shorebird_cli/src/auth/providers/providers.dart';
import 'package:shorebird_cli/src/auth/endpoints/endpoints.dart';
import 'package:shorebird_cli/src/command_runner.dart';
import 'package:shorebird_cli/src/http_client/http_client.dart';
import 'package:shorebird_cli/src/logger.dart';
Expand All @@ -22,7 +22,7 @@ import 'package:test/test.dart';
import '../fakes.dart';
import '../mocks.dart';

class FakeProvider extends oauth2.AuthProvider {
class FakeAuthEndpoints extends oauth2.AuthEndpoints {
@override
Uri get authorizationEndpoint => Uri.https('example.com');

Expand Down Expand Up @@ -52,17 +52,17 @@ void main() {
});

group('OauthValues', () {
final fakeAuthProvider = FakeProvider();
final fakeAuthEndpoints = FakeAuthEndpoints();

group('clientId', () {
test('throws UnsupportedError when provider is not a known type', () {
expect(() => fakeAuthProvider.clientId, throwsUnsupportedError);
test('throws UnsupportedError when endpoints is not a known type', () {
expect(() => fakeAuthEndpoints.clientId, throwsUnsupportedError);
});
});

group('scopes', () {
test('throws UnsupportedError when provider is not a known type', () {
expect(() => fakeAuthProvider.scopes, throwsUnsupportedError);
test('throws UnsupportedError when endpoints is not a known type', () {
expect(() => fakeAuthEndpoints.scopes, throwsUnsupportedError);
});
});
});
Expand All @@ -86,7 +86,7 @@ void main() {
});
});

group('OauthAuthProvider', () {
group('OauthAuthEndpoints', () {
late Jwt jwt;
late JwtPayload payload;

Expand All @@ -99,14 +99,14 @@ void main() {
);
});

group('authProvider', () {
group('authEndpoints', () {
group('when issuer is login.microsoft.online', () {
setUp(() {
when(() => payload.iss).thenReturn(microsoftJwtIssuer);
});

test('returns AuthProvider.microsoft', () {
expect(jwt.authProvider, isA<MicrosoftAuthProvider>());
test('returns MicrosoftAuthEndpoints', () {
expect(jwt.authEndpoints, isA<MicrosoftAuthEndpoints>());
});
});

Expand All @@ -115,8 +115,8 @@ void main() {
when(() => payload.iss).thenReturn(googleJwtIssuer);
});

test('returns AuthProvider.google', () {
expect(jwt.authProvider, isA<GoogleAuthProvider>());
test('returns GoogleAuthEndpoints', () {
expect(jwt.authEndpoints, isA<GoogleAuthEndpoints>());
});
});

Expand All @@ -127,7 +127,7 @@ void main() {

test('throws exception', () {
expect(
() => jwt.authProvider,
() => jwt.authEndpoints,
throwsA(
isA<Exception>().having(
(e) => e.toString(),
Expand All @@ -152,8 +152,8 @@ void main() {
);
const refreshToken = '';
const scopes = <String>[];
final googleAuthProvider = GoogleAuthProvider();
final microsoftAuthProvider = MicrosoftAuthProvider();
final googleAuthEndpoints = GoogleAuthEndpoints();
final microsoftAuthEndpoints = MicrosoftAuthEndpoints();
final accessToken = oauth2.AccessToken(
'Bearer',
'accessToken',
Expand Down Expand Up @@ -198,7 +198,7 @@ void main() {
return codePushClient;
},
obtainAccessCredentials:
(authProvider, clientId, scopes, client, userPrompt) async {
(authEndpoints, clientId, scopes, client, userPrompt) async {
return accessCredentials;
},
),
Expand Down Expand Up @@ -235,7 +235,7 @@ void main() {
token: token,
httpClient: httpClient,
refreshCredentials:
(authProvider, clientId, credentials, client) async =>
(authEndpoints, clientId, credentials, client) async =>
accessCredentials,
),
returnsNormally,
Expand All @@ -258,7 +258,7 @@ void main() {
httpClient: httpClient,
onRefreshCredentials: onRefreshCredentialsCalls.add,
refreshCredentials:
(authProvider, clientId, credentials, client) async =>
(authEndpoints, clientId, credentials, client) async =>
accessCredentials,
);

Expand Down Expand Up @@ -292,7 +292,7 @@ void main() {
httpClient: httpClient,
onRefreshCredentials: onRefreshCredentialsCalls.add,
refreshCredentials:
(authProvider, clientId, credentials, client) async =>
(authEndpoints, clientId, credentials, client) async =>
accessCredentials,
);

Expand Down Expand Up @@ -342,7 +342,7 @@ void main() {
httpClient: httpClient,
onRefreshCredentials: onRefreshCredentialsCalls.add,
refreshCredentials:
(authProvider, clientId, credentials, client) async =>
(authEndpoints, clientId, credentials, client) async =>
accessCredentials,
);

Expand Down Expand Up @@ -400,7 +400,7 @@ void main() {
HttpStatus.ok,
),
);
await auth.login(googleAuthProvider, prompt: (_) {});
await auth.login(googleAuthEndpoints, prompt: (_) {});
final client = auth.client;
expect(client, isA<http.Client>());
expect(client, isA<AuthenticatedClient>());
Expand Down Expand Up @@ -445,18 +445,18 @@ void main() {
group('login', () {
test('should set the email when claims are valid and current user exists',
() async {
await auth.login(googleAuthProvider, prompt: (_) {});
await auth.login(googleAuthEndpoints, prompt: (_) {});
expect(auth.email, email);
expect(auth.isAuthenticated, isTrue);
expect(buildAuth().email, email);
expect(buildAuth().isAuthenticated, isTrue);
});

group('with a custom auth provider', () {
group('with custom auth endpoints', () {
test(
'''should set the email when claims are valid and current user exists''',
() async {
await auth.login(microsoftAuthProvider, prompt: (_) {});
await auth.login(microsoftAuthEndpoints, prompt: (_) {});
expect(auth.email, email);
expect(auth.isAuthenticated, isTrue);
expect(buildAuth().email, email);
Expand All @@ -470,7 +470,7 @@ void main() {
auth = buildAuth();

await expectLater(
auth.login(googleAuthProvider, prompt: (_) {}),
auth.login(googleAuthEndpoints, prompt: (_) {}),
throwsA(isA<UserAlreadyLoggedInException>()),
);

Expand All @@ -483,7 +483,7 @@ void main() {
.thenAnswer((_) async => null);

await expectLater(
auth.login(googleAuthProvider, prompt: (_) {}),
auth.login(googleAuthEndpoints, prompt: (_) {}),
throwsA(isA<UserNotFoundException>()),
);

Expand All @@ -505,7 +505,7 @@ void main() {
'returns credentials and does not set the email or cache credentials',
() async {
await expectLater(
auth.loginCI(googleAuthProvider, prompt: (_) {}),
auth.loginCI(googleAuthEndpoints, prompt: (_) {}),
completion(equals(accessCredentials)),
);
expect(auth.email, isNull);
Expand All @@ -522,7 +522,7 @@ void main() {
).thenAnswer((_) async => null);

await expectLater(
auth.loginCI(googleAuthProvider, prompt: (_) {}),
auth.loginCI(googleAuthEndpoints, prompt: (_) {}),
throwsA(isA<UserNotFoundException>()),
);

Expand All @@ -532,7 +532,7 @@ void main() {

group('logout', () {
test('clears session and wipes state', () async {
await auth.login(googleAuthProvider, prompt: (_) {});
await auth.login(googleAuthEndpoints, prompt: (_) {});
expect(auth.email, email);
expect(auth.isAuthenticated, isTrue);

Expand Down
Loading

0 comments on commit a330d52

Please sign in to comment.