Skip to content

chore: Merging master into tenant-mgt #422

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

Merged
merged 8 commits into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .github/resources/firebase.asc.gpg
Binary file not shown.
2 changes: 1 addition & 1 deletion .github/resources/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</activation>
<properties>
<gpg.executable>gpg</gpg.executable>
<gpg.keyname>B652FFD3865AF7A75830876F5F55C8F6985BB9DD</gpg.keyname>
<gpg.keyname>A9B90B41060565F56F348F948B6B459CFD695DE8</gpg.keyname>
<gpg.passphrase>${env.GPG_PASSPHRASE}</gpg.passphrase>
</properties>
</profile>
Expand Down
2 changes: 1 addition & 1 deletion .github/scripts/publish_artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ set -u
gpg --quiet --batch --yes --decrypt --passphrase="${GPG_PRIVATE_KEY}" \
--output firebase.asc .github/resources/firebase.asc.gpg

gpg --import firebase.asc
gpg --import --no-tty --batch --yes firebase.asc

# Does the following:
# 1. Compiles the source (compile phase)
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ jobs:
id: preflight
run: ./.github/scripts/publish_preflight_check.sh

- name: Publish to Maven Central
run: ./.github/scripts/publish_artifacts.sh
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
NEXUS_OSSRH_USERNAME: ${{ secrets.NEXUS_OSSRH_USERNAME }}
NEXUS_OSSRH_PASSWORD: ${{ secrets.NEXUS_OSSRH_PASSWORD }}

# We pull this action from a custom fork of a contributor until
# https://github.com/actions/create-release/pull/32 is merged. Also note that v1 of
# this action does not support the "body" parameter.
Expand All @@ -105,14 +113,6 @@ jobs:
draft: false
prerelease: false

- name: Publish to Maven Central
run: ./.github/scripts/publish_artifacts.sh
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
NEXUS_OSSRH_USERNAME: ${{ secrets.NEXUS_OSSRH_USERNAME }}
NEXUS_OSSRH_PASSWORD: ${{ secrets.NEXUS_OSSRH_PASSWORD }}

# Post to Twitter if explicitly opted-in by adding the label 'release:tweet'.
- name: Post to Twitter
if: success() &&
Expand Down
12 changes: 10 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>6.12.3-SNAPSHOT</version>
<version>6.13.0</version>
<packaging>jar</packaging>

<name>firebase-admin</name>
Expand Down Expand Up @@ -59,7 +59,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<skipUTs>${skipTests}</skipUTs>
<netty.version>4.1.34.Final</netty.version>
<netty.version>4.1.45.Final</netty.version>
</properties>

<scm>
Expand Down Expand Up @@ -99,6 +99,7 @@
<plugin>
<!-- Generate API docs using Doclava for the developer site -->
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<executions>
<execution>
<phase>site</phase>
Expand Down Expand Up @@ -173,6 +174,12 @@
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
Expand Down Expand Up @@ -303,6 +310,7 @@
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<executions>
<execution>
<id>attach-javadocs</id>
Expand Down
137 changes: 137 additions & 0 deletions src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
import com.google.firebase.internal.NonNull;
import com.google.firebase.internal.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
Expand Down Expand Up @@ -762,6 +765,140 @@ protected UserImportResult execute() throws FirebaseAuthException {
};
}

/**
* Gets the user data corresponding to the specified identifiers.
*
* <p>There are no ordering guarantees; in particular, the nth entry in the users result list is
* not guaranteed to correspond to the nth entry in the input parameters list.
*
* <p>A maximum of 100 identifiers may be specified. If more than 100 identifiers are
* supplied, this method throws an {@link IllegalArgumentException}.
*
* @param identifiers The identifiers used to indicate which user records should be returned. Must
* have 100 or fewer entries.
* @return The corresponding user records.
* @throws IllegalArgumentException If any of the identifiers are invalid or if more than 100
* identifiers are specified.
* @throws NullPointerException If the identifiers parameter is null.
* @throws FirebaseAuthException If an error occurs while retrieving user data.
*/
public GetUsersResult getUsers(@NonNull Collection<UserIdentifier> identifiers)
throws FirebaseAuthException {
return getUsersOp(identifiers).call();
}

