Skip to content

Commit a3f09e5

Browse files
[google_sign_in] Implement hosted domain on Android (#9871)
Adds support for hosted domain filtering on Android. This was wired up for `authorize` (which would apply when calling `authorize` without a user set), but not for `authenticate`, because the first draft of Android support only used the one-tap flow, which doesn't have domain filter support, and I forgot to add it when I added the button flow. Because one-tap doesn't support the filtering feature, this adjusts the way the `attemptLightweightAuthentication` is handled when a filter is set. Instead of following the usual guidance to call it first with `filterToAuthorized` and `autoSelectEnabled` (for returning sign-in), then again without (for one-tap UI), it will only do the first call, which means it will allow returning sign-ins, but not show a general one-tap selection UI that could allow seleting an account that doesn't meet the filter requirement. (In theory, there are cases where this would be wrong if someone changed their filtering dynamically from run to run, but I can't imagine why that would be done, and in that case there's nothing that can be done with the current SDK support anyway, so if someone really wants to do that they need to just not call `attemptLightweightAuthentication`.) Also updates to the latest version of Pigeon since I was regenerating the Pigeon files already. Fixes flutter/flutter#174200 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent 37bafd4 commit a3f09e5

File tree

9 files changed

+506
-49
lines changed

9 files changed

+506
-49
lines changed

packages/google_sign_in/google_sign_in_android/CHANGELOG.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 7.0.5
2+
3+
* Adds support for `hostedDomain` when authenticating.
4+
15
## 7.0.4
26

37
* Bumps com.android.tools.build:gradle to 8.12.1 and kotlin_version to 2.2.10.
@@ -6,10 +10,7 @@
610
## 7.0.3
711

812
* Updates kotlin version to 2.2.0 to enable gradle 8.11 support.
9-
10-
## 7.0.3
11-
12-
* Add more details and troubleshooting for `serverClientId` configuration
13+
* Adds more details and troubleshooting for `serverClientId` configuration
1314
via Firebase.
1415

1516
## 7.0.2

packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,22 @@ public void getCredential(
231231
}
232232

233233
String nonce = params.getNonce();
234+
String hostedDomain = params.getHostedDomain();
234235
GetCredentialRequest.Builder requestBuilder = new GetCredentialRequest.Builder();
235236
if (params.getUseButtonFlow()) {
236237
GetSignInWithGoogleOption.Builder optionBuilder =
237238
new GetSignInWithGoogleOption.Builder(serverClientId);
239+
if (hostedDomain != null) {
240+
optionBuilder.setHostedDomainFilter(hostedDomain);
241+
}
238242
if (nonce != null) {
239243
optionBuilder.setNonce(nonce);
240244
}
241245
requestBuilder.addCredentialOption(optionBuilder.build());
242246
} else {
243247
GetCredentialRequestGoogleIdOptionParams optionParams = params.getGoogleIdOptionParams();
248+
// TODO(stuartmorgan): Add a hosted domain filter here if hosted
249+
// domain support is added to GetGoogleIdOption in the future.
244250
GetGoogleIdOption.Builder optionBuilder =
245251
new GetGoogleIdOption.Builder()
246252
.setFilterByAuthorizedAccounts(optionParams.getFilterToAuthorized())

packages/google_sign_in/google_sign_in_android/android/src/main/kotlin/io/flutter/plugins/googlesignin/Messages.kt

Lines changed: 151 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2013 The Flutter Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4-
// Autogenerated from Pigeon (v24.2.2), do not edit directly.
4+
// Autogenerated from Pigeon (v26.0.1), do not edit directly.
55
// See also: https://pub.dev/packages/pigeon
66
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
77

@@ -15,18 +15,47 @@ import io.flutter.plugin.common.StandardMessageCodec
1515
import java.io.ByteArrayOutputStream
1616
import java.nio.ByteBuffer
1717

18-
private fun wrapResult(result: Any?): List<Any?> {
19-
return listOf(result)
20-
}
18+
private object MessagesPigeonUtils {
19+
20+
fun wrapResult(result: Any?): List<Any?> {
21+
return listOf(result)
22+
}
2123

22-
private fun wrapError(exception: Throwable): List<Any?> {
23-
return if (exception is FlutterError) {
24-
listOf(exception.code, exception.message, exception.details)
25-
} else {
26-
listOf(
27-
exception.javaClass.simpleName,
28-
exception.toString(),
29-
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception))
24+
fun wrapError(exception: Throwable): List<Any?> {
25+
return if (exception is FlutterError) {
26+
listOf(exception.code, exception.message, exception.details)
27+
} else {
28+
listOf(
29+
exception.javaClass.simpleName,
30+
exception.toString(),
31+
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception))
32+
}
33+
}
34+
35+
fun deepEquals(a: Any?, b: Any?): Boolean {
36+
if (a is ByteArray && b is ByteArray) {
37+
return a.contentEquals(b)
38+
}
39+
if (a is IntArray && b is IntArray) {
40+
return a.contentEquals(b)
41+
}
42+
if (a is LongArray && b is LongArray) {
43+
return a.contentEquals(b)
44+
}
45+
if (a is DoubleArray && b is DoubleArray) {
46+
return a.contentEquals(b)
47+
}
48+
if (a is Array<*> && b is Array<*>) {
49+
return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) }
50+
}
51+
if (a is List<*> && b is List<*>) {
52+
return a.size == b.size && a.indices.all { deepEquals(a[it], b[it]) }
53+
}
54+
if (a is Map<*, *> && b is Map<*, *>) {
55+
return a.size == b.size &&
56+
a.all { (b as Map<Any?, Any?>).containsKey(it.key) && deepEquals(it.value, b[it.key]) }
57+
}
58+
return a == b
3059
}
3160
}
3261

