From 323909efb796305ae83e05dfb63ad03fe6847148 Mon Sep 17 00:00:00 2001 From: Edward Poot Date: Mon, 5 Dec 2022 17:55:48 +0100 Subject: [PATCH 1/9] Add Firebase Auth MFA info to user record --- .../google/firebase/auth/MultiFactorInfo.java | 71 ++++++++++++++++++ .../firebase/auth/MultiFactorSettings.java | 33 ++++++++ .../firebase/auth/PhoneMultiFactorInfo.java | 47 ++++++++++++ .../com/google/firebase/auth/UserRecord.java | 20 +++++ .../auth/internal/GetAccountInfoResponse.java | 75 +++++++++++++++++++ .../google/firebase/auth/UserRecordTest.java | 35 ++++++++- 6 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/google/firebase/auth/MultiFactorInfo.java create mode 100644 src/main/java/com/google/firebase/auth/MultiFactorSettings.java create mode 100644 src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java diff --git a/src/main/java/com/google/firebase/auth/MultiFactorInfo.java b/src/main/java/com/google/firebase/auth/MultiFactorInfo.java new file mode 100644 index 000000000..78fa9d45f --- /dev/null +++ b/src/main/java/com/google/firebase/auth/MultiFactorInfo.java @@ -0,0 +1,71 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.auth; + +import com.google.firebase.auth.internal.GetAccountInfoResponse; +import com.google.firebase.internal.Nullable; + +/** + * Interface representing the common properties of a user-enrolled second factor. + */ +public abstract class MultiFactorInfo { + + /** + * The ID of the enrolled second factor. This ID is unique to the user. + */ + private final String uid; + + /** + * The optional display name of the enrolled second factor. + */ + private final String displayName; + + /** + * The type identifier of the second factor. For SMS second factors, this is `phone`. + */ + private final String factorId; + + /** + * The optional date the second factor was enrolled, formatted as a UTC string. + */ + private final String enrollmentTime; + + MultiFactorInfo(GetAccountInfoResponse.MultiFactorInfo response) { + this.uid = response.getMfaEnrollmentId(); + this.displayName = response.getDisplayName(); + this.factorId = response.getFactorId(); + this.enrollmentTime = response.getEnrollmentTime(); + } + + public String getUid() { + return uid; + } + + @Nullable + public String getDisplayName() { + return displayName; + } + + public String getFactorId() { + return factorId; + } + + @Nullable + public String getEnrollmentTime() { + return enrollmentTime; + } +} diff --git a/src/main/java/com/google/firebase/auth/MultiFactorSettings.java b/src/main/java/com/google/firebase/auth/MultiFactorSettings.java new file mode 100644 index 000000000..96c06a402 --- /dev/null +++ b/src/main/java/com/google/firebase/auth/MultiFactorSettings.java @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.auth; + +/** + * The multi-factor related user settings. + */ +public class MultiFactorSettings { + + private final PhoneMultiFactorInfo[] enrolledFactors; + + public MultiFactorSettings(PhoneMultiFactorInfo[] enrolledFactors) { + this.enrolledFactors = enrolledFactors; + } + + public PhoneMultiFactorInfo[] getEnrolledFactors() { + return enrolledFactors; + } +} diff --git a/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java b/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java new file mode 100644 index 000000000..9c4b6b249 --- /dev/null +++ b/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java @@ -0,0 +1,47 @@ +/* + * Copyright 2022 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.auth; + +import com.google.firebase.auth.internal.GetAccountInfoResponse; + +/** + * Interface representing the common properties of a user-enrolled second factor. + */ +public class PhoneMultiFactorInfo extends MultiFactorInfo { + + /** + * The phone number associated with a phone second factor. + */ + private final String phoneNumber; + + private final String unobfuscatedPhoneNumber; + + public PhoneMultiFactorInfo(GetAccountInfoResponse.MultiFactorInfo response) { + super(response); + + this.phoneNumber = response.getPhoneInfo(); + this.unobfuscatedPhoneNumber = response.getUnobfuscatedPhoneInfo(); + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public String getUnobfuscatedPhoneNumber() { + return unobfuscatedPhoneNumber; + } +} diff --git a/src/main/java/com/google/firebase/auth/UserRecord.java b/src/main/java/com/google/firebase/auth/UserRecord.java index ac962c52d..80ecec323 100644 --- a/src/main/java/com/google/firebase/auth/UserRecord.java +++ b/src/main/java/com/google/firebase/auth/UserRecord.java @@ -61,6 +61,7 @@ public class UserRecord implements UserInfo { private final long tokensValidAfterTimestamp; private final UserMetadata userMetadata; private final Map customClaims; + private final MultiFactorSettings multiFactor; UserRecord(User response, JsonFactory jsonFactory) { checkNotNull(response, "response must not be null"); @@ -82,6 +83,18 @@ public class UserRecord implements UserInfo { this.providers[i] = new ProviderUserInfo(response.getProviders()[i]); } } + + if (response.getMfaInfo() == null || response.getMfaInfo().length == 0) { + this.multiFactor = new MultiFactorSettings(new PhoneMultiFactorInfo[0]); + } else { + int mfaInfoLength = response.getMfaInfo().length; + PhoneMultiFactorInfo[] multiFactorInfos = new PhoneMultiFactorInfo[mfaInfoLength]; + for (int i = 0; i < multiFactorInfos.length; i++) { + multiFactorInfos[i] = new PhoneMultiFactorInfo(response.getMfaInfo()[i]); + } + this.multiFactor = new MultiFactorSettings(multiFactorInfos); + } + this.tokensValidAfterTimestamp = response.getValidSince() * 1000; String lastRefreshAtRfc3339 = response.getLastRefreshAt(); @@ -240,6 +253,13 @@ public Map getCustomClaims() { return customClaims; } + /** + * The multi-factor related properties for the current user, if available. + */ + public MultiFactorSettings getMultiFactor() { + return multiFactor; + } + /** * Returns a new {@link UpdateRequest}, which can be used to update the attributes * of this user. diff --git a/src/main/java/com/google/firebase/auth/internal/GetAccountInfoResponse.java b/src/main/java/com/google/firebase/auth/internal/GetAccountInfoResponse.java index 7bde3eb39..581a5582c 100644 --- a/src/main/java/com/google/firebase/auth/internal/GetAccountInfoResponse.java +++ b/src/main/java/com/google/firebase/auth/internal/GetAccountInfoResponse.java @@ -17,6 +17,7 @@ package com.google.firebase.auth.internal; import com.google.api.client.util.Key; + import java.util.List; /** @@ -85,6 +86,9 @@ public static class User { @Key("customAttributes") private String customClaims; + @Key("mfaInfo") + private MultiFactorInfo[] mfaInfo; + public String getUid() { return uid; } @@ -140,6 +144,10 @@ public long getValidSince() { public String getCustomClaims() { return customClaims; } + + public MultiFactorInfo[] getMfaInfo() { + return mfaInfo; + } } /** @@ -189,4 +197,71 @@ public String getProviderId() { return providerId; } } + + /** + * JSON data binding for multi factor info data. + */ + public static final class MultiFactorInfo { + /** + * The ID of the enrolled second factor. This ID is unique to the user. + */ + @Key("mfaEnrollmentId") + private String mfaEnrollmentId; + + /** + * The optional display name of the enrolled second factor. + */ + @Key("displayName") + private String displayName; + + /** + * The type identifier of the second factor. For SMS second factors, this is `phone`. + */ + @Key("factorId") + private String factorId; + + /** + * The optional date the second factor was enrolled, formatted as a UTC string. + */ + @Key("enrollmentTime") + private String enrollmentTime; + + /** + * Normally this will show the phone number associated with this enrollment. + * In some situations, such as after a first factor sign in, + * it will only show the obfuscated version of the associated phone number. + */ + @Key("phoneInfo") + private String phoneInfo; + + /** + * Unobfuscated phoneInfo. + */ + @Key("unobfuscatedPhoneInfo") + private String unobfuscatedPhoneInfo; + + public String getMfaEnrollmentId() { + return mfaEnrollmentId; + } + + public String getDisplayName() { + return displayName; + } + + public String getFactorId() { + return factorId; + } + + public String getEnrollmentTime() { + return enrollmentTime; + } + + public String getPhoneInfo() { + return phoneInfo; + } + + public String getUnobfuscatedPhoneInfo() { + return unobfuscatedPhoneInfo; + } + } } diff --git a/src/test/java/com/google/firebase/auth/UserRecordTest.java b/src/test/java/com/google/firebase/auth/UserRecordTest.java index 6d50f075c..1948ed16b 100644 --- a/src/test/java/com/google/firebase/auth/UserRecordTest.java +++ b/src/test/java/com/google/firebase/auth/UserRecordTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; @@ -17,6 +18,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; + import org.junit.Test; public class UserRecordTest { @@ -92,7 +94,7 @@ public void testAllProviderInfo() throws IOException { .put("photoUrl", "http://photo.url") .put("providerId", "providerId") .build() - ) + ) ); String json = JSON_FACTORY.toString(resp); UserRecord userRecord = parseUser(json); @@ -108,6 +110,37 @@ public void testAllProviderInfo() throws IOException { } } + @Test + public void testPhoneMultiFactors() throws IOException { + ImmutableMap resp = ImmutableMap.of( + "localId", "user", + "mfaInfo", ImmutableList.of( + ImmutableMap.builder() + .put("mfaEnrollmentId", "53HG4HG45HG8G04GJ40J4G3J") + .put("displayName", "Display Name") + .put("factorId", "phone") + .put("enrollmentTime", "Fri, 22 Sep 2017 01:49:58 GMT") + .put("phoneInfo", "+16505551234") + .build() + ) + ); + String json = JSON_FACTORY.toString(resp); + UserRecord userRecord = parseUser(json); + assertEquals("user", userRecord.getUid()); + + assertNotNull(userRecord.getMultiFactor()); + PhoneMultiFactorInfo[] enrolledFactors = userRecord.getMultiFactor().getEnrolledFactors(); + assertEquals(1, enrolledFactors.length); + for (PhoneMultiFactorInfo multiFactorInfo : enrolledFactors) { + assertEquals("53HG4HG45HG8G04GJ40J4G3J", multiFactorInfo.getUid()); + assertEquals("Display Name", multiFactorInfo.getDisplayName()); + assertEquals("phone", multiFactorInfo.getFactorId()); + assertEquals("Fri, 22 Sep 2017 01:49:58 GMT", multiFactorInfo.getEnrollmentTime()); + assertEquals("+16505551234", multiFactorInfo.getPhoneNumber()); + assertNull(multiFactorInfo.getUnobfuscatedPhoneNumber()); + } + } + @Test public void testUserMetadata() throws IOException { ImmutableMap resp = ImmutableMap.of( From b2de7cad0b8263dba76c8ba3955725359e8c222d Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Wed, 2 Oct 2024 13:17:07 +1300 Subject: [PATCH 2/9] change group name --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3763023f4..ba7d88b71 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 4.0.0 - com.google.firebase + com.commercebuild.firebase firebase-admin 9.1.1 jar From 669b200994679b075d5c0c9064ca9ef9351c28f8 Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Wed, 2 Oct 2024 16:24:30 +1300 Subject: [PATCH 3/9] totp --- pom.xml | 22 +++++++------------ .../google/firebase/auth/MultiFactorInfo.java | 4 ++++ .../firebase/auth/MultiFactorInfoFactory.java | 14 ++++++++++++ .../firebase/auth/MultiFactorSettings.java | 6 ++--- .../firebase/auth/PhoneMultiFactorInfo.java | 7 +++++- .../firebase/auth/TotpMultiFactorInfo.java | 17 ++++++++++++++ .../com/google/firebase/auth/UserRecord.java | 6 ++--- .../google/firebase/auth/UserRecordTest.java | 2 +- 8 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java create mode 100644 src/main/java/com/google/firebase/auth/TotpMultiFactorInfo.java diff --git a/pom.xml b/pom.xml index ba7d88b71..84b3cb5c5 100644 --- a/pom.xml +++ b/pom.xml @@ -70,9 +70,15 @@ + + platform-release + platform-release + https://nexus.dev-mysagestore.com/repository/platform-release + - ossrh - https://oss.sonatype.org/content/repositories/snapshots + platform-snapshot + platform-snapshot + https://nexus.dev-mysagestore.com/repository/platform-snapshot @@ -348,18 +354,6 @@ - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 - true - - ossrh - https://oss.sonatype.org/ - true - - diff --git a/src/main/java/com/google/firebase/auth/MultiFactorInfo.java b/src/main/java/com/google/firebase/auth/MultiFactorInfo.java index 78fa9d45f..207d8ae22 100644 --- a/src/main/java/com/google/firebase/auth/MultiFactorInfo.java +++ b/src/main/java/com/google/firebase/auth/MultiFactorInfo.java @@ -24,6 +24,8 @@ */ public abstract class MultiFactorInfo { + public enum MfaType { PHONE, TOTP } + /** * The ID of the enrolled second factor. This ID is unique to the user. */ @@ -68,4 +70,6 @@ public String getFactorId() { public String getEnrollmentTime() { return enrollmentTime; } + + public abstract MfaType getMfaType(); } diff --git a/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java b/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java new file mode 100644 index 000000000..679e03b44 --- /dev/null +++ b/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java @@ -0,0 +1,14 @@ +package com.google.firebase.auth; + +import com.google.firebase.auth.internal.GetAccountInfoResponse; + +public class MultiFactorInfoFactory { + + + public MultiFactorInfo create(GetAccountInfoResponse.MultiFactorInfo multiFactorInfo) { + if (multiFactorInfo.getPhoneInfo().isEmpty()){ + return new TotpMultiFactorInfo(multiFactorInfo); + } + return new PhoneMultiFactorInfo(multiFactorInfo); + } +} diff --git a/src/main/java/com/google/firebase/auth/MultiFactorSettings.java b/src/main/java/com/google/firebase/auth/MultiFactorSettings.java index 96c06a402..59ffff56c 100644 --- a/src/main/java/com/google/firebase/auth/MultiFactorSettings.java +++ b/src/main/java/com/google/firebase/auth/MultiFactorSettings.java @@ -21,13 +21,13 @@ */ public class MultiFactorSettings { - private final PhoneMultiFactorInfo[] enrolledFactors; + private final MultiFactorInfo[] enrolledFactors; - public MultiFactorSettings(PhoneMultiFactorInfo[] enrolledFactors) { + public MultiFactorSettings(MultiFactorInfo[] enrolledFactors) { this.enrolledFactors = enrolledFactors; } - public PhoneMultiFactorInfo[] getEnrolledFactors() { + public MultiFactorInfo[] getEnrolledFactors() { return enrolledFactors; } } diff --git a/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java b/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java index 9c4b6b249..cc6191d69 100644 --- a/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java +++ b/src/main/java/com/google/firebase/auth/PhoneMultiFactorInfo.java @@ -37,7 +37,12 @@ public PhoneMultiFactorInfo(GetAccountInfoResponse.MultiFactorInfo response) { this.unobfuscatedPhoneNumber = response.getUnobfuscatedPhoneInfo(); } - public String getPhoneNumber() { + @Override + public MfaType getMfaType() { + return MfaType.PHONE; + } + + public String getPhoneNumber() { return phoneNumber; } diff --git a/src/main/java/com/google/firebase/auth/TotpMultiFactorInfo.java b/src/main/java/com/google/firebase/auth/TotpMultiFactorInfo.java new file mode 100644 index 000000000..1f882a195 --- /dev/null +++ b/src/main/java/com/google/firebase/auth/TotpMultiFactorInfo.java @@ -0,0 +1,17 @@ +package com.google.firebase.auth; + +import com.google.firebase.auth.internal.GetAccountInfoResponse; + +public class TotpMultiFactorInfo extends MultiFactorInfo { + + + public TotpMultiFactorInfo(GetAccountInfoResponse.MultiFactorInfo response) { + super(response); + } + + public MfaType getMfaType() { + return MfaType.TOTP; + } + + +} diff --git a/src/main/java/com/google/firebase/auth/UserRecord.java b/src/main/java/com/google/firebase/auth/UserRecord.java index 80ecec323..e62aeb0fa 100644 --- a/src/main/java/com/google/firebase/auth/UserRecord.java +++ b/src/main/java/com/google/firebase/auth/UserRecord.java @@ -85,12 +85,12 @@ public class UserRecord implements UserInfo { } if (response.getMfaInfo() == null || response.getMfaInfo().length == 0) { - this.multiFactor = new MultiFactorSettings(new PhoneMultiFactorInfo[0]); + this.multiFactor = new MultiFactorSettings(new MultiFactorInfo[0]); } else { int mfaInfoLength = response.getMfaInfo().length; - PhoneMultiFactorInfo[] multiFactorInfos = new PhoneMultiFactorInfo[mfaInfoLength]; + MultiFactorInfo[] multiFactorInfos = new MultiFactorInfo[mfaInfoLength]; for (int i = 0; i < multiFactorInfos.length; i++) { - multiFactorInfos[i] = new PhoneMultiFactorInfo(response.getMfaInfo()[i]); + multiFactorInfos[i] = new MultiFactorInfoFactory().create(response.getMfaInfo()[i]); } this.multiFactor = new MultiFactorSettings(multiFactorInfos); } diff --git a/src/test/java/com/google/firebase/auth/UserRecordTest.java b/src/test/java/com/google/firebase/auth/UserRecordTest.java index 1948ed16b..2a700f757 100644 --- a/src/test/java/com/google/firebase/auth/UserRecordTest.java +++ b/src/test/java/com/google/firebase/auth/UserRecordTest.java @@ -129,7 +129,7 @@ public void testPhoneMultiFactors() throws IOException { assertEquals("user", userRecord.getUid()); assertNotNull(userRecord.getMultiFactor()); - PhoneMultiFactorInfo[] enrolledFactors = userRecord.getMultiFactor().getEnrolledFactors(); + PhoneMultiFactorInfo[] enrolledFactors = (PhoneMultiFactorInfo[]) userRecord.getMultiFactor().getEnrolledFactors(); assertEquals(1, enrolledFactors.length); for (PhoneMultiFactorInfo multiFactorInfo : enrolledFactors) { assertEquals("53HG4HG45HG8G04GJ40J4G3J", multiFactorInfo.getUid()); From 12c5e8c79aaa618b7ff58228d1956a7fd4f4d5ca Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Wed, 2 Oct 2024 16:35:02 +1300 Subject: [PATCH 4/9] null check --- .../java/com/google/firebase/auth/MultiFactorInfoFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java b/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java index 679e03b44..79fe5fc00 100644 --- a/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java +++ b/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java @@ -6,7 +6,7 @@ public class MultiFactorInfoFactory { public MultiFactorInfo create(GetAccountInfoResponse.MultiFactorInfo multiFactorInfo) { - if (multiFactorInfo.getPhoneInfo().isEmpty()){ + if (multiFactorInfo.getPhoneInfo() != null && multiFactorInfo.getPhoneInfo().isEmpty()){ return new TotpMultiFactorInfo(multiFactorInfo); } return new PhoneMultiFactorInfo(multiFactorInfo); From 23269a2bc04864b69b26f29b5cff087388829ec1 Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Wed, 2 Oct 2024 16:40:00 +1300 Subject: [PATCH 5/9] fix --- .../java/com/google/firebase/auth/MultiFactorInfoFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java b/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java index 79fe5fc00..1eaccfed5 100644 --- a/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java +++ b/src/main/java/com/google/firebase/auth/MultiFactorInfoFactory.java @@ -6,7 +6,7 @@ public class MultiFactorInfoFactory { public MultiFactorInfo create(GetAccountInfoResponse.MultiFactorInfo multiFactorInfo) { - if (multiFactorInfo.getPhoneInfo() != null && multiFactorInfo.getPhoneInfo().isEmpty()){ + if (multiFactorInfo.getPhoneInfo() == null || multiFactorInfo.getPhoneInfo().isEmpty()){ return new TotpMultiFactorInfo(multiFactorInfo); } return new PhoneMultiFactorInfo(multiFactorInfo); From 047a382fba71ff24bc426d2c5b1c122dbec356ae Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Tue, 19 Nov 2024 16:54:10 +1300 Subject: [PATCH 6/9] mfa --- .../google/firebase/auth/multitenancy/Tenant.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/google/firebase/auth/multitenancy/Tenant.java b/src/main/java/com/google/firebase/auth/multitenancy/Tenant.java index 57d215e96..14e1a2a13 100644 --- a/src/main/java/com/google/firebase/auth/multitenancy/Tenant.java +++ b/src/main/java/com/google/firebase/auth/multitenancy/Tenant.java @@ -22,6 +22,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -119,6 +120,19 @@ public CreateRequest setEmailLinkSignInEnabled(boolean emailLinkSignInEnabled) { return this; } + public CreateRequest setMFAEnabled() { + properties.put("mfaConfig", Map.of( + "state", "ENABLED", + "enabledProviders", List.of("PHONE_SMS"), + "providerConfigs", List.of(Map.of( + "state", "ENABLED", + "totpProviderConfig", Map.of("adjacentIntervals", 5) + )) + + )); + return this; + } + Map getProperties() { return ImmutableMap.copyOf(properties); } From 54eefffefe03586895136e614193e04ed38c508c Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Thu, 21 Nov 2024 14:53:44 +1300 Subject: [PATCH 7/9] add authorized domain --- .../java/com/google/firebase/auth/FirebaseAuth.java | 4 ++++ .../google/firebase/auth/FirebaseUserManager.java | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/main/java/com/google/firebase/auth/FirebaseAuth.java b/src/main/java/com/google/firebase/auth/FirebaseAuth.java index 27e79960d..9b2482687 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseAuth.java +++ b/src/main/java/com/google/firebase/auth/FirebaseAuth.java @@ -111,4 +111,8 @@ public FirebaseAuth build() { return new FirebaseAuth(this); } } + + public void addAuthorizedDomain(String domain) throws FirebaseAuthException { + this.getUserManager().addAuthorizedDomain(domain); + } } diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java index 195527841..a59c93d17 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java +++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java @@ -46,7 +46,10 @@ import com.google.firebase.internal.HttpRequestInfo; import com.google.firebase.internal.NonNull; import com.google.firebase.internal.Nullable; + +import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -292,6 +295,15 @@ SamlProviderConfig getSamlProviderConfig(String providerId) throws FirebaseAuthE return httpClient.sendRequest(HttpRequestInfo.buildGetRequest(url), SamlProviderConfig.class); } + void addAuthorizedDomain(String domain) throws FirebaseAuthException { + String url = idpConfigMgtBaseUrl + "/config"; + HashMap map = httpClient.sendRequest(HttpRequestInfo.buildGetRequest(url), HashMap.class); + map.put("authorizedDomains", ((ArrayList)map.get("authorizedDomains")).add(domain)); + HttpRequestInfo requestInfo = HttpRequestInfo.buildJsonPatchRequest(url, map) + .addParameter("updateMask", Joiner.on(",").join(AuthHttpClient.generateMask(map))); + httpClient.sendRequest(requestInfo, Map.class); + } + ListOidcProviderConfigsResponse listOidcProviderConfigs(int maxResults, String pageToken) throws FirebaseAuthException { ImmutableMap.Builder builder = From 00647af93d99e9d36c1a0d220f35f161691b0291 Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Thu, 21 Nov 2024 15:11:18 +1300 Subject: [PATCH 8/9] fix --- src/main/java/com/google/firebase/auth/FirebaseUserManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java index a59c93d17..b37dc7a3b 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java +++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java @@ -298,7 +298,7 @@ SamlProviderConfig getSamlProviderConfig(String providerId) throws FirebaseAuthE void addAuthorizedDomain(String domain) throws FirebaseAuthException { String url = idpConfigMgtBaseUrl + "/config"; HashMap map = httpClient.sendRequest(HttpRequestInfo.buildGetRequest(url), HashMap.class); - map.put("authorizedDomains", ((ArrayList)map.get("authorizedDomains")).add(domain)); + ((ArrayList)map.get("authorizedDomains")).add(domain); HttpRequestInfo requestInfo = HttpRequestInfo.buildJsonPatchRequest(url, map) .addParameter("updateMask", Joiner.on(",").join(AuthHttpClient.generateMask(map))); httpClient.sendRequest(requestInfo, Map.class); From d2149be009db57db73379355009cd6abb9be932c Mon Sep 17 00:00:00 2001 From: Tom Fisk Date: Mon, 2 Dec 2024 15:26:25 +1300 Subject: [PATCH 9/9] verify and apply domain --- README.md | 6 +++++ .../google/firebase/auth/FirebaseAuth.java | 27 ++++++++++++++----- .../firebase/auth/FirebaseUserManager.java | 25 ++++++++++++++++- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1ad5352e5..9820a3fe0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +commercebuild install +mvn clean install -DskipTests -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true +commercebuild deploy +mvn deploy -B -DskipTests -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true + + [![Build Status](https://github.com/firebase/firebase-admin-java/workflows/Continuous%20Integration/badge.svg)](https://github.com/firebase/firebase-admin-java/actions) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.google.firebase/firebase-admin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.google.firebase/firebase-admin) [![Javadoc](https://javadoc-badge.appspot.com/com.google.firebase/firebase-admin.svg)](https://firebase.google.com/docs/reference/admin/java/reference/packages) diff --git a/src/main/java/com/google/firebase/auth/FirebaseAuth.java b/src/main/java/com/google/firebase/auth/FirebaseAuth.java index 9b2482687..2df49c87d 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseAuth.java +++ b/src/main/java/com/google/firebase/auth/FirebaseAuth.java @@ -91,6 +91,24 @@ static Builder builder() { return new Builder(); } + public void addAuthorizedDomain(String domain) throws FirebaseAuthException { + this + .getUserManager() + .addAuthorizedDomain(domain); + } + + public void verifyDomain(String domain) throws FirebaseAuthException { + this + .getUserManager() + .verifyDomain(domain); + } + + public void applyDomain(String domain) throws FirebaseAuthException { + this + .getUserManager() + .applyDomain(domain); + } + static class Builder extends AbstractFirebaseAuth.Builder { private Supplier tenantManager; @@ -107,12 +125,9 @@ public Builder setTenantManager(Supplier tenantManager) { return this; } - public FirebaseAuth build() { - return new FirebaseAuth(this); - } + public FirebaseAuth build() { + return new FirebaseAuth(this); + } } - public void addAuthorizedDomain(String domain) throws FirebaseAuthException { - this.getUserManager().addAuthorizedDomain(domain); - } } diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java index b37dc7a3b..41bd7ac8c 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java +++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java @@ -76,11 +76,16 @@ final class FirebaseUserManager { private static final String ID_TOOLKIT_URL = "https://identitytoolkit.googleapis.com/%s/projects/%s"; + + private static final String ID_TOOLKIT_ADMIN_URL = + "https://identitytoolkit.googleapis.com/admin/%s/projects/%s"; + private static final String ID_TOOLKIT_URL_EMULATOR = "http://%s/identitytoolkit.googleapis.com/%s/projects/%s"; private final String userMgtBaseUrl; private final String idpConfigMgtBaseUrl; + private final String adminUrl; private final JsonFactory jsonFactory; private final AuthHttpClient httpClient; @@ -102,7 +107,7 @@ private FirebaseUserManager(Builder builder) { this.userMgtBaseUrl = idToolkitUrlV1 + "/tenants/" + tenantId; this.idpConfigMgtBaseUrl = idToolkitUrlV2 + "/tenants/" + tenantId; } - + this.adminUrl = getIdToolkitAdminUrl(projectId, "v2"); this.httpClient = new AuthHttpClient(jsonFactory, builder.requestFactory); } @@ -113,6 +118,10 @@ private String getIdToolkitUrl(String projectId, String version) { return String.format(ID_TOOLKIT_URL, version, projectId); } + private String getIdToolkitAdminUrl(String projectId, String version) { + return String.format(ID_TOOLKIT_ADMIN_URL, version, projectId); + } + @VisibleForTesting void setInterceptor(HttpResponseInterceptor interceptor) { httpClient.setInterceptor(interceptor); @@ -304,6 +313,20 @@ void addAuthorizedDomain(String domain) throws FirebaseAuthException { httpClient.sendRequest(requestInfo, Map.class); } + void verifyDomain(String domain) throws FirebaseAuthException { + String url = adminUrl + "/domain:verify"; + HttpRequestInfo requestInfo = HttpRequestInfo.buildJsonPostRequest(url, Map.of("domain", domain, "action", "VERIFY")); + + httpClient.sendRequest(requestInfo, Map.class); + } + + void applyDomain(String domain) throws FirebaseAuthException { + String url = adminUrl + "/domain:verify"; + HttpRequestInfo requestInfo = HttpRequestInfo.buildJsonPostRequest(url, Map.of("domain", domain, "action", "APPLY")); + + httpClient.sendRequest(requestInfo, Map.class); + } + ListOidcProviderConfigsResponse listOidcProviderConfigs(int maxResults, String pageToken) throws FirebaseAuthException { ImmutableMap.Builder builder =