/**
* Gets the user data corresponding to the specified identifiers.
*
* <p>There are no ordering guarantees; in particular, the nth entry in the users result list is
* not guaranteed to correspond to the nth entry in the input parameters list.
*
* <p>A maximum of 100 identifiers may be specified. If more than 100 identifiers are
* supplied, this method throws an {@link IllegalArgumentException}.
*
* @param identifiers The identifiers used to indicate which user records should be returned.
* Must have 100 or fewer entries.
* @return An {@code ApiFuture} that resolves to the corresponding user records.
* @throws IllegalArgumentException If any of the identifiers are invalid or if more than 100
* identifiers are specified.
* @throws NullPointerException If the identifiers parameter is null.
*/
public ApiFuture<GetUsersResult> getUsersAsync(@NonNull Collection<UserIdentifier> identifiers) {
return getUsersOp(identifiers).callAsync(firebaseApp);
}

private CallableOperation<GetUsersResult, FirebaseAuthException> getUsersOp(
@NonNull final Collection<UserIdentifier> identifiers) {
checkNotDestroyed();
checkNotNull(identifiers, "identifiers must not be null");
checkArgument(identifiers.size() <= FirebaseUserManager.MAX_GET_ACCOUNTS_BATCH_SIZE,
"identifiers parameter must have <= " + FirebaseUserManager.MAX_GET_ACCOUNTS_BATCH_SIZE
+ " entries.");

final FirebaseUserManager userManager = getUserManager();
return new CallableOperation<GetUsersResult, FirebaseAuthException>() {
@Override
protected GetUsersResult execute() throws FirebaseAuthException {
Set<UserRecord> users = userManager.getAccountInfo(identifiers);
Set<UserIdentifier> notFound = new HashSet<>();
for (UserIdentifier id : identifiers) {
if (!isUserFound(id, users)) {
notFound.add(id);
}
}
return new GetUsersResult(users, notFound);
}
};
}

private boolean isUserFound(UserIdentifier id, Collection<UserRecord> userRecords) {
for (UserRecord userRecord : userRecords) {
if (id.matches(userRecord)) {
return true;
}
}
return false;
}

/**
* Deletes the users specified by the given identifiers.
*
* <p>Deleting a non-existing user does not generate an error (the method is idempotent).
* Non-existing users are considered to be successfully deleted and are therefore included in the
* DeleteUsersResult.getSuccessCount() value.
*
* <p>A maximum of 1000 identifiers may be supplied. If more than 1000 identifiers are
* supplied, this method throws an {@link IllegalArgumentException}.
*
* <p>This API has a rate limit of 1 QPS. Exceeding the limit may result in a quota exceeded
* error. If you want to delete more than 1000 users, we suggest adding a delay to ensure you
* don't exceed this limit.
*
* @param uids The uids of the users to be deleted. Must have <= 1000 entries.
* @return The total number of successful/failed deletions, as well as the array of errors that
* correspond to the failed deletions.
* @throw IllegalArgumentException If any of the identifiers are invalid or if more than 1000
* identifiers are specified.
* @throws FirebaseAuthException If an error occurs while deleting users.
*/
public DeleteUsersResult deleteUsers(List<String> uids) throws FirebaseAuthException {
return deleteUsersOp(uids).call();
}

/**
* Similar to {@link #deleteUsers(List)} but performs the operation asynchronously.
*
* @param uids The uids of the users to be deleted. Must have <= 1000 entries.
* @return An {@code ApiFuture} that resolves to the total number of successful/failed
* deletions, as well as the array of errors that correspond to the failed deletions. If an
* error occurs while deleting the user account, the future throws a
* {@link FirebaseAuthException}.
* @throw IllegalArgumentException If any of the identifiers are invalid or if more than 1000
* identifiers are specified.
*/
public ApiFuture<DeleteUsersResult> deleteUsersAsync(List<String> uids) {
return deleteUsersOp(uids).callAsync(firebaseApp);
}

