-   Notifications  
You must be signed in to change notification settings  - Fork 298
 
feat(auth): Link federatedid #345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
52608d5 dface3a a9e09c2 e5847c2 0bcaf69 cf34cf1 e18af15 File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|      |  @@ -548,6 +548,41 @@ public UpdateRequest setCustomClaims(Map<String,Object> customClaims) { | |
| return this; | ||
| } | ||
|   |  ||
| /** | ||
| * Links this user to the specified provider. | ||
| * | ||
| * <p>Linking a provider to an existing user account does not invalidate the | ||
| * refresh token of that account. In other words, the existing account | ||
| * would continue to be able to access resources, despite not having used | ||
| * the newly linked provider to log in. If you wish to force the user to | ||
| * authenticate with this new provider, you need to (a) revoke their | ||
| * refresh token (see | ||
| * https://firebase.google.com/docs/auth/admin/manage-sessions#revoke_refresh_tokens), | ||
| * and (b) ensure no other authentication methods are present on this | ||
| * account. | ||
| * | ||
| * @param providerToLink provider info to be linked to this user\'s account. | ||
| */ | ||
| public UpdateRequest setProviderToLink(@NonNull UserProvider providerToLink) { | ||
| properties.put("linkProviderUserInfo", checkNotNull(providerToLink)); | ||
| return this; | ||
| } | ||
|   |  ||
| /** | ||
| * Unlinks this user from the specified providers. | ||
| * | ||
| * @param providerIds list of identifiers for the identity providers. | ||
| */ | ||
| public UpdateRequest setProvidersToUnlink(Iterable<String> providerIds) { | ||
| checkNotNull(providerIds); | ||
| for (String id : providerIds) { | ||
| checkArgument(!Strings.isNullOrEmpty(id), "providerIds must not be null or empty"); | ||
| } | ||
|   |  ||
| properties.put("deleteProvider", providerIds); | ||
    rsgowman marked this conversation as resolved.    Show resolved Hide resolved  |  ||
| return this; | ||
| } | ||
|   |  ||
| UpdateRequest setValidSince(long epochSeconds) { | ||
| checkValidSince(epochSeconds); | ||
| properties.put("validSince", epochSeconds); | ||
|      |  @@ -569,7 +604,35 @@ Map<String, Object> getProperties(JsonFactory jsonFactory) { | |
| } | ||
|   |  ||
| if (copy.containsKey("phoneNumber") && copy.get("phoneNumber") == null) { | ||
| copy.put("deleteProvider", ImmutableList.of("phone")); | ||
| Object deleteProvider = copy.get("deleteProvider"); | ||
| if (deleteProvider != null) { | ||
| // Due to java's type erasure, we can't fully check the type. :( | ||
| @SuppressWarnings("unchecked") | ||
| Iterable<String> deleteProviderIterable = (Iterable<String>)deleteProvider; | ||
|   |  ||
| // If we've been told to unlink the phone provider both via setting | ||
| // phoneNumber to null *and* by setting providersToUnlink to include | ||
| // 'phone', then we'll reject that. Though it might also be reasonable | ||
| // to relax this restriction and just unlink it. | ||
| for (String dp : deleteProviderIterable) { | ||
| if (dp == "phone") { | ||
| throw new IllegalArgumentException( | ||
| "Both UpdateRequest.setPhoneNumber(null) and " | ||
| + "UpdateRequest.setProvidersToUnlink(['phone']) were set. To " | ||
| + "unlink from a phone provider, only specify " | ||
| + "UpdateRequest.setPhoneNumber(null)."); | ||
|   |  ||
| } | ||
| } | ||
|   |  ||
| copy.put("deleteProvider", new ImmutableList.Builder<String>() | ||
|   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we handle the double specification case? I remember handling this case is other languages. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Note that this results in the IllegalArgumentException being wrapped in an ExecutionException, which is a little awkward. (Option 1) Option 2: (NB: This is not a public interface.) Option 3: I've left it as option 1 for now. lmk if you'd prefer 2 or 3. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to enforce this constraint in the setters? We'd have to do so in both  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's better; done. I've removed the logic here, i.e. if we somehow get into a bad state, we won't notice it. (But now we shouldn't get into that state.) I didn't create a helper; there wasn't much duplication (though the exception itself is duplicated). If we set the value first and then checked, it would work out better... but that risks leaving the object in a bad state (eg if user catches and ignores the exception and then proceeds to use the object anyways.)  |  ||
| .addAll(deleteProviderIterable) | ||
| .add("phone") | ||
| .build()); | ||
| } else { | ||
| copy.put("deleteProvider", ImmutableList.of("phone")); | ||
| } | ||
|   |  ||
| copy.remove("phoneNumber"); | ||
| } | ||
|   |  ||
|      |  ||
Uh oh!
There was an error while loading. Please reload this page.