@@ -106,7 +135,7 @@ enum class AuthorizeFailureType(val raw: Int) {
106135
}
107136

108137
/**
109-
* The information necessary to build a an authorization request.
138+
* The information necessary to build an authorization request.
110139
*
111140
* Corresponds to the native AuthorizationRequest object, but only contains the fields used by this
112141
* plugin.
@@ -139,6 +168,18 @@ data class PlatformAuthorizationRequest(
139168
serverClientIdForForcedRefreshToken,
140169
)
141170
}
171+
172+
override fun equals(other: Any?): Boolean {
173+
if (other !is PlatformAuthorizationRequest) {
174+
return false
175+
}
176+
if (this === other) {
177+
return true
178+
}
179+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
180+
}
181+
182+
override fun hashCode(): Int = toList().hashCode()
142183
}
143184

144185
/**
@@ -163,15 +204,18 @@ data class GetCredentialRequestParams(
163204
*/
164205
val googleIdOptionParams: GetCredentialRequestGoogleIdOptionParams,
165206
val serverClientId: String? = null,
207+
val hostedDomain: String? = null,
166208
val nonce: String? = null
167209
) {
168210
companion object {
169211
fun fromList(pigeonVar_list: List<Any?>): GetCredentialRequestParams {
170212
val useButtonFlow = pigeonVar_list[0] as Boolean
171213
val googleIdOptionParams = pigeonVar_list[1] as GetCredentialRequestGoogleIdOptionParams
172214
val serverClientId = pigeonVar_list[2] as String?
173-
val nonce = pigeonVar_list[3] as String?
174-
return GetCredentialRequestParams(useButtonFlow, googleIdOptionParams, serverClientId, nonce)
215+
val hostedDomain = pigeonVar_list[3] as String?
216+
val nonce = pigeonVar_list[4] as String?
217+
return GetCredentialRequestParams(
218+
useButtonFlow, googleIdOptionParams, serverClientId, hostedDomain, nonce)
175219
}
176220
}
177221

@@ -180,9 +224,22 @@ data class GetCredentialRequestParams(
180224
useButtonFlow,
181225
googleIdOptionParams,
182226
serverClientId,
227+
hostedDomain,
183228
nonce,
184229
)
185230
}
231+
232+
override fun equals(other: Any?): Boolean {
233+
if (other !is GetCredentialRequestParams) {
234+
return false
235+
}
236+
if (this === other) {
237+
return true
238+
}
239+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
240+
}
241+
242+
override fun hashCode(): Int = toList().hashCode()
186243
}
187244

188245
/** Generated class from Pigeon that represents data sent in messages. */
@@ -204,6 +261,18 @@ data class GetCredentialRequestGoogleIdOptionParams(
204261
autoSelectEnabled,
205262
)
206263
}
264+
265+
override fun equals(other: Any?): Boolean {
266+
if (other !is GetCredentialRequestGoogleIdOptionParams) {
267+
return false
268+
}
269+
if (this === other) {
270+
return true
271+
}
272+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
273+
}
274+
275+
override fun hashCode(): Int = toList().hashCode()
207276
}
208277

