diff --git a/checkstyle.xml b/checkstyle.xml
index 663918173..77e2dba54 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -42,15 +42,15 @@
-
+
-
-
+
+
@@ -229,6 +229,9 @@
+
+
+
diff --git a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
index f779ae9df..a864c4f6c 100644
--- a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
+++ b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
@@ -29,10 +29,12 @@
import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.FirebaseUserManager.EmailLinkType;
import com.google.firebase.auth.FirebaseUserManager.UserImportRequest;
+import com.google.firebase.auth.ListProviderConfigsPage;
+import com.google.firebase.auth.ListProviderConfigsPage.DefaultOidcProviderConfigSource;
+import com.google.firebase.auth.ListProviderConfigsPage.DefaultSamlProviderConfigSource;
+import com.google.firebase.auth.ListUsersPage;
import com.google.firebase.auth.ListUsersPage.DefaultUserSource;
-import com.google.firebase.auth.ListUsersPage.PageFactory;
-import com.google.firebase.auth.UserRecord.CreateRequest;
-import com.google.firebase.auth.UserRecord.UpdateRequest;
+import com.google.firebase.auth.UserRecord;
import com.google.firebase.auth.internal.FirebaseTokenFactory;
import com.google.firebase.internal.CallableOperation;
import com.google.firebase.internal.NonNull;
@@ -323,7 +325,8 @@ private CallableOperation revokeRefreshTokensOp(fin
@Override
protected Void execute() throws FirebaseAuthException {
int currentTimeSeconds = (int) (System.currentTimeMillis() / 1000);
- UpdateRequest request = new UpdateRequest(uid).setValidSince(currentTimeSeconds);
+ UserRecord.UpdateRequest request =
+ new UserRecord.UpdateRequest(uid).setValidSince(currentTimeSeconds);
userManager.updateUser(request, jsonFactory);
return null;
}
@@ -444,8 +447,8 @@ protected UserRecord execute() throws FirebaseAuthException {
}
/**
- * Gets a page of users starting from the specified {@code pageToken}. Page size will be limited
- * to 1000 users.
+ * Gets a page of users starting from the specified {@code pageToken}. Page size is limited to
+ * 1000 users.
*
* @param pageToken A non-empty page token string, or null to retrieve the first page of users.
* @return A {@link ListUsersPage} instance.
@@ -503,8 +506,8 @@ private CallableOperation listUsersOp(
@Nullable final String pageToken, final int maxResults) {
checkNotDestroyed();
final FirebaseUserManager userManager = getUserManager();
- final PageFactory factory =
- new PageFactory(new DefaultUserSource(userManager, jsonFactory), maxResults, pageToken);
+ final DefaultUserSource source = new DefaultUserSource(userManager, jsonFactory);
+ final ListUsersPage.Factory factory = new ListUsersPage.Factory(source, maxResults, pageToken);
return new CallableOperation() {
@Override
protected ListUsersPage execute() throws FirebaseAuthException {
@@ -515,32 +518,33 @@ protected ListUsersPage execute() throws FirebaseAuthException {
/**
* Creates a new user account with the attributes contained in the specified {@link
- * CreateRequest}.
+ * UserRecord.CreateRequest}.
*
- * @param request A non-null {@link CreateRequest} instance.
+ * @param request A non-null {@link UserRecord.CreateRequest} instance.
* @return A {@link UserRecord} instance corresponding to the newly created account.
* @throws NullPointerException if the provided request is null.
* @throws FirebaseAuthException if an error occurs while creating the user account.
*/
- public UserRecord createUser(@NonNull CreateRequest request) throws FirebaseAuthException {
+ public UserRecord createUser(@NonNull UserRecord.CreateRequest request)
+ throws FirebaseAuthException {
return createUserOp(request).call();
}
/**
- * Similar to {@link #createUser(CreateRequest)} but performs the operation asynchronously.
+ * Similar to {@link #createUser} but performs the operation asynchronously.
*
- * @param request A non-null {@link CreateRequest} instance.
+ * @param request A non-null {@link UserRecord.CreateRequest} instance.
* @return An {@code ApiFuture} which will complete successfully with a {@link UserRecord}
* instance corresponding to the newly created account. If an error occurs while creating the
* user account, the future throws a {@link FirebaseAuthException}.
* @throws NullPointerException if the provided request is null.
*/
- public ApiFuture createUserAsync(@NonNull CreateRequest request) {
+ public ApiFuture createUserAsync(@NonNull UserRecord.CreateRequest request) {
return createUserOp(request).callAsync(firebaseApp);
}
private CallableOperation createUserOp(
- final CreateRequest request) {
+ final UserRecord.CreateRequest request) {
checkNotDestroyed();
checkNotNull(request, "create request must not be null");
final FirebaseUserManager userManager = getUserManager();
@@ -555,31 +559,32 @@ protected UserRecord execute() throws FirebaseAuthException {
/**
* Updates an existing user account with the attributes contained in the specified {@link
- * UpdateRequest}.
+ * UserRecord.UpdateRequest}.
*
- * @param request A non-null {@link UpdateRequest} instance.
+ * @param request A non-null {@link UserRecord.UpdateRequest} instance.
* @return A {@link UserRecord} instance corresponding to the updated user account.
* @throws NullPointerException if the provided update request is null.
* @throws FirebaseAuthException if an error occurs while updating the user account.
*/
- public UserRecord updateUser(@NonNull UpdateRequest request) throws FirebaseAuthException {
+ public UserRecord updateUser(@NonNull UserRecord.UpdateRequest request)
+ throws FirebaseAuthException {
return updateUserOp(request).call();
}
/**
- * Similar to {@link #updateUser(UpdateRequest)} but performs the operation asynchronously.
+ * Similar to {@link #updateUser} but performs the operation asynchronously.
*
- * @param request A non-null {@link UpdateRequest} instance.
+ * @param request A non-null {@link UserRecord.UpdateRequest} instance.
* @return An {@code ApiFuture} which will complete successfully with a {@link UserRecord}
* instance corresponding to the updated user account. If an error occurs while updating the
* user account, the future throws a {@link FirebaseAuthException}.
*/
- public ApiFuture updateUserAsync(@NonNull UpdateRequest request) {
+ public ApiFuture updateUserAsync(@NonNull UserRecord.UpdateRequest request) {
return updateUserOp(request).callAsync(firebaseApp);
}
private CallableOperation updateUserOp(
- final UpdateRequest request) {
+ final UserRecord.UpdateRequest request) {
checkNotDestroyed();
checkNotNull(request, "update request must not be null");
final FirebaseUserManager userManager = getUserManager();
@@ -639,7 +644,8 @@ private CallableOperation setCustomUserClaimsOp(
return new CallableOperation() {
@Override
protected Void execute() throws FirebaseAuthException {
- final UpdateRequest request = new UpdateRequest(uid).setCustomClaims(claims);
+ final UserRecord.UpdateRequest request =
+ new UserRecord.UpdateRequest(uid).setCustomClaims(claims);
userManager.updateUser(request, jsonFactory);
return null;
}
@@ -1054,18 +1060,6 @@ public ApiFuture generateSignInWithEmailLinkAsync(
.callAsync(firebaseApp);
}
- FirebaseApp getFirebaseApp() {
- return this.firebaseApp;
- }
-
- FirebaseTokenVerifier getCookieVerifier() {
- return this.cookieVerifier.get();
- }
-
- FirebaseUserManager getUserManager() {
- return this.userManager.get();
- }
-
private CallableOperation generateEmailActionLinkOp(
final EmailLinkType type, final String email, final ActionCodeSettings settings) {
checkNotDestroyed();
@@ -1082,6 +1076,544 @@ protected String execute() throws FirebaseAuthException {
};
}
+ /**
+ * Creates a new OpenID Connect auth provider config with the attributes contained in the
+ * specified {@link OidcProviderConfig.CreateRequest}.
+ *
+ * @param request A non-null {@link OidcProviderConfig.CreateRequest} instance.
+ * @return An {@link OidcProviderConfig} instance corresponding to the newly created provider
+ * config.
+ * @throws NullPointerException if the provided request is null.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not
+ * prefixed with 'oidc.'.
+ * @throws FirebaseAuthException if an error occurs while creating the provider config.
+ */
+ public OidcProviderConfig createOidcProviderConfig(
+ @NonNull OidcProviderConfig.CreateRequest request) throws FirebaseAuthException {
+ return createOidcProviderConfigOp(request).call();
+ }
+
+ /**
+ * Similar to {@link #createOidcProviderConfig} but performs the operation asynchronously.
+ *
+ * @param request A non-null {@link OidcProviderConfig.CreateRequest} instance.
+ * @return An {@code ApiFuture} which will complete successfully with a {@link OidcProviderConfig}
+ * instance corresponding to the newly created provider config. If an error occurs while
+ * creating the provider config, the future throws a {@link FirebaseAuthException}.
+ * @throws NullPointerException if the provided request is null.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not
+ * prefixed with 'oidc.'.
+ */
+ public ApiFuture createOidcProviderConfigAsync(
+ @NonNull OidcProviderConfig.CreateRequest request) {
+ return createOidcProviderConfigOp(request).callAsync(firebaseApp);
+ }
+
+ private CallableOperation
+ createOidcProviderConfigOp(final OidcProviderConfig.CreateRequest request) {
+ checkNotDestroyed();
+ checkNotNull(request, "Create request must not be null.");
+ OidcProviderConfig.checkOidcProviderId(request.getProviderId());
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected OidcProviderConfig execute() throws FirebaseAuthException {
+ return userManager.createOidcProviderConfig(request);
+ }
+ };
+ }
+
+ /**
+ * Updates an existing OpenID Connect auth provider config with the attributes contained in the
+ * specified {@link OidcProviderConfig.UpdateRequest}.
+ *
+ * @param request A non-null {@link OidcProviderConfig.UpdateRequest} instance.
+ * @return A {@link OidcProviderConfig} instance corresponding to the updated provider config.
+ * @throws NullPointerException if the provided update request is null.
+ * @throws IllegalArgumentException If the provided update request is invalid.
+ * @throws FirebaseAuthException if an error occurs while updating the provider config.
+ */
+ public OidcProviderConfig updateOidcProviderConfig(
+ @NonNull OidcProviderConfig.UpdateRequest request) throws FirebaseAuthException {
+ return updateOidcProviderConfigOp(request).call();
+ }
+
+ /**
+ * Similar to {@link #updateOidcProviderConfig} but performs the operation asynchronously.
+ *
+ * @param request A non-null {@link OidcProviderConfig.UpdateRequest} instance.
+ * @return An {@code ApiFuture} which will complete successfully with a {@link OidcProviderConfig}
+ * instance corresponding to the updated provider config. If an error occurs while updating
+ * the provider config, the future throws a {@link FirebaseAuthException}.
+ * @throws NullPointerException if the provided update request is null.
+ * @throws IllegalArgumentException If the provided update request is invalid.
+ */
+ public ApiFuture updateOidcProviderConfigAsync(
+ @NonNull OidcProviderConfig.UpdateRequest request) {
+ return updateOidcProviderConfigOp(request).callAsync(firebaseApp);
+ }
+
+ private CallableOperation updateOidcProviderConfigOp(
+ final OidcProviderConfig.UpdateRequest request) {
+ checkNotDestroyed();
+ checkNotNull(request, "Update request must not be null.");
+ checkArgument(!request.getProperties().isEmpty(),
+ "Update request must have at least one property set.");
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected OidcProviderConfig execute() throws FirebaseAuthException {
+ return userManager.updateOidcProviderConfig(request);
+ }
+ };
+ }
+
+ /**
+ * Gets the OpenID Connect auth provider corresponding to the specified provider ID.
+ *
+ * @param providerId A provider ID string.
+ * @return An {@link OidcProviderConfig} instance.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with 'oidc'.
+ * @throws FirebaseAuthException If an error occurs while retrieving the provider config.
+ */
+ public OidcProviderConfig getOidcProviderConfig(@NonNull String providerId)
+ throws FirebaseAuthException {
+ return getOidcProviderConfigOp(providerId).call();
+ }
+
+ /**
+ * Similar to {@link #getOidcProviderConfig(String)} but performs the operation asynchronously.
+ * Page size is limited to 100 provider configs.
+ *
+ * @param providerId A provider ID string.
+ * @return An {@code ApiFuture} which will complete successfully with an
+ * {@link OidcProviderConfig} instance. If an error occurs while retrieving the provider
+ * config or if the specified provider ID does not exist, the future throws a
+ * {@link FirebaseAuthException}.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not
+ * prefixed with 'oidc.'.
+ */
+ public ApiFuture getOidcProviderConfigAsync(@NonNull String providerId) {
+ return getOidcProviderConfigOp(providerId).callAsync(firebaseApp);
+ }
+
+ private CallableOperation
+ getOidcProviderConfigOp(final String providerId) {
+ checkNotDestroyed();
+ OidcProviderConfig.checkOidcProviderId(providerId);
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected OidcProviderConfig execute() throws FirebaseAuthException {
+ return userManager.getOidcProviderConfig(providerId);
+ }
+ };
+ }
+
+ /**
+ * Gets a page of OpenID Connect auth provider configs starting from the specified
+ * {@code pageToken}. Page size is limited to 100 provider configs.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @return A {@link ListProviderConfigsPage} instance.
+ * @throws IllegalArgumentException If the specified page token is empty
+ * @throws FirebaseAuthException If an error occurs while retrieving provider config data.
+ */
+ public ListProviderConfigsPage listOidcProviderConfigs(
+ @Nullable String pageToken) throws FirebaseAuthException {
+ int maxResults = FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS;
+ return listOidcProviderConfigsOp(pageToken, maxResults).call();
+ }
+
+ /**
+ * Gets a page of OpenID Connect auth provider configs starting from the specified
+ * {@code pageToken}.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @param maxResults Maximum number of provider configs to include in the returned page. This may
+ * not exceed 100.
+ * @return A {@link ListProviderConfigsPage} instance.
+ * @throws IllegalArgumentException If the specified page token is empty, or max results value is
+ * invalid.
+ * @throws FirebaseAuthException If an error occurs while retrieving provider config data.
+ */
+ public ListProviderConfigsPage listOidcProviderConfigs(
+ @Nullable String pageToken, int maxResults) throws FirebaseAuthException {
+ return listOidcProviderConfigsOp(pageToken, maxResults).call();
+ }
+
+ /**
+ * Similar to {@link #listOidcProviderConfigs(String)} but performs the operation asynchronously.
+ * Page size is limited to 100 provider configs.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @return An {@code ApiFuture} which will complete successfully with a
+ * {@link ListProviderConfigsPage} instance. If an error occurs while retrieving provider
+ * config data, the future throws an exception.
+ * @throws IllegalArgumentException If the specified page token is empty.
+ */
+ public ApiFuture> listOidcProviderConfigsAsync(
+ @Nullable String pageToken) {
+ int maxResults = FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS;
+ return listOidcProviderConfigsAsync(pageToken, maxResults);
+ }
+
+ /**
+ * Similar to {@link #listOidcProviderConfigs(String, int)} but performs the operation
+ * asynchronously.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @param maxResults Maximum number of provider configs to include in the returned page. This may
+ * not exceed 100.
+ * @return An {@code ApiFuture} which will complete successfully with a
+ * {@link ListProviderConfigsPage} instance. If an error occurs while retrieving provider
+ * config data, the future throws an exception.
+ * @throws IllegalArgumentException If the specified page token is empty, or max results value is
+ * invalid.
+ */
+ public ApiFuture> listOidcProviderConfigsAsync(
+ @Nullable String pageToken,
+ int maxResults) {
+ return listOidcProviderConfigsOp(pageToken, maxResults).callAsync(firebaseApp);
+ }
+
+ private CallableOperation, FirebaseAuthException>
+ listOidcProviderConfigsOp(@Nullable final String pageToken, final int maxResults) {
+ checkNotDestroyed();
+ final FirebaseUserManager userManager = getUserManager();
+ final DefaultOidcProviderConfigSource source = new DefaultOidcProviderConfigSource(userManager);
+ final ListProviderConfigsPage.Factory factory =
+ new ListProviderConfigsPage.Factory(source, maxResults, pageToken);
+ return
+ new CallableOperation, FirebaseAuthException>() {
+ @Override
+ protected ListProviderConfigsPage execute()
+ throws FirebaseAuthException {
+ return factory.create();
+ }
+ };
+ }
+
+ /**
+ * Deletes the OpenID Connect auth provider config identified by the specified provider ID.
+ *
+ * @param providerId A provider ID string.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with 'oidc'.
+ * @throws FirebaseAuthException If an error occurs while deleting the provider config.
+ */
+ public void deleteOidcProviderConfig(@NonNull String providerId) throws FirebaseAuthException {
+ deleteOidcProviderConfigOp(providerId).call();
+ }
+
+ /**
+ * Similar to {@link #deleteOidcProviderConfig} but performs the operation asynchronously.
+ *
+ * @param providerId A provider ID string.
+ * @return An {@code ApiFuture} which will complete successfully when the specified provider
+ * config has been deleted. If an error occurs while deleting the provider config, the future
+ * throws a {@link FirebaseAuthException}.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with "oidc.".
+ */
+ public ApiFuture deleteOidcProviderConfigAsync(String providerId) {
+ return deleteOidcProviderConfigOp(providerId).callAsync(firebaseApp);
+ }
+
+ private CallableOperation deleteOidcProviderConfigOp(
+ final String providerId) {
+ checkNotDestroyed();
+ OidcProviderConfig.checkOidcProviderId(providerId);
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected Void execute() throws FirebaseAuthException {
+ userManager.deleteOidcProviderConfig(providerId);
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Creates a new SAML Auth provider config with the attributes contained in the specified
+ * {@link SamlProviderConfig.CreateRequest}.
+ *
+ * @param request A non-null {@link SamlProviderConfig.CreateRequest} instance.
+ * @return An {@link SamlProviderConfig} instance corresponding to the newly created provider
+ * config.
+ * @throws NullPointerException if the provided request is null.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with 'saml'.
+ * @throws FirebaseAuthException if an error occurs while creating the provider config.
+ */
+ public SamlProviderConfig createSamlProviderConfig(
+ @NonNull SamlProviderConfig.CreateRequest request) throws FirebaseAuthException {
+ return createSamlProviderConfigOp(request).call();
+ }
+
+ /**
+ * Similar to {@link #createSamlProviderConfig} but performs the operation asynchronously.
+ *
+ * @param request A non-null {@link SamlProviderConfig.CreateRequest} instance.
+ * @return An {@code ApiFuture} which will complete successfully with a {@link SamlProviderConfig}
+ * instance corresponding to the newly created provider config. If an error occurs while
+ * creating the provider config, the future throws a {@link FirebaseAuthException}.
+ * @throws NullPointerException if the provided request is null.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with 'saml'.
+ */
+ public ApiFuture createSamlProviderConfigAsync(
+ @NonNull SamlProviderConfig.CreateRequest request) {
+ return createSamlProviderConfigOp(request).callAsync(firebaseApp);
+ }
+
+ private CallableOperation
+ createSamlProviderConfigOp(final SamlProviderConfig.CreateRequest request) {
+ checkNotDestroyed();
+ checkNotNull(request, "Create request must not be null.");
+ SamlProviderConfig.checkSamlProviderId(request.getProviderId());
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected SamlProviderConfig execute() throws FirebaseAuthException {
+ return userManager.createSamlProviderConfig(request);
+ }
+ };
+ }
+
+ /**
+ * Updates an existing SAML Auth provider config with the attributes contained in the specified
+ * {@link SamlProviderConfig.UpdateRequest}.
+ *
+ * @param request A non-null {@link SamlProviderConfig.UpdateRequest} instance.
+ * @return A {@link SamlProviderConfig} instance corresponding to the updated provider config.
+ * @throws NullPointerException if the provided update request is null.
+ * @throws IllegalArgumentException If the provided update request is invalid.
+ * @throws FirebaseAuthException if an error occurs while updating the provider config.
+ */
+ public SamlProviderConfig updateSamlProviderConfig(
+ @NonNull SamlProviderConfig.UpdateRequest request) throws FirebaseAuthException {
+ return updateSamlProviderConfigOp(request).call();
+ }
+
+ /**
+ * Similar to {@link #updateSamlProviderConfig} but performs the operation asynchronously.
+ *
+ * @param request A non-null {@link SamlProviderConfig.UpdateRequest} instance.
+ * @return An {@code ApiFuture} which will complete successfully with a {@link SamlProviderConfig}
+ * instance corresponding to the updated provider config. If an error occurs while updating
+ * the provider config, the future throws a {@link FirebaseAuthException}.
+ * @throws NullPointerException if the provided update request is null.
+ * @throws IllegalArgumentException If the provided update request is invalid.
+ */
+ public ApiFuture updateSamlProviderConfigAsync(
+ @NonNull SamlProviderConfig.UpdateRequest request) {
+ return updateSamlProviderConfigOp(request).callAsync(firebaseApp);
+ }
+
+ private CallableOperation updateSamlProviderConfigOp(
+ final SamlProviderConfig.UpdateRequest request) {
+ checkNotDestroyed();
+ checkNotNull(request, "Update request must not be null.");
+ checkArgument(!request.getProperties().isEmpty(),
+ "Update request must have at least one property set.");
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected SamlProviderConfig execute() throws FirebaseAuthException {
+ return userManager.updateSamlProviderConfig(request);
+ }
+ };
+ }
+
+ /**
+ * Gets the SAML Auth provider config corresponding to the specified provider ID.
+ *
+ * @param providerId A provider ID string.
+ * @return An {@link SamlProviderConfig} instance.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with 'saml'.
+ * @throws FirebaseAuthException If an error occurs while retrieving the provider config.
+ */
+ public SamlProviderConfig getSamlProviderConfig(@NonNull String providerId)
+ throws FirebaseAuthException {
+ return getSamlProviderConfigOp(providerId).call();
+ }
+
+ /**
+ * Similar to {@link #getSamlProviderConfig(String)} but performs the operation asynchronously.
+ * Page size is limited to 100 provider configs.
+ *
+ * @param providerId A provider ID string.
+ * @return An {@code ApiFuture} which will complete successfully with an
+ * {@link SamlProviderConfig} instance. If an error occurs while retrieving the provider
+ * config or if the specified provider ID does not exist, the future throws a
+ * {@link FirebaseAuthException}.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with 'saml'.
+ */
+ public ApiFuture getSamlProviderConfigAsync(@NonNull String providerId) {
+ return getSamlProviderConfigOp(providerId).callAsync(firebaseApp);
+ }
+
+ private CallableOperation
+ getSamlProviderConfigOp(final String providerId) {
+ checkNotDestroyed();
+ SamlProviderConfig.checkSamlProviderId(providerId);
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected SamlProviderConfig execute() throws FirebaseAuthException {
+ return userManager.getSamlProviderConfig(providerId);
+ }
+ };
+ }
+
+ /**
+ * Gets a page of SAML Auth provider configs starting from the specified {@code pageToken}. Page
+ * size is limited to 100 provider configs.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @return A {@link ListProviderConfigsPage} instance.
+ * @throws IllegalArgumentException If the specified page token is empty.
+ * @throws FirebaseAuthException If an error occurs while retrieving provider config data.
+ */
+ public ListProviderConfigsPage listSamlProviderConfigs(
+ @Nullable String pageToken) throws FirebaseAuthException {
+ return listSamlProviderConfigs(
+ pageToken,
+ FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS);
+ }
+
+ /**
+ * Gets a page of SAML Auth provider configs starting from the specified {@code pageToken}.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @param maxResults Maximum number of provider configs to include in the returned page. This may
+ * not exceed 100.
+ * @return A {@link ListProviderConfigsPage} instance.
+ * @throws IllegalArgumentException If the specified page token is empty, or max results value is
+ * invalid.
+ * @throws FirebaseAuthException If an error occurs while retrieving provider config data.
+ */
+ public ListProviderConfigsPage listSamlProviderConfigs(
+ @Nullable String pageToken, int maxResults) throws FirebaseAuthException {
+ return listSamlProviderConfigsOp(pageToken, maxResults).call();
+ }
+
+ /**
+ * Similar to {@link #listSamlProviderConfigs(String)} but performs the operation asynchronously.
+ * Page size is limited to 100 provider configs.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @return An {@code ApiFuture} which will complete successfully with a
+ * {@link ListProviderConfigsPage} instance. If an error occurs while retrieving provider
+ * config data, the future throws an exception.
+ * @throws IllegalArgumentException If the specified page token is empty.
+ */
+ public ApiFuture> listSamlProviderConfigsAsync(
+ @Nullable String pageToken) {
+ int maxResults = FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS;
+ return listSamlProviderConfigsAsync(pageToken, maxResults);
+ }
+
+ /**
+ * Similar to {@link #listSamlProviderConfigs(String, int)} but performs the operation
+ * asynchronously.
+ *
+ * @param pageToken A non-empty page token string, or null to retrieve the first page of provider
+ * configs.
+ * @param maxResults Maximum number of provider configs to include in the returned page. This may
+ * not exceed 100.
+ * @return An {@code ApiFuture} which will complete successfully with a
+ * {@link ListProviderConfigsPage} instance. If an error occurs while retrieving provider
+ * config data, the future throws an exception.
+ * @throws IllegalArgumentException If the specified page token is empty, or max results value is
+ * invalid.
+ */
+ public ApiFuture> listSamlProviderConfigsAsync(
+ @Nullable String pageToken,
+ int maxResults) {
+ return listSamlProviderConfigsOp(pageToken, maxResults).callAsync(firebaseApp);
+ }
+
+ private CallableOperation, FirebaseAuthException>
+ listSamlProviderConfigsOp(@Nullable final String pageToken, final int maxResults) {
+ checkNotDestroyed();
+ final FirebaseUserManager userManager = getUserManager();
+ final DefaultSamlProviderConfigSource source = new DefaultSamlProviderConfigSource(userManager);
+ final ListProviderConfigsPage.Factory factory =
+ new ListProviderConfigsPage.Factory(source, maxResults, pageToken);
+ return
+ new CallableOperation, FirebaseAuthException>() {
+ @Override
+ protected ListProviderConfigsPage execute()
+ throws FirebaseAuthException {
+ return factory.create();
+ }
+ };
+ }
+
+ /**
+ * Deletes the SAML Auth provider config identified by the specified provider ID.
+ *
+ * @param providerId A provider ID string.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with "saml.".
+ * @throws FirebaseAuthException If an error occurs while deleting the provider config.
+ */
+ public void deleteSamlProviderConfig(@NonNull String providerId) throws FirebaseAuthException {
+ deleteSamlProviderConfigOp(providerId).call();
+ }
+
+ /**
+ * Similar to {@link #deleteSamlProviderConfig} but performs the operation asynchronously.
+ *
+ * @param providerId A provider ID string.
+ * @return An {@code ApiFuture} which will complete successfully when the specified provider
+ * config has been deleted. If an error occurs while deleting the provider config, the future
+ * throws a {@link FirebaseAuthException}.
+ * @throws IllegalArgumentException If the provider ID string is null or empty, or is not prefixed
+ * with "saml.".
+ */
+ public ApiFuture deleteSamlProviderConfigAsync(String providerId) {
+ return deleteSamlProviderConfigOp(providerId).callAsync(firebaseApp);
+ }
+
+ private CallableOperation deleteSamlProviderConfigOp(
+ final String providerId) {
+ checkNotDestroyed();
+ SamlProviderConfig.checkSamlProviderId(providerId);
+ final FirebaseUserManager userManager = getUserManager();
+ return new CallableOperation() {
+ @Override
+ protected Void execute() throws FirebaseAuthException {
+ userManager.deleteSamlProviderConfig(providerId);
+ return null;
+ }
+ };
+ }
+
+ FirebaseApp getFirebaseApp() {
+ return this.firebaseApp;
+ }
+
+ FirebaseTokenVerifier getCookieVerifier() {
+ return this.cookieVerifier.get();
+ }
+
+ FirebaseUserManager getUserManager() {
+ return this.userManager.get();
+ }
+
protected Supplier threadSafeMemoize(final Supplier supplier) {
return Suppliers.memoize(
new Supplier() {
diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java
index e5d39b87f..c65e44deb 100644
--- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java
+++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java
@@ -44,6 +44,8 @@
import com.google.firebase.auth.internal.GetAccountInfoRequest;
import com.google.firebase.auth.internal.GetAccountInfoResponse;
import com.google.firebase.auth.internal.HttpErrorResponse;
+import com.google.firebase.auth.internal.ListOidcProviderConfigsResponse;
+import com.google.firebase.auth.internal.ListSamlProviderConfigsResponse;
import com.google.firebase.auth.internal.ListTenantsResponse;
import com.google.firebase.auth.internal.UploadAccountResponse;
import com.google.firebase.internal.ApiClientUtils;
@@ -69,6 +71,7 @@
*/
class FirebaseUserManager {
+ static final String CONFIGURATION_NOT_FOUND_ERROR = "configuration-not-found";
static final String TENANT_ID_MISMATCH_ERROR = "tenant-id-mismatch";
static final String TENANT_NOT_FOUND_ERROR = "tenant-not-found";
static final String USER_NOT_FOUND_ERROR = "user-not-found";
@@ -78,7 +81,7 @@ class FirebaseUserManager {
// SDK error codes defined at: https://firebase.google.com/docs/auth/admin/errors
private static final Map ERROR_CODES = ImmutableMap.builder()
.put("CLAIMS_TOO_LARGE", "claims-too-large")
- .put("CONFIGURATION_NOT_FOUND", "project-not-found")
+ .put("CONFIGURATION_NOT_FOUND", CONFIGURATION_NOT_FOUND_ERROR)
.put("INSUFFICIENT_PERMISSION", "insufficient-permission")
.put("DUPLICATE_EMAIL", "email-already-exists")
.put("DUPLICATE_LOCAL_ID", "uid-already-exists")
@@ -97,6 +100,7 @@ class FirebaseUserManager {
.put("INVALID_DYNAMIC_LINK_DOMAIN", "invalid-dynamic-link-domain")
.build();
+ static final int MAX_LIST_PROVIDER_CONFIGS_RESULTS = 100;
static final int MAX_LIST_TENANTS_RESULTS = 1000;
static final int MAX_GET_ACCOUNTS_BATCH_SIZE = 100;
static final int MAX_DELETE_ACCOUNTS_BATCH_SIZE = 1000;
@@ -112,6 +116,7 @@ class FirebaseUserManager {
private static final String CLIENT_VERSION_HEADER = "X-Client-Version";
private final String userMgtBaseUrl;
+ private final String idpConfigMgtBaseUrl;
private final String tenantMgtBaseUrl;
private final JsonFactory jsonFactory;
private final HttpRequestFactory requestFactory;
@@ -126,15 +131,18 @@ class FirebaseUserManager {
"Project ID is required to access the auth service. Use a service account credential or "
+ "set the project ID explicitly via FirebaseOptions. Alternatively you can also "
+ "set the project ID via the GOOGLE_CLOUD_PROJECT environment variable.");
- String tenantId = builder.tenantId;
- if (builder.tenantId == null) {
- this.userMgtBaseUrl = String.format(ID_TOOLKIT_URL, "v1", projectId);
+ final String idToolkitUrlV1 = String.format(ID_TOOLKIT_URL, "v1", projectId);
+ final String idToolkitUrlV2 = String.format(ID_TOOLKIT_URL, "v2", projectId);
+ final String tenantId = builder.tenantId;
+ if (tenantId == null) {
+ this.userMgtBaseUrl = idToolkitUrlV1;
+ this.idpConfigMgtBaseUrl = idToolkitUrlV2;
} else {
- checkArgument(!tenantId.isEmpty(), "Tenant ID must not be empty");
- this.userMgtBaseUrl =
- String.format(ID_TOOLKIT_URL, "v1", projectId) + getTenantUrlSuffix(tenantId);
+ checkArgument(!tenantId.isEmpty(), "Tenant ID must not be empty.");
+ this.userMgtBaseUrl = idToolkitUrlV1 + getTenantUrlSuffix(tenantId);
+ this.idpConfigMgtBaseUrl = idToolkitUrlV2 + getTenantUrlSuffix(tenantId);
}
- this.tenantMgtBaseUrl = String.format(ID_TOOLKIT_URL, "v2", projectId);
+ this.tenantMgtBaseUrl = idToolkitUrlV2;
this.jsonFactory = app.getOptions().getJsonFactory();
this.requestFactory = builder.requestFactory == null
? ApiClientUtils.newAuthorizedRequestFactory(app) : builder.requestFactory;
@@ -295,20 +303,11 @@ Tenant createTenant(Tenant.CreateRequest request) throws FirebaseAuthException {
Tenant updateTenant(Tenant.UpdateRequest request) throws FirebaseAuthException {
Map properties = request.getProperties();
- checkArgument(!properties.isEmpty(), "Tenant update must have at least one property set");
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + getTenantUrlSuffix(request.getTenantId()));
- url.put("updateMask", generateMask(properties));
+ url.put("updateMask", Joiner.on(",").join(generateMask(properties)));
return sendRequest("PATCH", url, properties, Tenant.class);
}
- private static String generateMask(Map properties) {
- // This implementation does not currently handle the case of nested properties. This is fine
- // since we do not currently generate masks for any properties with nested values. When it
- // comes time to implement this, we can check if a property has nested properties by checking
- // if it is an instance of the Map class.
- return Joiner.on(",").join(ImmutableSortedSet.copyOf(properties.keySet()));
- }
-
void deleteTenant(String tenantId) throws FirebaseAuthException {
GenericUrl url = new GenericUrl(tenantMgtBaseUrl + getTenantUrlSuffix(tenantId));
sendRequest("DELETE", url, null, GenericJson.class);
@@ -366,11 +365,128 @@ String getEmailActionLink(EmailLinkType type, String email,
throw new FirebaseAuthException(INTERNAL_ERROR, "Failed to create email action link");
}
+ OidcProviderConfig createOidcProviderConfig(
+ OidcProviderConfig.CreateRequest request) throws FirebaseAuthException {
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + "/oauthIdpConfigs");
+ url.set("oauthIdpConfigId", request.getProviderId());
+ return sendRequest("POST", url, request.getProperties(), OidcProviderConfig.class);
+ }
+
+ SamlProviderConfig createSamlProviderConfig(
+ SamlProviderConfig.CreateRequest request) throws FirebaseAuthException {
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + "/inboundSamlConfigs");
+ url.set("inboundSamlConfigId", request.getProviderId());
+ return sendRequest("POST", url, request.getProperties(), SamlProviderConfig.class);
+ }
+
+ OidcProviderConfig updateOidcProviderConfig(OidcProviderConfig.UpdateRequest request)
+ throws FirebaseAuthException {
+ Map properties = request.getProperties();
+ GenericUrl url =
+ new GenericUrl(idpConfigMgtBaseUrl + getOidcUrlSuffix(request.getProviderId()));
+ url.put("updateMask", Joiner.on(",").join(generateMask(properties)));
+ return sendRequest("PATCH", url, properties, OidcProviderConfig.class);
+ }
+
+ SamlProviderConfig updateSamlProviderConfig(SamlProviderConfig.UpdateRequest request)
+ throws FirebaseAuthException {
+ Map properties = request.getProperties();
+ GenericUrl url =
+ new GenericUrl(idpConfigMgtBaseUrl + getSamlUrlSuffix(request.getProviderId()));
+ url.put("updateMask", Joiner.on(",").join(generateMask(properties)));
+ return sendRequest("PATCH", url, properties, SamlProviderConfig.class);
+ }
+
+ OidcProviderConfig getOidcProviderConfig(String providerId) throws FirebaseAuthException {
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + getOidcUrlSuffix(providerId));
+ return sendRequest("GET", url, null, OidcProviderConfig.class);
+ }
+
+ SamlProviderConfig getSamlProviderConfig(String providerId) throws FirebaseAuthException {
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + getSamlUrlSuffix(providerId));
+ return sendRequest("GET", url, null, SamlProviderConfig.class);
+ }
+
+ ListOidcProviderConfigsResponse listOidcProviderConfigs(int maxResults, String pageToken)
+ throws FirebaseAuthException {
+ ImmutableMap.Builder builder =
+ ImmutableMap.builder().put("pageSize", maxResults);
+ if (pageToken != null) {
+ checkArgument(!pageToken.equals(
+ ListProviderConfigsPage.END_OF_LIST), "Invalid end of list page token.");
+ builder.put("nextPageToken", pageToken);
+ }
+
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + "/oauthIdpConfigs");
+ url.putAll(builder.build());
+ ListOidcProviderConfigsResponse response =
+ sendRequest("GET", url, null, ListOidcProviderConfigsResponse.class);
+ if (response == null) {
+ throw new FirebaseAuthException(INTERNAL_ERROR, "Failed to retrieve provider configs.");
+ }
+ return response;
+ }
+
+ ListSamlProviderConfigsResponse listSamlProviderConfigs(int maxResults, String pageToken)
+ throws FirebaseAuthException {
+ ImmutableMap.Builder builder =
+ ImmutableMap.builder().put("pageSize", maxResults);
+ if (pageToken != null) {
+ checkArgument(!pageToken.equals(
+ ListProviderConfigsPage.END_OF_LIST), "Invalid end of list page token.");
+ builder.put("nextPageToken", pageToken);
+ }
+
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + "/inboundSamlConfigs");
+ url.putAll(builder.build());
+ ListSamlProviderConfigsResponse response =
+ sendRequest("GET", url, null, ListSamlProviderConfigsResponse.class);
+ if (response == null) {
+ throw new FirebaseAuthException(INTERNAL_ERROR, "Failed to retrieve provider configs.");
+ }
+ return response;
+ }
+
+ void deleteOidcProviderConfig(String providerId) throws FirebaseAuthException {
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + getOidcUrlSuffix(providerId));
+ sendRequest("DELETE", url, null, GenericJson.class);
+ }
+
+ void deleteSamlProviderConfig(String providerId) throws FirebaseAuthException {
+ GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + getSamlUrlSuffix(providerId));
+ sendRequest("DELETE", url, null, GenericJson.class);
+ }
+
+ private static Set generateMask(Map properties) {
+ ImmutableSortedSet.Builder maskBuilder = ImmutableSortedSet.naturalOrder();
+ for (Map.Entry entry : properties.entrySet()) {
+ if (entry.getValue() instanceof Map) {
+ Set childMask = generateMask((Map) entry.getValue());
+ for (String childProperty : childMask) {
+ maskBuilder.add(entry.getKey() + "." + childProperty);
+ }
+ } else {
+ maskBuilder.add(entry.getKey());
+ }
+ }
+ return maskBuilder.build();
+ }
+
private static String getTenantUrlSuffix(String tenantId) {
- checkArgument(!Strings.isNullOrEmpty(tenantId));
+ checkArgument(!Strings.isNullOrEmpty(tenantId), "Tenant ID must not be null or empty.");
return "/tenants/" + tenantId;
}
+ private static String getOidcUrlSuffix(String providerId) {
+ checkArgument(!Strings.isNullOrEmpty(providerId), "Provider ID must not be null or empty.");
+ return "/oauthIdpConfigs/" + providerId;
+ }
+
+ private static String getSamlUrlSuffix(String providerId) {
+ checkArgument(!Strings.isNullOrEmpty(providerId), "Provider ID must not be null or empty.");
+ return "/inboundSamlConfigs/" + providerId;
+ }
+
private T post(String path, Object content, Class clazz) throws FirebaseAuthException {
checkArgument(!Strings.isNullOrEmpty(path), "path must not be null or empty");
checkNotNull(content, "content must not be null for POST requests");
diff --git a/src/main/java/com/google/firebase/auth/ListProviderConfigsPage.java b/src/main/java/com/google/firebase/auth/ListProviderConfigsPage.java
new file mode 100644
index 000000000..4530c0fae
--- /dev/null
+++ b/src/main/java/com/google/firebase/auth/ListProviderConfigsPage.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * 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 static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.client.json.JsonFactory;
+import com.google.api.gax.paging.Page;
+import com.google.common.collect.ImmutableList;
+import com.google.firebase.auth.internal.DownloadAccountResponse;
+import com.google.firebase.auth.internal.ListOidcProviderConfigsResponse;
+import com.google.firebase.auth.internal.ListProviderConfigsResponse;
+import com.google.firebase.auth.internal.ListSamlProviderConfigsResponse;
+import com.google.firebase.internal.NonNull;
+import com.google.firebase.internal.Nullable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Represents a page of {@link ProviderConfig} instances.
+ *
+ *
Provides methods for iterating over the provider configs in the current page, and calling up
+ * subsequent pages of provider configs.
+ *
+ *
Instances of this class are thread-safe and immutable.
+ */
+public class ListProviderConfigsPage implements Page {
+
+ static final String END_OF_LIST = "";
+
+ private final ListProviderConfigsResponse currentBatch;
+ private final ProviderConfigSource source;
+ private final int maxResults;
+
+ private ListProviderConfigsPage(
+ @NonNull ListProviderConfigsResponse currentBatch,
+ @NonNull ProviderConfigSource source,
+ int maxResults) {
+ this.currentBatch = checkNotNull(currentBatch);
+ this.source = checkNotNull(source);
+ this.maxResults = maxResults;
+ }
+
+ /**
+ * Checks if there is another page of provider configs available to retrieve.
+ *
+ * @return true if another page is available, or false otherwise.
+ */
+ @Override
+ public boolean hasNextPage() {
+ return !END_OF_LIST.equals(currentBatch.getPageToken());
+ }
+
+ /**
+ * Returns the string token that identifies the next page.
+ *
+ *
Never returns null. Returns empty string if there are no more pages available to be
+ * retrieved.
+ *
+ * @return A non-null string token (possibly empty, representing no more pages)
+ */
+ @NonNull
+ @Override
+ public String getNextPageToken() {
+ return currentBatch.getPageToken();
+ }
+
+ /**
+ * Returns the next page of provider configs.
+ *
+ * @return A new {@link ListProviderConfigsPage} instance, or null if there are no more pages.
+ */
+ @Nullable
+ @Override
+ public ListProviderConfigsPage getNextPage() {
+ if (hasNextPage()) {
+ Factory factory = new Factory(source, maxResults, currentBatch.getPageToken());
+ try {
+ return factory.create();
+ } catch (FirebaseAuthException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns an {@link Iterable} that facilitates transparently iterating over all the provider
+ * configs in the current Firebase project, starting from this page.
+ *
+ *
The {@link Iterator} instances produced by the returned {@link Iterable} never buffers more
+ * than one page of provider configs at a time. It is safe to abandon the iterators (i.e. break
+ * the loops) at any time.
+ *
+ * @return a new {@link Iterable} instance.
+ */
+ @NonNull
+ @Override
+ public Iterable iterateAll() {
+ return new ProviderConfigIterable(this);
+ }
+
+ /**
+ * Returns an {@link Iterable} over the provider configs in this page.
+ *
+ * @return a {@link Iterable} instance.
+ */
+ @NonNull
+ @Override
+ public Iterable getValues() {
+ return currentBatch.getProviderConfigs();
+ }
+
+ private static class ProviderConfigIterable implements Iterable {
+
+ private final ListProviderConfigsPage startingPage;
+
+ ProviderConfigIterable(@NonNull ListProviderConfigsPage startingPage) {
+ this.startingPage = checkNotNull(startingPage, "starting page must not be null");
+ }
+
+ @Override
+ @NonNull
+ public Iterator iterator() {
+ return new ProviderConfigIterator(startingPage);
+ }
+
+ /**
+ * An {@link Iterator} that cycles through provider configs, one at a time.
+ *
+ *
It buffers the last retrieved batch of provider configs in memory. The {@code maxResults}
+ * parameter is an upper bound on the batch size.
+ */
+ private static class ProviderConfigIterator implements Iterator {
+
+ private ListProviderConfigsPage currentPage;
+ private List batch;
+ private int index = 0;
+
+ private ProviderConfigIterator(ListProviderConfigsPage startingPage) {
+ setCurrentPage(startingPage);
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (index == batch.size()) {
+ if (currentPage.hasNextPage()) {
+ setCurrentPage(currentPage.getNextPage());
+ } else {
+ return false;
+ }
+ }
+
+ return index < batch.size();
+ }
+
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return batch.get(index++);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("remove operation not supported");
+ }
+
+ private void setCurrentPage(ListProviderConfigsPage page) {
+ this.currentPage = checkNotNull(page);
+ this.batch = ImmutableList.copyOf(page.getValues());
+ this.index = 0;
+ }
+ }
+ }
+
+ /**
+ * Represents a source of provider config data that can be queried to load a batch of provider
+ * configs.
+ */
+ interface ProviderConfigSource {
+ @NonNull
+ ListProviderConfigsResponse fetch(int maxResults, String pageToken)
+ throws FirebaseAuthException;
+ }
+
+ static class DefaultOidcProviderConfigSource implements ProviderConfigSource {
+
+ private final FirebaseUserManager userManager;
+
+ DefaultOidcProviderConfigSource(FirebaseUserManager userManager) {
+ this.userManager = checkNotNull(userManager, "User manager must not be null.");
+ }
+
+ @Override
+ public ListOidcProviderConfigsResponse fetch(int maxResults, String pageToken)
+ throws FirebaseAuthException {
+ return userManager.listOidcProviderConfigs(maxResults, pageToken);
+ }
+ }
+
+ static class DefaultSamlProviderConfigSource implements ProviderConfigSource {
+
+ private final FirebaseUserManager userManager;
+
+ DefaultSamlProviderConfigSource(FirebaseUserManager userManager) {
+ this.userManager = checkNotNull(userManager, "User manager must not be null.");
+ }
+
+ @Override
+ public ListSamlProviderConfigsResponse fetch(int maxResults, String pageToken)
+ throws FirebaseAuthException {
+ return userManager.listSamlProviderConfigs(maxResults, pageToken);
+ }
+ }
+
+ /**
+ * A simple factory class for {@link ProviderConfigsPage} instances.
+ *
+ *
Performs argument validation before attempting to load any provider config data (which is
+ * expensive, and hence may be performed asynchronously on a separate thread).
+ */
+ static class Factory {
+
+ private final ProviderConfigSource source;
+ private final int maxResults;
+ private final String pageToken;
+
+ Factory(@NonNull ProviderConfigSource source) {
+ this(source, FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS, null);
+ }
+
+ Factory(
+ @NonNull ProviderConfigSource source,
+ int maxResults,
+ @Nullable String pageToken) {
+ checkArgument(
+ maxResults > 0 && maxResults <= FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS,
+ "maxResults must be a positive integer that does not exceed %s",
+ FirebaseUserManager.MAX_LIST_PROVIDER_CONFIGS_RESULTS);
+ checkArgument(!END_OF_LIST.equals(pageToken), "invalid end of list page token");
+ this.source = checkNotNull(source, "source must not be null");
+ this.maxResults = maxResults;
+ this.pageToken = pageToken;
+ }
+
+ ListProviderConfigsPage create() throws FirebaseAuthException {
+ ListProviderConfigsResponse batch = source.fetch(maxResults, pageToken);
+ return new ListProviderConfigsPage(batch, source, maxResults);
+ }
+ }
+}
+
diff --git a/src/main/java/com/google/firebase/auth/ListTenantsPage.java b/src/main/java/com/google/firebase/auth/ListTenantsPage.java
index 8a8c8b4fe..d637174c7 100644
--- a/src/main/java/com/google/firebase/auth/ListTenantsPage.java
+++ b/src/main/java/com/google/firebase/auth/ListTenantsPage.java
@@ -113,7 +113,7 @@ public Iterable iterateAll() {
}
/**
- * Returns an {@link Iterable} over the users in this page.
+ * Returns an {@link Iterable} over the tenants in this page.
*
* @return a {@link Iterable} instance.
*/
diff --git a/src/main/java/com/google/firebase/auth/ListUsersPage.java b/src/main/java/com/google/firebase/auth/ListUsersPage.java
index f406366ba..ba727af5a 100644
--- a/src/main/java/com/google/firebase/auth/ListUsersPage.java
+++ b/src/main/java/com/google/firebase/auth/ListUsersPage.java
@@ -80,7 +80,7 @@ public String getNextPageToken() {
@Override
public ListUsersPage getNextPage() {
if (hasNextPage()) {
- PageFactory factory = new PageFactory(source, maxResults, currentBatch.getNextPageToken());
+ Factory factory = new Factory(source, maxResults, currentBatch.getNextPageToken());
try {
return factory.create();
} catch (FirebaseAuthException e) {
@@ -237,17 +237,17 @@ String getNextPageToken() {
* before attempting to load any user data (which is expensive, and hence may be performed
* asynchronously on a separate thread).
*/
- static class PageFactory {
+ static class Factory {
private final UserSource source;
private final int maxResults;
private final String pageToken;
- PageFactory(@NonNull UserSource source) {
+ Factory(@NonNull UserSource source) {
this(source, FirebaseUserManager.MAX_LIST_USERS_RESULTS, null);
}
- PageFactory(@NonNull UserSource source, int maxResults, @Nullable String pageToken) {
+ Factory(@NonNull UserSource source, int maxResults, @Nullable String pageToken) {
checkArgument(maxResults > 0 && maxResults <= FirebaseUserManager.MAX_LIST_USERS_RESULTS,
"maxResults must be a positive integer that does not exceed %s",
FirebaseUserManager.MAX_LIST_USERS_RESULTS);
diff --git a/src/main/java/com/google/firebase/auth/OidcProviderConfig.java b/src/main/java/com/google/firebase/auth/OidcProviderConfig.java
new file mode 100644
index 000000000..90a49e624
--- /dev/null
+++ b/src/main/java/com/google/firebase/auth/OidcProviderConfig.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * 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 static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.api.client.util.Key;
+import com.google.common.base.Strings;
+import com.google.firebase.auth.ProviderConfig.AbstractCreateRequest;
+import com.google.firebase.auth.ProviderConfig.AbstractUpdateRequest;
+
+/**
+ * Contains metadata associated with an OIDC Auth provider.
+ *
+ *
Instances of this class are immutable and thread safe.
+ */
+public final class OidcProviderConfig extends ProviderConfig {
+
+ @Key("clientId")
+ private String clientId;
+
+ @Key("issuer")
+ private String issuer;
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public String getIssuer() {
+ return issuer;
+ }
+
+ /**
+ * Returns a new {@link UpdateRequest}, which can be used to update the attributes of this
+ * provider config.
+ *
+ * @return A non-null {@link UpdateRequest} instance.
+ */
+ public UpdateRequest updateRequest() {
+ return new UpdateRequest(getProviderId());
+ }
+
+ static void checkOidcProviderId(String providerId) {
+ checkArgument(!Strings.isNullOrEmpty(providerId), "Provider ID must not be null or empty.");
+ checkArgument(providerId.startsWith("oidc."),
+ "Invalid OIDC provider ID (must be prefixed with 'oidc.'): " + providerId);
+ }
+
+ /**
+ * A specification class for creating a new OIDC Auth provider.
+ *
+ *
Set the initial attributes of the new provider by calling various setter methods available
+ * in this class.
+ */
+ public static final class CreateRequest extends AbstractCreateRequest {
+
+ /**
+ * Creates a new {@link CreateRequest}, which can be used to create a new OIDC Auth provider.
+ *
+ *
The returned object should be passed to
+ * {@link AbstractFirebaseAuth#createOidcProviderConfig(CreateRequest)} to save the config.
+ */
+ public CreateRequest() { }
+
+ /**
+ * Sets the ID for the new provider.
+ *
+ * @param providerId A non-null, non-empty provider ID string.
+ * @throws IllegalArgumentException If the provider ID is null or empty, or is not prefixed with
+ * 'oidc.'.
+ */
+ @Override
+ public CreateRequest setProviderId(String providerId) {
+ checkOidcProviderId(providerId);
+ return super.setProviderId(providerId);
+ }
+
+ /**
+ * Sets the client ID for the new provider.
+ *
+ * @param clientId A non-null, non-empty client ID string.
+ * @throws IllegalArgumentException If the client ID is null or empty.
+ */
+ public CreateRequest setClientId(String clientId) {
+ checkArgument(!Strings.isNullOrEmpty(clientId), "Client ID must not be null or empty.");
+ properties.put("clientId", clientId);
+ return this;
+ }
+
+ /**
+ * Sets the issuer for the new provider.
+ *
+ * @param issuer A non-null, non-empty issuer URL string.
+ * @throws IllegalArgumentException If the issuer URL is null or empty, or if the format is
+ * invalid.
+ */
+ public CreateRequest setIssuer(String issuer) {
+ checkArgument(!Strings.isNullOrEmpty(issuer), "Issuer must not be null or empty.");
+ assertValidUrl(issuer);
+ properties.put("issuer", issuer);
+ return this;
+ }
+
+ CreateRequest getThis() {
+ return this;
+ }
+ }
+
+ /**
+ * A specification class for updating an existing OIDC Auth provider.
+ *
+ *
An instance of this class can be obtained via a {@link OidcProviderConfig} object, or from
+ * a provider ID string. Specify the changes to be made to the provider config by calling the
+ * various setter methods available in this class.
+ */
+ public static final class UpdateRequest extends AbstractUpdateRequest {
+
+ /**
+ * Creates a new {@link UpdateRequest}, which can be used to updates an existing OIDC Auth
+ * provider.
+ *
+ *
The returned object should be passed to
+ * {@link AbstractFirebaseAuth#updateOidcProviderConfig(CreateRequest)} to save the updated
+ * config.
+ *
+ * @param providerId A non-null, non-empty provider ID string.
+ * @throws IllegalArgumentException If the provider ID is null or empty, or is not prefixed with
+ * "oidc.".
+ */
+ public UpdateRequest(String providerId) {
+ super(providerId);
+ checkOidcProviderId(providerId);
+ }
+
+ /**
+ * Sets the client ID for the exsting provider.
+ *
+ * @param clientId A non-null, non-empty client ID string.
+ * @throws IllegalArgumentException If the client ID is null or empty.
+ */
+ public UpdateRequest setClientId(String clientId) {
+ checkArgument(!Strings.isNullOrEmpty(clientId), "Client ID must not be null or empty.");
+ properties.put("clientId", clientId);
+ return this;
+ }
+
+ /**
+ * Sets the issuer for the existing provider.
+ *
+ * @param issuer A non-null, non-empty issuer URL string.
+ * @throws IllegalArgumentException If the issuer URL is null or empty, or if the format is
+ * invalid.
+ */
+ public UpdateRequest setIssuer(String issuer) {
+ checkArgument(!Strings.isNullOrEmpty(issuer), "Issuer must not be null or empty.");
+ assertValidUrl(issuer);
+ properties.put("issuer", issuer);
+ return this;
+ }
+
+ UpdateRequest getThis() {
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/com/google/firebase/auth/ProviderConfig.java b/src/main/java/com/google/firebase/auth/ProviderConfig.java
new file mode 100644
index 000000000..921a07b5b
--- /dev/null
+++ b/src/main/java/com/google/firebase/auth/ProviderConfig.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * 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 static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.api.client.util.Key;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The base class for Auth providers.
+ */
+public abstract class ProviderConfig {
+
+ @Key("name")
+ private String resourceName;
+
+ @Key("displayName")
+ private String displayName;
+
+ @Key("enabled")
+ private boolean enabled;
+
+ public String getProviderId() {
+ return resourceName.substring(resourceName.lastIndexOf("/") + 1);
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ static void assertValidUrl(String url) throws IllegalArgumentException {
+ try {
+ new URL(url);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException(url + " is a malformed URL.", e);
+ }
+ }
+
+ /**
+ * A base specification class for creating a new provider.
+ *
+ *
Set the initial attributes of the new provider by calling various setter methods available
+ * in this class.
+ */
+ public abstract static class AbstractCreateRequest> {
+
+ final Map properties = new HashMap<>();
+ String providerId;
+
+ T setProviderId(String providerId) {
+ this.providerId = providerId;
+ return getThis();
+ }
+
+ String getProviderId() {
+ return providerId;
+ }
+
+ /**
+ * Sets the display name for the new provider.
+ *
+ * @param displayName A non-null, non-empty display name string.
+ * @throws IllegalArgumentException If the display name is null or empty.
+ */
+ public T setDisplayName(String displayName) {
+ checkArgument(!Strings.isNullOrEmpty(displayName), "Display name must not be null or empty.");
+ properties.put("displayName", displayName);
+ return getThis();
+ }
+
+ /**
+ * Sets whether to allow the user to sign in with the provider.
+ *
+ * @param enabled A boolean indicating whether the user can sign in with the provider.
+ */
+ public T setEnabled(boolean enabled) {
+ properties.put("enabled", enabled);
+ return getThis();
+ }
+
+ Map getProperties() {
+ return ImmutableMap.copyOf(properties);
+ }
+
+ abstract T getThis();
+ }
+
+ /**
+ * A base class for updating the attributes of an existing provider.
+ */
+ public abstract static class AbstractUpdateRequest> {
+
+ final String providerId;
+ final Map properties = new HashMap<>();
+
+ AbstractUpdateRequest(String providerId) {
+ checkArgument(!Strings.isNullOrEmpty(providerId), "Provider ID must not be null or empty.");
+ this.providerId = providerId;
+ }
+
+ String getProviderId() {
+ return providerId;
+ }
+
+ /**
+ * Sets the display name for the existing provider.
+ *
+ * @param displayName A non-null, non-empty display name string.
+ * @throws IllegalArgumentException If the display name is null or empty.
+ */
+ public T setDisplayName(String displayName) {
+ checkArgument(!Strings.isNullOrEmpty(displayName), "Display name must not be null or empty.");
+ properties.put("displayName", displayName);
+ return getThis();
+ }
+
+ /**
+ * Sets whether to allow the user to sign in with the provider.
+ *
+ * @param enabled A boolean indicating whether the user can sign in with the provider.
+ */
+ public T setEnabled(boolean enabled) {
+ properties.put("enabled", enabled);
+ return getThis();
+ }
+
+ Map getProperties() {
+ return ImmutableMap.copyOf(properties);
+ }
+
+ abstract T getThis();
+ }
+}
diff --git a/src/main/java/com/google/firebase/auth/SamlProviderConfig.java b/src/main/java/com/google/firebase/auth/SamlProviderConfig.java
new file mode 100644
index 000000000..e74478bea
--- /dev/null
+++ b/src/main/java/com/google/firebase/auth/SamlProviderConfig.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * 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 static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.client.json.GenericJson;
+import com.google.api.client.util.Key;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.firebase.auth.ProviderConfig.AbstractCreateRequest;
+import com.google.firebase.auth.ProviderConfig.AbstractUpdateRequest;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains metadata associated with a SAML Auth provider.
+ *
+ *
Instances of this class are immutable and thread safe.
+ */
+public final class SamlProviderConfig extends ProviderConfig {
+
+ @Key("idpConfig")
+ private GenericJson idpConfig;
+
+ @Key("spConfig")
+ private GenericJson spConfig;
+
+ public String getIdpEntityId() {
+ return (String) idpConfig.get("idpEntityId");
+ }
+
+ public String getSsoUrl() {
+ return (String) idpConfig.get("ssoUrl");
+ }
+
+ public List getX509Certificates() {
+ List