private CallableOperation<DeleteUsersResult, FirebaseAuthException> deleteUsersOp(
final List<String> uids) {
checkNotDestroyed();
checkNotNull(uids, "uids must not be null");
for (String uid : uids) {
UserRecord.checkUid(uid);
}
checkArgument(uids.size() <= FirebaseUserManager.MAX_DELETE_ACCOUNTS_BATCH_SIZE,
"uids parameter must have <= " + FirebaseUserManager.MAX_DELETE_ACCOUNTS_BATCH_SIZE
+ " entries.");
final FirebaseUserManager userManager = getUserManager();
return new CallableOperation<DeleteUsersResult, FirebaseAuthException>() {
@Override
protected DeleteUsersResult execute() throws FirebaseAuthException {
return userManager.deleteUsers(uids);
}
};
}

/**
* Generates the out-of-band email action link for password reset flows for the specified email
* address.
Expand Down
74 changes: 74 additions & 0 deletions src/main/java/com/google/firebase/auth/DeleteUsersResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2020 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 static com.google.common.base.Preconditions.checkArgument;

import com.google.common.collect.ImmutableList;
import com.google.firebase.auth.internal.BatchDeleteResponse;
import com.google.firebase.internal.NonNull;
import java.util.List;

/**
* Represents the result of the {@link FirebaseAuth#deleteUsersAsync(List)} API.
*/
public final class DeleteUsersResult {

private final int successCount;
private final List<ErrorInfo> errors;

DeleteUsersResult(int users, BatchDeleteResponse response) {
ImmutableList.Builder<ErrorInfo> errorsBuilder = ImmutableList.builder();
List<BatchDeleteResponse.ErrorInfo> responseErrors = response.getErrors();
if (responseErrors != null) {
checkArgument(users >= responseErrors.size());
for (BatchDeleteResponse.ErrorInfo error : responseErrors) {
errorsBuilder.add(new ErrorInfo(error.getIndex(), error.getMessage()));
}
}
errors = errorsBuilder.build();
successCount = users - errors.size();
}

/**
* Returns the number of users that were deleted successfully (possibly zero). Users that did not
* exist prior to calling {@link FirebaseAuth#deleteUsersAsync(List)} are considered to be
* successfully deleted.
*/
public int getSuccessCount() {
return successCount;
}

/**
* Returns the number of users that failed to be deleted (possibly zero).
*/
public int getFailureCount() {
return errors.size();
}

/**
* A list of {@link ErrorInfo} instances describing the errors that were encountered during
* the deletion. Length of this list is equal to the return value of
* {@link #getFailureCount()}.
*
* @return A non-null list (possibly empty).
*/
@NonNull
public List<ErrorInfo> getErrors() {
return errors;
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/google/firebase/auth/EmailIdentifier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2020 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.GetAccountInfoRequest;
import com.google.firebase.internal.NonNull;

/**
* Used for looking up an account by email.
*
* @see {FirebaseAuth#getUsers}
*/
public final class EmailIdentifier extends UserIdentifier {
private final String email;

public EmailIdentifier(@NonNull String email) {
UserRecord.checkEmail(email);
this.email = email;
}

@Override
public String toString() {
return "EmailIdentifier(" + email + ")";
}

@Override
void populate(@NonNull GetAccountInfoRequest payload) {
payload.addEmail(email);
}

@Override
boolean matches(@NonNull UserRecord userRecord) {
return email.equals(userRecord.getEmail());
}
}
3 changes: 1 addition & 2 deletions src/main/java/com/google/firebase/auth/FirebaseAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import com.google.common.base.Supplier;
import com.google.firebase.FirebaseApp;
import com.google.firebase.ImplFirebaseTrampolines;
import com.google.firebase.auth.AbstractFirebaseAuth.Builder;
import com.google.firebase.auth.internal.FirebaseTokenFactory;
import com.google.firebase.internal.CallableOperation;
import com.google.firebase.internal.FirebaseService;
Expand All @@ -41,7 +40,7 @@
* 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.
*/
public class FirebaseAuth extends AbstractFirebaseAuth {
public final class FirebaseAuth extends AbstractFirebaseAuth {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make TenantAwareFirebaseAuth final for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should. Lets do that in a separate PR to keep this merge commit clean.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright! I'll slip that into tenant-mgt in a separate commit.


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

Expand Down
Loading