209278
/**
@@ -242,6 +311,18 @@ data class PlatformGoogleIdTokenCredential(
242311
profilePictureUri,
243312
)
244313
}
314+
315+
override fun equals(other: Any?): Boolean {
316+
if (other !is PlatformGoogleIdTokenCredential) {
317+
return false
318+
}
319+
if (this === other) {
320+
return true
321+
}
322+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
323+
}
324+
325+
override fun hashCode(): Int = toList().hashCode()
245326
}
246327

247328
/**
@@ -284,6 +365,18 @@ data class GetCredentialFailure(
284365
details,
285366
)
286367
}
368+
369+
override fun equals(other: Any?): Boolean {
370+
if (other !is GetCredentialFailure) {
371+
return false
372+
}
373+
if (this === other) {
374+
return true
375+
}
376+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
377+
}
378+
379+
override fun hashCode(): Int = toList().hashCode()
287380
}
288381

289382
/**
@@ -305,6 +398,18 @@ data class GetCredentialSuccess(val credential: PlatformGoogleIdTokenCredential)
305398
credential,
306399
)
307400
}
401+
402+
override fun equals(other: Any?): Boolean {
403+
if (other !is GetCredentialSuccess) {
404+
return false
405+
}
406+
if (this === other) {
407+
return true
408+
}
409+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
410+
}
411+
412+
override fun hashCode(): Int = toList().hashCode()
308413
}
309414

310415
/**
@@ -343,6 +448,18 @@ data class AuthorizeFailure(
343448
details,
344449
)
345450
}
451+
452+
override fun equals(other: Any?): Boolean {
453+
if (other !is AuthorizeFailure) {
454+
return false
455+
}
456+
if (this === other) {
457+
return true
458+
}
459+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
460+
}
461+
462+
override fun hashCode(): Int = toList().hashCode()
346463
}
347464

348465
/**
@@ -373,6 +490,18 @@ data class PlatformAuthorizationResult(
373490
grantedScopes,
374491
)
375492
}
493+
494+
override fun equals(other: Any?): Boolean {
495+
if (other !is PlatformAuthorizationResult) {
496+
return false
497+
}
498+
if (this === other) {
499+
return true
500+
}
501+
return MessagesPigeonUtils.deepEquals(toList(), other.toList())
502+
}
503+
504+
override fun hashCode(): Int = toList().hashCode()
376505
}
377506

378507
private open class MessagesPigeonCodec : StandardMessageCodec() {
@@ -510,7 +639,7 @@ interface GoogleSignInApi {
510639
try {
511640
listOf(api.getGoogleServicesJsonServerClientId())
512641
} catch (exception: Throwable) {
513-
wrapError(exception)
642+
MessagesPigeonUtils.wrapError(exception)
514643
}
515644
reply.reply(wrapped)
516645
}
@@ -531,10 +660,10 @@ interface GoogleSignInApi {
531660
api.getCredential(paramsArg) { result: Result<GetCredentialResult> ->
532661
val error = result.exceptionOrNull()
533662
if (error != null) {
534-
reply.reply(wrapError(error))
663+
reply.reply(MessagesPigeonUtils.wrapError(error))
535664
} else {
536665
val data = result.getOrNull()
537-
reply.reply(wrapResult(data))
666+
reply.reply(MessagesPigeonUtils.wrapResult(data))
538667
}
539668
}
540669
}
@@ -553,9 +682,9 @@ interface GoogleSignInApi {
553682
api.clearCredentialState { result: Result<Unit> ->
554683
val error = result.exceptionOrNull()
555684
if (error != null) {
556-
reply.reply(wrapError(error))
685+
reply.reply(MessagesPigeonUtils.wrapError(error))
557686
} else {
558-
reply.reply(wrapResult(null))
687+
reply.reply(MessagesPigeonUtils.wrapResult(null))
559688
}
560689
}
561690
}
@@ -577,10 +706,10 @@ interface GoogleSignInApi {
577706
api.authorize(paramsArg, promptIfUnauthorizedArg) { result: Result<AuthorizeResult> ->
578707
val error = result.exceptionOrNull()
579708
if (error != null) {
580-
reply.reply(wrapError(error))
709+
reply.reply(MessagesPigeonUtils.wrapError(error))
581710
} else {
582711
val data = result.getOrNull()
583-
reply.reply(wrapResult(data))
712+
reply.reply(MessagesPigeonUtils.wrapResult(data))
584713
}
585714
}
586715
}

0 commit comments

Comments
 (0)