Merge "AccountManager: Allow unlinking of several external IDs at once"
This commit is contained in:
@@ -591,7 +591,7 @@ public class AccountIT extends AbstractDaemonTest {
|
|||||||
assertThat(getEmails()).contains(email);
|
assertThat(getEmails()).contains(email);
|
||||||
|
|
||||||
gApi.accounts().self().deleteEmail(email);
|
gApi.accounts().self().deleteEmail(email);
|
||||||
accountIndexedCounter.assertReindexOf(admin, 2); // for each deleted external ID once
|
accountIndexedCounter.assertReindexOf(admin);
|
||||||
|
|
||||||
resetCurrentApiUser();
|
resetCurrentApiUser();
|
||||||
assertThat(getEmails()).doesNotContain(email);
|
assertThat(getEmails()).doesNotContain(email);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.server.account;
|
package com.google.gerrit.server.account;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.gerrit.audit.AuditService;
|
import com.google.gerrit.audit.AuditService;
|
||||||
import com.google.gerrit.common.data.AccessSection;
|
import com.google.gerrit.common.data.AccessSection;
|
||||||
import com.google.gerrit.common.data.GlobalCapability;
|
import com.google.gerrit.common.data.GlobalCapability;
|
||||||
@@ -412,45 +413,67 @@ public class AccountManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlink an authentication identity from an existing account.
|
* Unlink an external identity from an existing account.
|
||||||
*
|
*
|
||||||
* @param from account to unlink the identity from.
|
* @param from account to unlink the external identity from
|
||||||
* @param who the identity to delete
|
* @param extIdKey the key of the external ID that should be deleted
|
||||||
* @return the result of unlinking the identity from the user.
|
* @throws AccountException the identity belongs to a different account, or the identity was not
|
||||||
* @throws AccountException the identity belongs to a different account, or it cannot be unlinked
|
* found
|
||||||
* at this time.
|
|
||||||
*/
|
*/
|
||||||
public AuthResult unlink(Account.Id from, AuthRequest who)
|
public void unlink(Account.Id from, ExternalId.Key extIdKey)
|
||||||
throws AccountException, OrmException, IOException, ConfigInvalidException {
|
throws AccountException, OrmException, IOException, ConfigInvalidException {
|
||||||
|
unlink(from, ImmutableList.of(extIdKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlink an external identities from an existing account.
|
||||||
|
*
|
||||||
|
* @param from account to unlink the external identity from
|
||||||
|
* @param extIdKeys the keys of the external IDs that should be deleted
|
||||||
|
* @throws AccountException any of the identity belongs to a different account, or any of the
|
||||||
|
* identity was not found
|
||||||
|
*/
|
||||||
|
public void unlink(Account.Id from, Collection<ExternalId.Key> extIdKeys)
|
||||||
|
throws AccountException, OrmException, IOException, ConfigInvalidException {
|
||||||
|
if (extIdKeys.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try (ReviewDb db = schema.open()) {
|
try (ReviewDb db = schema.open()) {
|
||||||
ExternalId extId = externalIds.get(who.getExternalIdKey());
|
List<ExternalId> extIds = new ArrayList<>(extIdKeys.size());
|
||||||
|
for (ExternalId.Key extIdKey : extIdKeys) {
|
||||||
|
ExternalId extId = externalIds.get(extIdKey);
|
||||||
if (extId != null) {
|
if (extId != null) {
|
||||||
if (!extId.accountId().equals(from)) {
|
if (!extId.accountId().equals(from)) {
|
||||||
throw new AccountException(
|
throw new AccountException(
|
||||||
"Identity '" + who.getExternalIdKey().get() + "' in use by another account");
|
"Identity '" + extIdKey.get() + "' in use by another account");
|
||||||
|
}
|
||||||
|
extIds.add(extId);
|
||||||
|
} else {
|
||||||
|
throw new AccountException("Identity '" + extIdKey.get() + "' not found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
externalIdsUpdateFactory.create().delete(extId);
|
|
||||||
|
|
||||||
if (who.getEmailAddress() != null) {
|
externalIdsUpdateFactory.create().delete(extIds);
|
||||||
|
|
||||||
|
if (extIds.stream().anyMatch(e -> e.email() != null)) {
|
||||||
accountsUpdateFactory
|
accountsUpdateFactory
|
||||||
.create()
|
.create()
|
||||||
.update(
|
.update(
|
||||||
db,
|
db,
|
||||||
from,
|
from,
|
||||||
a -> {
|
a -> {
|
||||||
if (a.getPreferredEmail() != null
|
if (a.getPreferredEmail() != null) {
|
||||||
&& a.getPreferredEmail().equals(who.getEmailAddress())) {
|
for (ExternalId extId : extIds) {
|
||||||
|
if (a.getPreferredEmail().equals(extId.email())) {
|
||||||
a.setPreferredEmail(null);
|
a.setPreferredEmail(null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
byEmailCache.evict(who.getEmailAddress());
|
extIds.stream().forEach(e -> byEmailCache.evict(e.email()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new AccountException("Identity '" + who.getExternalIdKey().get() + "' not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AuthResult(from, who.getExternalIdKey(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,11 +92,8 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (ExternalId extId : extIds) {
|
accountManager.unlink(
|
||||||
AuthRequest authRequest = new AuthRequest(extId.key());
|
user.getAccountId(), extIds.stream().map(e -> e.key()).collect(toSet()));
|
||||||
authRequest.setEmailAddress(email);
|
|
||||||
accountManager.unlink(user.getAccountId(), authRequest);
|
|
||||||
}
|
|
||||||
} catch (AccountException e) {
|
} catch (AccountException e) {
|
||||||
throw new ResourceConflictException(e.getMessage());
|
throw new ResourceConflictException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package com.google.gerrit.server.account;
|
|||||||
|
|
||||||
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
|
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
|
||||||
import static java.util.stream.Collectors.toMap;
|
import static java.util.stream.Collectors.toMap;
|
||||||
|
import static java.util.stream.Collectors.toSet;
|
||||||
|
|
||||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
@@ -96,11 +97,8 @@ public class DeleteExternalIds implements RestModifyView<AccountResource, List<S
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (ExternalId extId : toDelete) {
|
accountManager.unlink(
|
||||||
AuthRequest authRequest = new AuthRequest(extId.key());
|
resource.getUser().getAccountId(), toDelete.stream().map(e -> e.key()).collect(toSet()));
|
||||||
authRequest.setEmailAddress(extId.email());
|
|
||||||
accountManager.unlink(extId.accountId(), authRequest);
|
|
||||||
}
|
|
||||||
} catch (AccountException e) {
|
} catch (AccountException e) {
|
||||||
throw new ResourceConflictException(e.getMessage());
|
throw new ResourceConflictException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user