Skip to content

Create TenantManager class and wire through listTenants operation. #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -690,8 +690,7 @@ protected UserRecord execute() throws FirebaseAuthException {
* UpdateRequest}.
*
* @param request A non-null {@link UpdateRequest} instance.
* @return A {@link UserRecord} instance corresponding to the updated user account. account, the
* task fails with a {@link FirebaseAuthException}.
* @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.
*/
Expand Down Expand Up @@ -1053,7 +1052,6 @@ public ApiFuture<String> generateSignInWithEmailLinkAsync(
.callAsync(firebaseApp);
}

@VisibleForTesting
FirebaseUserManager getUserManager() {
return this.userManager.get();
}
Expand All @@ -1074,7 +1072,7 @@ protected String execute() throws FirebaseAuthException {
};
}

private <T> Supplier<T> threadSafeMemoize(final Supplier<T> supplier) {
<T> Supplier<T> threadSafeMemoize(final Supplier<T> supplier) {
checkNotNull(supplier);
return Suppliers.memoize(
new Supplier<T>() {
Expand Down
16 changes: 13 additions & 3 deletions src/main/java/com/google/firebase/auth/FirebaseAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,29 @@
* then use it to perform a variety of authentication-related operations, including generating
* custom tokens for use by client-side code, verifying Firebase ID Tokens received from clients, or
* creating new FirebaseApp instances that are scoped to a particular authentication UID.
*
* <p>TODO(micahstairs): Add getTenantManager() method.
*/
public class FirebaseAuth extends AbstractFirebaseAuth {

private static final String SERVICE_ID = FirebaseAuth.class.getName();

private FirebaseAuth(Builder builder) {
private final Supplier<TenantManager> tenantManager;

private FirebaseAuth(final Builder builder) {
super(
builder.firebaseApp,
builder.tokenFactory,
builder.idTokenVerifier,
builder.cookieVerifier);
tenantManager = threadSafeMemoize(new Supplier<TenantManager>() {
@Override
public TenantManager get() {
return new TenantManager(builder.firebaseApp, getUserManager());
}
});
}

public TenantManager getTenantManager() {
return tenantManager.get();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@
/**
* FirebaseUserManager provides methods for interacting with the Google Identity Toolkit via its
* REST API. This class does not hold any mutable state, and is thread safe.
*
* <p>TODO(micahstairs): Consider renaming this to FirebaseAuthManager since this also supports
* tenants.
*
* <p>TODO(micahstairs): Rename this class to IdentityToolkitClient.
*
* @see <a href="https://developers.google.com/identity/toolkit/web/reference/relyingparty">
* Google Identity Toolkit</a>
Expand Down Expand Up @@ -227,7 +226,8 @@ UserImportResult importUsers(UserImportRequest request) throws FirebaseAuthExcep
return new UserImportResult(request.getUsersCount(), response);
}

ListTenantsResponse listTenants(int maxResults, String pageToken) throws FirebaseAuthException {
ListTenantsResponse listTenants(int maxResults, String pageToken)
throws FirebaseAuthException {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
.put("pageSize", maxResults);
if (pageToken != null) {
Expand Down
16 changes: 7 additions & 9 deletions src/main/java/com/google/firebase/auth/ListTenantsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@

/**
* Represents a page of {@link Tenant} instances.
*
*
* <p>Provides methods for iterating over the tenants in the current page, and calling up
* subsequent pages of tenants.
*
*
* <p>Instances of this class are thread-safe and immutable.
*/
public class ListTenantsPage implements Page<Tenant> {
Expand Down Expand Up @@ -65,7 +65,7 @@ public boolean hasNextPage() {

/**
* Returns the string token that identifies the next page.
*
*
* <p>Never returns null. Returns empty string if there are no more pages available to be
* retrieved.
*
Expand Down Expand Up @@ -99,7 +99,7 @@ public ListTenantsPage getNextPage() {
/**
* Returns an {@link Iterable} that facilitates transparently iterating over all the tenants in
* the current Firebase project, starting from this page.
*
*
* <p>The {@link Iterator} instances produced by the returned {@link Iterable} never buffers more
* than one page of tenants at a time. It is safe to abandon the iterators (i.e. break the loops)
* at any time.
Expand Down Expand Up @@ -139,7 +139,7 @@ public Iterator<Tenant> iterator() {

/**
* An {@link Iterator} that cycles through tenants, one at a time.
*
*
* <p>It buffers the last retrieved batch of tenants in memory. The {@code maxResults} parameter
* is an upper bound on the batch size.
*/
Expand Down Expand Up @@ -199,11 +199,9 @@ ListTenantsResponse fetch(int maxResults, String pageToken)
static class DefaultTenantSource implements TenantSource {

private final FirebaseUserManager userManager;
private final JsonFactory jsonFactory;

DefaultTenantSource(FirebaseUserManager userManager, JsonFactory jsonFactory) {
DefaultTenantSource(FirebaseUserManager userManager) {
this.userManager = checkNotNull(userManager, "user manager must not be null");
this.jsonFactory = checkNotNull(jsonFactory, "json factory must not be null");
}

@Override
Expand All @@ -215,7 +213,7 @@ public ListTenantsResponse fetch(int maxResults, String pageToken)

/**
* A simple factory class for {@link ListTenantsPage} instances.
*
*
* <p>Performs argument validation before attempting to load any tenant data (which is expensive,
* and hence may be performed asynchronously on a separate thread).
*/
Expand Down
153 changes: 97 additions & 56 deletions src/main/java/com/google/firebase/auth/Tenant.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@

package com.google.firebase.auth;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.api.client.util.Key;
import com.google.auto.value.AutoValue;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.Map;

/**
* Contains metadata associated with a Firebase tenant.
Expand All @@ -26,7 +31,7 @@
*/
public final class Tenant {

@Key("tenantId")
@Key("name")
private String tenantId;

@Key("displayName")
Expand Down Expand Up @@ -55,100 +60,136 @@ public boolean isEmailLinkSignInEnabled() {
}

/**
* Class used to hold the information needs to make a tenant create request.
* Returns a new {@link UpdateRequest}, which can be used to update the attributes
* of this tenant.
*
* @return a non-null Tenant.UpdateRequest instance.
*/
@AutoValue
public abstract static class CreateRequest {
public UpdateRequest updateRequest() {
return new UpdateRequest(getTenantId());
}

/**
* A specification class for creating new user accounts.
*
* <p>Set the initial attributes of the new tenant by calling various setter methods available in
* this class. None of the attributes are required.
*/
public static final class CreateRequest {

private final Map<String,Object> properties = new HashMap<>();

/**
* Returns the display name of this tenant.
* Creates a new {@link CreateRequest}, which can be used to create a new tenant.
*
* @return a non-empty display name string.
* <p>The returned object should be passed to {@link TenantManager#createTenant(CreateRequest)}
* to register the tenant information persistently.
*/
public abstract String getDisplayName();
public CreateRequest() { }

/**
* Returns whether to allow email/password user authentication.
* Sets the display name for the new tenant.
*
* @return true if a user can be authenticated using an email and password, and false otherwise.
* @param displayName a non-null, non-empty display name string.
*/
public abstract boolean isPasswordSignInAllowed();
public CreateRequest setDisplayName(String displayName) {
checkArgument(!Strings.isNullOrEmpty(displayName), "display name must not be null or empty");
properties.put("displayName", displayName);
return this;
}

/**
* Returns whether to enable email link user authentication.
* Sets whether to allow email/password user authentication.
*
* @return true if a user can be authenticated using an email link, and false otherwise.
* @param passwordSignInAllowed a boolean indicating whether users can be authenticated using
* an email and password, and false otherwise.
*/
public abstract boolean isEmailLinkSignInEnabled();
public CreateRequest setPasswordSignInAllowed(boolean passwordSignInAllowed) {
properties.put("allowPasswordSignup", passwordSignInAllowed);
return this;
}

/**
* Returns a builder for a tenant create request.
* Sets whether to enable email link user authentication.
*
* @param emailLinkSignInEnabled a boolean indicating whether users can be authenticated using
* an email link, and false otherwise.
*/
public static Builder newBuilder() {
return new AutoValue_Tenant_CreateRequest.Builder();
public CreateRequest setEmailLinkSignInEnabled(boolean emailLinkSignInEnabled) {
properties.put("enableEmailLinkSignin", emailLinkSignInEnabled);
return this;
}

/**
* Builder class used to construct a create request.
*/
@AutoValue.Builder
abstract static class Builder {
public abstract Builder setDisplayName(String displayName);

public abstract Builder setPasswordSignInAllowed(boolean allowPasswordSignIn);

public abstract Builder setEmailLinkSignInEnabled(boolean enableEmailLinkSignIn);

public abstract CreateRequest build();
Map<String, Object> getProperties() {
return ImmutableMap.copyOf(properties);
}
}

/**
* Class used to hold the information needs to make a tenant update request.
* A class for updating the attributes of an existing tenant.
*
* <p>An instance of this class can be obtained via a {@link Tenant} object, or from a tenant ID
* string. Specify the changes to be made to the tenant by calling the various setter methods
* available in this class.
*/
@AutoValue
public abstract static class UpdateRequest {
public static final class UpdateRequest {

private final Map<String,Object> properties = new HashMap<>();

/**
* Returns the display name of this tenant.
* Creates a new {@link UpdateRequest}, which can be used to update the attributes of the
* of the tenant identified by the specified tenant ID.
*
* <p>This method allows updating attributes of a tenant account, without first having to call
* {@link TenantManager#getTenant(String)}.
*
* @return a non-empty display name string.
* @param tenantId a non-null, non-empty tenant ID string.
* @throws IllegalArgumentException If the tenant ID is null or empty.
*/
public abstract String getDisplayName();
public UpdateRequest(String tenantId) {
checkArgument(!Strings.isNullOrEmpty(tenantId), "tenant ID must not be null or empty");
properties.put("name", tenantId);
}

String getTenantId() {
return (String) properties.get("name");
}

/**
* Returns whether to allow email/password user authentication.
* Sets the display name of the existingtenant.
*
* @return true if a user can be authenticated using an email and password, and false otherwise.
* @param displayName a non-null, non-empty display name string.
*/
public abstract boolean isPasswordSignInAllowed();
public UpdateRequest setDisplayName(String displayName) {
checkArgument(!Strings.isNullOrEmpty(displayName), "display name must not be null or empty");
properties.put("displayName", displayName);
return this;
}

/**
* Returns whether to enable email link user authentication.
* Sets whether to allow email/password user authentication.
*
* @return true if a user can be authenticated using an email link, and false otherwise.
* @param passwordSignInAllowed a boolean indicating whether users can be authenticated using
* an email and password, and false otherwise.
*/
public abstract boolean isEmailLinkSignInEnabled();
public UpdateRequest setPasswordSignInAllowed(boolean passwordSignInAllowed) {
properties.put("allowPasswordSignup", passwordSignInAllowed);
return this;
}

/**
* Returns a builder for a tenant update request.
* Sets whether to enable email link user authentication.
*
* @param emailLinkSignInEnabled a boolean indicating whether users can be authenticated using
* an email link, and false otherwise.
*/
public static Builder newBuilder() {
return new AutoValue_Tenant_UpdateRequest.Builder();
public UpdateRequest setEmailLinkSignInEnabled(boolean emailLinkSignInEnabled) {
properties.put("enableEmailLinkSignin", emailLinkSignInEnabled);
return this;
}

/**
* Builder class used to construct a update request.
*/
@AutoValue.Builder
abstract static class Builder {
public abstract Builder setDisplayName(String displayName);

public abstract Builder setPasswordSignInAllowed(boolean allowPasswordSignIn);

public abstract Builder setEmailLinkSignInEnabled(boolean enableEmailLinkSignIn);

public abstract UpdateRequest build();
Map<String, Object> getProperties() {
return ImmutableMap.copyOf(properties);
}
}
}
Loading