Repository navigation
Expand file tree
/
Copy pathTenantManager.java
More file actions
292 lines (265 loc) · 12.3 KB
/
Copy pathTenantManager.java
File metadata and controls
292 lines (265 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
* 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.multitenancy;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.api.client.http.HttpResponseInterceptor;
import com.google.api.core.ApiFuture;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthException;
import com.google.firebase.auth.multitenancy.ListTenantsPage.DefaultTenantSource;
import com.google.firebase.auth.multitenancy.ListTenantsPage.PageFactory;
import com.google.firebase.auth.multitenancy.ListTenantsPage.TenantSource;
import com.google.firebase.auth.multitenancy.Tenant.CreateRequest;
import com.google.firebase.auth.multitenancy.Tenant.UpdateRequest;
import com.google.firebase.internal.CallableOperation;
import com.google.firebase.internal.NonNull;
import com.google.firebase.internal.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* This class can be used to perform a variety of tenant-related operations, including creating,
* updating, and listing tenants.
*/
public final class TenantManager {
private final FirebaseApp firebaseApp;
private final FirebaseTenantClient tenantClient;
private final Map<String, TenantAwareFirebaseAuth> tenantAwareAuths;
/**
* Creates a new {@link TenantManager} instance. For internal use only. Use
* {@link FirebaseAuth#getTenantManager()} to obtain an instance for regular use.
*
* @hide
*/
public TenantManager(FirebaseApp firebaseApp) {
this(firebaseApp, new FirebaseTenantClient(firebaseApp));
}
@VisibleForTesting
TenantManager(FirebaseApp firebaseApp, FirebaseTenantClient tenantClient) {
this.firebaseApp = checkNotNull(firebaseApp);
this.tenantClient = checkNotNull(tenantClient);
this.tenantAwareAuths = new HashMap<>();
}
@VisibleForTesting
void setInterceptor(HttpResponseInterceptor interceptor) {
this.tenantClient.setInterceptor(interceptor);
}
/**
* Gets the tenant corresponding to the specified tenant ID.
*
* @param tenantId A tenant ID string.
* @return A {@link Tenant} instance.
* @throws IllegalArgumentException If the tenant ID string is null or empty.
* @throws FirebaseAuthException If an error occurs while retrieving user data.
*/
public Tenant getTenant(@NonNull String tenantId) throws FirebaseAuthException {
return getTenantOp(tenantId).call();
}
public synchronized TenantAwareFirebaseAuth getAuthForTenant(@NonNull String tenantId) {
checkArgument(!Strings.isNullOrEmpty(tenantId), "Tenant ID must not be null or empty.");
if (!tenantAwareAuths.containsKey(tenantId)) {
tenantAwareAuths.put(tenantId, TenantAwareFirebaseAuth.fromApp(firebaseApp, tenantId));
}
return tenantAwareAuths.get(tenantId);
}
/**
* Similar to {@link #getTenant(String)} but performs the operation asynchronously.
*
* @param tenantId A tenantId string.
* @return An {@code ApiFuture} which will complete successfully with a {@link Tenant} instance
* If an error occurs while retrieving tenant data or if the specified tenant ID does not
* exist, the future throws a {@link FirebaseAuthException}.
* @throws IllegalArgumentException If the tenant ID string is null or empty.
*/
public ApiFuture<Tenant> getTenantAsync(@NonNull String tenantId) {
return getTenantOp(tenantId).callAsync(firebaseApp);
}
private CallableOperation<Tenant, FirebaseAuthException> getTenantOp(final String tenantId) {
checkArgument(!Strings.isNullOrEmpty(tenantId), "Tenant ID must not be null or empty.");
return new CallableOperation<Tenant, FirebaseAuthException>() {
@Override
protected Tenant execute() throws FirebaseAuthException {
return tenantClient.getTenant(tenantId);
}
};
}
/**
* Gets a page of tenants starting from the specified {@code pageToken}. Page size will be limited
* to 1000 tenants.
*
* @param pageToken A non-empty page token string, or null to retrieve the first page of tenants.
* @return A {@link ListTenantsPage} instance.
* @throws IllegalArgumentException If the specified page token is empty.
* @throws FirebaseAuthException If an error occurs while retrieving tenant data.
*/
public ListTenantsPage listTenants(@Nullable String pageToken) throws FirebaseAuthException {
return listTenants(pageToken, FirebaseTenantClient.MAX_LIST_TENANTS_RESULTS);
}
/**
* Gets a page of tenants starting from the specified {@code pageToken}.
*
* @param pageToken A non-empty page token string, or null to retrieve the first page of tenants.
* @param maxResults Maximum number of tenants to include in the returned page. This may not
* exceed 1000.
* @return A {@link ListTenantsPage} instance.
* @throws IllegalArgumentException If the specified page token is empty, or max results value is
* invalid.
* @throws FirebaseAuthException If an error occurs while retrieving tenant data.
*/
public ListTenantsPage listTenants(@Nullable String pageToken, int maxResults)
throws FirebaseAuthException {
return listTenantsOp(pageToken, maxResults).call();
}
/**
* Similar to {@link #listTenants(String)} but performs the operation asynchronously.
*
* @param pageToken A non-empty page token string, or null to retrieve the first page of tenants.
* @return An {@code ApiFuture} which will complete successfully with a {@link ListTenantsPage}
* instance. If an error occurs while retrieving tenant data, the future throws an exception.
* @throws IllegalArgumentException If the specified page token is empty.
*/
public ApiFuture<ListTenantsPage> listTenantsAsync(@Nullable String pageToken) {
return listTenantsAsync(pageToken, FirebaseTenantClient.MAX_LIST_TENANTS_RESULTS);
}
/**
* Similar to {@link #listTenants(String, int)} but performs the operation asynchronously.
*
* @param pageToken A non-empty page token string, or null to retrieve the first page of tenants.
* @param maxResults Maximum number of tenants to include in the returned page. This may not
* exceed 1000.
* @return An {@code ApiFuture} which will complete successfully with a {@link ListTenantsPage}
* instance. If an error occurs while retrieving tenant data, the future throws an exception.
* @throws IllegalArgumentException If the specified page token is empty, or max results value is
* invalid.
*/
public ApiFuture<ListTenantsPage> listTenantsAsync(@Nullable String pageToken, int maxResults) {
return listTenantsOp(pageToken, maxResults).callAsync(firebaseApp);
}
private CallableOperation<ListTenantsPage, FirebaseAuthException> listTenantsOp(
@Nullable final String pageToken, final int maxResults) {
final TenantSource tenantSource = new DefaultTenantSource(tenantClient);
final PageFactory factory = new PageFactory(tenantSource, maxResults, pageToken);
return new CallableOperation<ListTenantsPage, FirebaseAuthException>() {
@Override
protected ListTenantsPage execute() throws FirebaseAuthException {
return factory.create();
}
};
}
/**
* Creates a new tenant with the attributes contained in the specified {@link CreateRequest}.
*
* @param request A non-null {@link CreateRequest} instance.
* @return A {@link Tenant} instance corresponding to the newly created tenant.
* @throws NullPointerException if the provided request is null.
* @throws FirebaseAuthException if an error occurs while creating the tenant.
*/
public Tenant createTenant(@NonNull CreateRequest request) throws FirebaseAuthException {
return createTenantOp(request).call();
}
/**
* Similar to {@link #createTenant(CreateRequest)} but performs the operation asynchronously.
*
* @param request A non-null {@link CreateRequest} instance.
* @return An {@code ApiFuture} which will complete successfully with a {@link Tenant}
* instance corresponding to the newly created tenant. If an error occurs while creating the
* tenant, the future throws a {@link FirebaseAuthException}.
* @throws NullPointerException if the provided request is null.
*/
public ApiFuture<Tenant> createTenantAsync(@NonNull CreateRequest request) {
return createTenantOp(request).callAsync(firebaseApp);
}
private CallableOperation<Tenant, FirebaseAuthException> createTenantOp(
final CreateRequest request) {
checkNotNull(request, "Create request must not be null.");
return new CallableOperation<Tenant, FirebaseAuthException>() {
@Override
protected Tenant execute() throws FirebaseAuthException {
return tenantClient.createTenant(request);
}
};
}
/**
* Updates an existing user account with the attributes contained in the specified {@link
* UpdateRequest}.
*
* @param request A non-null {@link UpdateRequest} instance.
* @return A {@link Tenant} 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 Tenant updateTenant(@NonNull UpdateRequest request) throws FirebaseAuthException {
return updateTenantOp(request).call();
}
/**
* Similar to {@link #updateTenant(UpdateRequest)} but performs the operation asynchronously.
*
* @param request A non-null {@link UpdateRequest} instance.
* @return An {@code ApiFuture} which will complete successfully with a {@link Tenant}
* instance corresponding to the updated user account. If an error occurs while updating the
* user account, the future throws a {@link FirebaseAuthException}.
*/
public ApiFuture<Tenant> updateTenantAsync(@NonNull UpdateRequest request) {
return updateTenantOp(request).callAsync(firebaseApp);
}
private CallableOperation<Tenant, FirebaseAuthException> updateTenantOp(
final UpdateRequest request) {
checkNotNull(request, "Update request must not be null.");
checkArgument(!request.getProperties().isEmpty(),
"Tenant update must have at least one property set.");
return new CallableOperation<Tenant, FirebaseAuthException>() {
@Override
protected Tenant execute() throws FirebaseAuthException {
return tenantClient.updateTenant(request);
}
};
}
/**
* Deletes the tenant identified by the specified tenant ID.
*
* @param tenantId A tenant ID string.
* @throws IllegalArgumentException If the tenant ID string is null or empty.
* @throws FirebaseAuthException If an error occurs while deleting the tenant.
*/
public void deleteTenant(@NonNull String tenantId) throws FirebaseAuthException {
deleteTenantOp(tenantId).call();
}
/**
* Similar to {@link #deleteTenant(String)} but performs the operation asynchronously.
*
* @param tenantId A tenant ID string.
* @return An {@code ApiFuture} which will complete successfully when the specified tenant account
* has been deleted. If an error occurs while deleting the tenant account, the future throws a
* {@link FirebaseAuthException}.
* @throws IllegalArgumentException If the tenant ID string is null or empty.
*/
public ApiFuture<Void> deleteTenantAsync(String tenantId) {
return deleteTenantOp(tenantId).callAsync(firebaseApp);
}
private CallableOperation<Void, FirebaseAuthException> deleteTenantOp(final String tenantId) {
checkArgument(!Strings.isNullOrEmpty(tenantId), "Tenant ID must not be null or empty.");
return new CallableOperation<Void, FirebaseAuthException>() {
@Override
protected Void execute() throws FirebaseAuthException {
tenantClient.deleteTenant(tenantId);
return null;
}
};
}
}