Merge "Revert "Retire the token highlight experiment""
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 2a019ca..3da69df 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -477,6 +477,11 @@
`+refs/heads/sandbox/${username}/*+`. If you do, it's also recommended
you grant the users the push force permission to be able to clean up
stale branches.
+If link:config-gerrit.html#auth.userNameCaseInsensitive[auth.userNameCaseInsensitive]
+is enabled, the `${username}` is still case sensitive and will use
+the capitalization used during account creation. This is done, since
+git branches are case sensitive, so that sandbox branches containing
+`${username}` are still reachable by the users.
[[category_delete]]
=== Delete Reference
diff --git a/Documentation/cmd-set-account.txt b/Documentation/cmd-set-account.txt
index 6808e017..02eaf83 100644
--- a/Documentation/cmd-set-account.txt
+++ b/Documentation/cmd-set-account.txt
@@ -14,7 +14,8 @@
[--delete-ssh-key - | <KEY> | ALL]
[--generate-http-password]
[--http-password <PASSWORD>]
- [--clear-http-password] <USER>
+ [--clear-http-password]
+ [--delete-external-id <EXTERNALID>] <USER>
--
== DESCRIPTION
@@ -106,6 +107,13 @@
--clear-http-password::
Clear the HTTP password for the user account.
+--delete-external-id::
+ Delete an external ID from a user's account if it exists.
+ If the external ID provided is 'ALL', all associated
+ external IDs are deleted from this account.
+ May be supplied more than once to remove multiple external
+ IDs from an account in a single command execution.
+
== EXAMPLES
Add an email and SSH key to `watcher`'s account:
diff --git a/Documentation/config-accounts.txt b/Documentation/config-accounts.txt
index 2f226536..7a7cef2 100644
--- a/Documentation/config-accounts.txt
+++ b/Documentation/config-accounts.txt
@@ -297,6 +297,13 @@
This ensures that an external ID is used only once (e.g. an external ID can
never be assigned to multiple accounts at a point in time).
+By default, the SHA-1 sum is computed preserving the case of the external ID. If
+auth.userNameCaseInsensitive` is set to `true`, the SHA-1 sum of external IDs
+in the `gerrit:` and `username:` schemes are computed from the all lowercase
+external ID. This enables case insensitive username handling. The case of the
+external ID is however preserved by using the original capitalization in the
+note content.
+
The following commands show how to find the SHA-1 of an external ID:
----
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 90c69b6..9e73f6f 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -652,6 +652,32 @@
+
By default this is set to false.
+[[auth.userNameCaseInsensitive]]auth.userNameCaseInsensitive::
++
+If set the username will be handled case insensitively but case preserving,
+i.e. a user can login with `johndoe` or `JohnDoe` for the same account
+created for `JohnDoe`. The form of the username used during account creation
+will be used wherever the username is displayed. Sandbox branches created
+for a user can also only be created for this original form.
++
+Note, that this does not work for all existing accounts, if they were
+not originally created with all lowercase, since the note keys of the
+external IDs will not match the new scheme. For more details refer to
+the link:config-accounts.html#external-ids[External ID documentation].
++
+Gerrit provides the
+link:pgm-ChangeExternalIdCaseSensitivity.html[ChangeExternalIdCaseSensitivity tool]
+to migrate existing accounts to match the new scheme.
++
+Naturally, if there were two accounts only different in capitalization,
+e.g. `johndoe` and `JohnDoe`, the account `JohnDoe` will not be able
+to authenticate anymore after setting this option. If such duplicate
+accounts exist the migration tool will fail, since the newly computed
+note name would be identical and thus conflict. These duplicates thus
+have to be deleted manually by deleting the respective external ID.
++
+Default is false.
+
[[auth.enableRunAs]]auth.enableRunAs::
+
If true HTTP REST APIs will accept the `X-Gerrit-RunAs` HTTP request
diff --git a/Documentation/pgm-ChangeExternalIdCaseSensitivity.txt b/Documentation/pgm-ChangeExternalIdCaseSensitivity.txt
new file mode 100644
index 0000000..1fb4b97
--- /dev/null
+++ b/Documentation/pgm-ChangeExternalIdCaseSensitivity.txt
@@ -0,0 +1,71 @@
+= ChangeExternalIdCaseSensitivity
+
+== NAME
+ChangeExternalIdCaseSensitivity - Convert `username` and `gerrit`
+external IDs to be handled case insensitively
+
+== SYNOPSIS
+[verse]
+--
+_java_ -jar gerrit.war _ChangeExternalIdCaseSensitivity_
+ -d <SITE_PATH>
+ [--batch]
+ [--dryrun]
+--
+
+== DESCRIPTION
+Convert `username` and `gerrit` external IDs to be handled case
+insensitively or case sensitively. This is done by recomputing
+the name of the note from the sha1 sum of the all lowercase
+external ID key or of the key with its original capitalization
+respectively.
+
+The tool uses the `auth.userNameCaseInsensitive` option to determine,
+whether the migration should be performed to case insensitive or case sensitive
+usernames, i.e. if the option is set to `false`, migration will be performed to
+make external IDs case insensitive and if set to `true` to case sensitive.
+
+== OPTIONS
+
+-d::
+--site-path::
+ Path of the Gerrit site
+
+--batch::
+ No user interaction is required. The tool won't ask for confirmation before migrating.
+
+--dryrun::
+ Whether to perform the conversion without persisting it.
+
+== CONTEXT
+This command can only be run offline with direct access to the server's
+site.
+
+== EXAMPLES
+To convert the external IDs to be case insensitive:
+
+----
+ $ git config -f $SITE/etc/gerrit.config --get auth.userNameCaseInsensitive
+ > false
+ $ java -jar gerrit.war ChangeExternalIdCaseSensitivity -d site_path
+----
+
+To convert the external IDs to be case sensitive again:
+
+----
+ $ git config -f $SITE/etc/gerrit.config --get auth.userNameCaseInsensitive
+ > true
+ $ java -jar gerrit.war ChangeExternalIdCaseSensitivity -d site_path
+----
+
+
+== SEE ALSO
+
+* Configuration parameter link:config-gerrit.html#auth.userNameCaseInsensitive[auth.userNameCaseInsensitive]
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-index.txt b/Documentation/pgm-index.txt
index dde0231..8f4cbda 100644
--- a/Documentation/pgm-index.txt
+++ b/Documentation/pgm-index.txt
@@ -38,6 +38,9 @@
link:pgm-LocalUsernamesToLowerCase.html[LocalUsernamesToLowerCase]::
Convert the local username of every account to lower case.
+link:pgm-ChangeExternalIdCaseSensitivity.html[ChangeExternalIdCaseSensitivity]::
+ Convert external IDs to be case insensitive.
+
link:pgm-MigrateAccountPatchReviewDb.html[MigrateAccountPatchReviewDb]::
Migrates AccountPatchReviewDb from one database backend to another.
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 3510305..a613c7e 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -1779,7 +1779,16 @@
Only external ids belonging to the caller may be deleted. Users that have
link:access-control.html#capability_modifyAccount[Modify Account] can delete
-external ids that belong to other accounts.
+external ids that belong to other accounts. External ids in the 'username:'
+scheme can only be deleted by users that have
+link:access-control.html#capability_administrateServer[Administrate Server]
+or both
+link:access-control.html#capability_maintainServer[Maintain Server] and
+link:access-control.html#capability__modifyAccount[Modify Account]
+since the user may not be able to login anymore, after the removal of the
+external id with scheme 'username:'. Users cannot delete their own external id
+with scheme 'username:' in order to prevent they can lock themselves out
+since they may not be able to login anymore.
.Request
----
diff --git a/java/com/google/gerrit/acceptance/AccountCreator.java b/java/com/google/gerrit/acceptance/AccountCreator.java
index aa13339..c67991d 100644
--- a/java/com/google/gerrit/acceptance/AccountCreator.java
+++ b/java/com/google/gerrit/acceptance/AccountCreator.java
@@ -29,6 +29,7 @@
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.group.db.GroupDelta;
import com.google.gerrit.server.group.db.GroupsUpdate;
import com.google.gerrit.server.notedb.Sequences;
@@ -52,18 +53,21 @@
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final GroupCache groupCache;
private final Provider<GroupsUpdate> groupsUpdateProvider;
+ private final ExternalIdFactory externalIdFactory;
@Inject
AccountCreator(
Sequences sequences,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider,
GroupCache groupCache,
- @ServerInitiated Provider<GroupsUpdate> groupsUpdateProvider) {
+ @ServerInitiated Provider<GroupsUpdate> groupsUpdateProvider,
+ ExternalIdFactory externalIdFactory) {
accounts = new HashMap<>();
this.sequences = sequences;
this.accountsUpdateProvider = accountsUpdateProvider;
this.groupCache = groupCache;
this.groupsUpdateProvider = groupsUpdateProvider;
+ this.externalIdFactory = externalIdFactory;
}
public synchronized TestAccount create(
@@ -84,11 +88,11 @@
String httpPass = null;
if (username != null) {
httpPass = "http-pass";
- extIds.add(ExternalId.createUsername(username, id, httpPass));
+ extIds.add(externalIdFactory.createUsername(username, id, httpPass));
}
if (email != null) {
- extIds.add(ExternalId.createEmail(id, email));
+ extIds.add(externalIdFactory.createEmail(id, email));
}
accountsUpdateProvider
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
index 3763f9a..c6457a4 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
@@ -27,6 +27,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AccountsUpdate.ConfigureDeltaFromState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.notedb.Sequences;
import com.google.inject.Inject;
import java.io.IOException;
@@ -44,13 +45,18 @@
private final Accounts accounts;
private final AccountsUpdate accountsUpdate;
private final Sequences seq;
+ private final ExternalIdFactory externalIdFactory;
@Inject
public AccountOperationsImpl(
- Accounts accounts, @ServerInitiated AccountsUpdate accountsUpdate, Sequences seq) {
+ Accounts accounts,
+ @ServerInitiated AccountsUpdate accountsUpdate,
+ Sequences seq,
+ ExternalIdFactory externalIdFactory) {
this.accounts = accounts;
this.accountsUpdate = accountsUpdate;
this.seq = seq;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -72,7 +78,7 @@
return createdAccount.account().id();
}
- private static void initAccountDelta(
+ private void initAccountDelta(
AccountDelta.Builder builder, TestAccountCreation accountCreation, Account.Id accountId) {
accountCreation.fullname().ifPresent(builder::setFullName);
accountCreation.preferredEmail().ifPresent(e -> setPreferredEmail(builder, accountId, e));
@@ -84,19 +90,19 @@
.secondaryEmails()
.forEach(
secondaryEmail ->
- builder.addExternalId(ExternalId.createEmail(accountId, secondaryEmail)));
+ builder.addExternalId(externalIdFactory.createEmail(accountId, secondaryEmail)));
}
- private static void setPreferredEmail(
+ private void setPreferredEmail(
AccountDelta.Builder builder, Account.Id accountId, String preferredEmail) {
builder
.setPreferredEmail(preferredEmail)
- .addExternalId(ExternalId.createEmail(accountId, preferredEmail));
+ .addExternalId(externalIdFactory.createEmail(accountId, preferredEmail));
}
- private static void setUsername(
+ private void setUsername(
AccountDelta.Builder builder, Account.Id accountId, String username, String httpPassword) {
- builder.addExternalId(ExternalId.createUsername(username, accountId, httpPassword));
+ builder.addExternalId(externalIdFactory.createUsername(username, accountId, httpPassword));
}
private class PerAccountOperationsImpl implements PerAccountOperations {
@@ -202,14 +208,14 @@
.collect(toImmutableSet()));
builder.addExternalIds(
newSecondaryEmails.stream()
- .map(secondaryEmail -> ExternalId.createEmail(accountId, secondaryEmail))
+ .map(secondaryEmail -> externalIdFactory.createEmail(accountId, secondaryEmail))
.collect(toImmutableSet()));
if (accountUpdate.preferredEmail().isPresent()) {
builder.addExternalId(
- ExternalId.createEmail(accountId, accountUpdate.preferredEmail().get()));
+ externalIdFactory.createEmail(accountId, accountUpdate.preferredEmail().get()));
} else if (accountState.account().preferredEmail() != null) {
builder.addExternalId(
- ExternalId.createEmail(accountId, accountState.account().preferredEmail()));
+ externalIdFactory.createEmail(accountId, accountState.account().preferredEmail()));
}
}
diff --git a/java/com/google/gerrit/auth/ldap/LdapRealm.java b/java/com/google/gerrit/auth/ldap/LdapRealm.java
index 9305914..9a9f309 100644
--- a/java/com/google/gerrit/auth/ldap/LdapRealm.java
+++ b/java/com/google/gerrit/auth/ldap/LdapRealm.java
@@ -32,6 +32,7 @@
import com.google.gerrit.server.account.EmailExpander;
import com.google.gerrit.server.account.GroupBackends;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.auth.AuthenticationUnavailableException;
import com.google.gerrit.server.auth.NoSuchUserException;
@@ -346,10 +347,12 @@
static class UserLoader extends CacheLoader<String, Optional<Account.Id>> {
private final ExternalIds externalIds;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
- UserLoader(ExternalIds externalIds) {
+ UserLoader(ExternalIds externalIds, ExternalIdKeyFactory externalIdKeyFactory) {
this.externalIds = externalIds;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -358,7 +361,7 @@
TraceContext.newTimer(
"Loading account for username", Metadata.builder().username(username).build())) {
return externalIds
- .get(ExternalId.Key.create(SCHEME_GERRIT, username))
+ .get(externalIdKeyFactory.create(SCHEME_GERRIT, username))
.map(ExternalId::accountId);
}
}
diff --git a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
index 9477cb6..71dff97 100644
--- a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
+++ b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
@@ -26,6 +26,7 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.query.account.InternalAccountQuery;
@@ -62,17 +63,20 @@
private final IdentifiedUser.GenericFactory userFactory;
private final int maxTrustDepth;
private final ImmutableMap<Long, Fingerprint> trusted;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
Factory(
@GerritServerConfig Config cfg,
Provider<InternalAccountQuery> accountQueryProvider,
IdentifiedUser.GenericFactory userFactory,
- DynamicItem<UrlFormatter> urlFormatter) {
+ DynamicItem<UrlFormatter> urlFormatter,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.accountQueryProvider = accountQueryProvider;
this.urlFormatter = urlFormatter;
this.userFactory = userFactory;
this.maxTrustDepth = cfg.getInt("receive", null, "maxTrustDepth", 0);
+ this.externalIdKeyFactory = externalIdKeyFactory;
String[] strs = cfg.getStringList("receive", null, "trustedKey");
if (strs.length != 0) {
@@ -103,6 +107,7 @@
private final Provider<InternalAccountQuery> accountQueryProvider;
private final DynamicItem<UrlFormatter> urlFormatter;
private final IdentifiedUser.GenericFactory userFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
private IdentifiedUser expectedUser;
@@ -113,6 +118,7 @@
if (factory.trusted != null) {
enableTrust(factory.maxTrustDepth, factory.trusted);
}
+ this.externalIdKeyFactory = factory.externalIdKeyFactory;
}
/**
@@ -247,7 +253,8 @@
return sb.toString();
}
- static ExternalId.Key toExtIdKey(PGPPublicKey key) {
- return ExternalId.Key.create(SCHEME_GPGKEY, BaseEncoding.base16().encode(key.getFingerprint()));
+ ExternalId.Key toExtIdKey(PGPPublicKey key) {
+ return externalIdKeyFactory.create(
+ SCHEME_GPGKEY, BaseEncoding.base16().encode(key.getFingerprint()));
}
}
diff --git a/java/com/google/gerrit/gpg/server/DeleteGpgKey.java b/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
index 1be37f5..e0c921d 100644
--- a/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
+++ b/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
@@ -32,6 +32,7 @@
import com.google.gerrit.server.UserInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.mail.send.DeleteKeySender;
import com.google.inject.Inject;
@@ -53,6 +54,7 @@
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final ExternalIds externalIds;
private final DeleteKeySender.Factory deleteKeySenderFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
DeleteGpgKey(
@@ -60,12 +62,14 @@
Provider<PublicKeyStore> storeProvider,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider,
ExternalIds externalIds,
- DeleteKeySender.Factory deleteKeySenderFactory) {
+ DeleteKeySender.Factory deleteKeySenderFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.serverIdent = serverIdent;
this.storeProvider = storeProvider;
this.accountsUpdateProvider = accountsUpdateProvider;
this.externalIds = externalIds;
this.deleteKeySenderFactory = deleteKeySenderFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -73,7 +77,8 @@
throws RestApiException, PGPException, IOException, ConfigInvalidException {
PGPPublicKey key = rsrc.getKeyRing().getPublicKey();
String fingerprint = BaseEncoding.base16().encode(key.getFingerprint());
- Optional<ExternalId> extId = externalIds.get(ExternalId.Key.create(SCHEME_GPGKEY, fingerprint));
+ Optional<ExternalId> extId =
+ externalIds.get(externalIdKeyFactory.create(SCHEME_GPGKEY, fingerprint));
if (!extId.isPresent()) {
throw new ResourceNotFoundException(fingerprint);
}
diff --git a/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index 1b5e06a..d46b344 100644
--- a/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -53,6 +53,8 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.mail.send.AddKeySender;
import com.google.gerrit.server.mail.send.DeleteKeySender;
@@ -93,6 +95,8 @@
private final ExternalIds externalIds;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final RetryHelper retryHelper;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
PostGpgKeys(
@@ -105,7 +109,9 @@
Provider<InternalAccountQuery> accountQueryProvider,
ExternalIds externalIds,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider,
- RetryHelper retryHelper) {
+ RetryHelper retryHelper,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.serverIdent = serverIdent;
this.self = self;
this.storeProvider = storeProvider;
@@ -116,6 +122,8 @@
this.externalIds = externalIds;
this.accountsUpdateProvider = accountsUpdateProvider;
this.retryHelper = retryHelper;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -140,7 +148,7 @@
throw new ResourceConflictException("GPG key already associated with another account");
}
} else {
- newExtIds.add(ExternalId.create(extIdKey, rsrc.getUser().getAccountId()));
+ newExtIds.add(externalIdFactory.create(extIdKey, rsrc.getUser().getAccountId()));
}
}
@@ -287,7 +295,7 @@
}
private ExternalId.Key toExtIdKey(byte[] fp) {
- return ExternalId.Key.create(SCHEME_GPGKEY, BaseEncoding.base16().encode(fp));
+ return externalIdKeyFactory.create(SCHEME_GPGKEY, BaseEncoding.base16().encode(fp));
}
private Account getAccountByExternalId(ExternalId.Key extIdKey) {
diff --git a/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
index de989ac..a421139 100644
--- a/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
@@ -76,17 +76,23 @@
private final AccountCache accountCache;
private final AccountManager accountManager;
private final AuthConfig authConfig;
+ private final AuthRequest.Factory authRequestFactory;
+ private final PasswordVerifier passwordVerifier;
@Inject
ProjectBasicAuthFilter(
DynamicItem<WebSession> session,
AccountCache accountCache,
AccountManager accountManager,
- AuthConfig authConfig) {
+ AuthConfig authConfig,
+ AuthRequest.Factory authRequestFactory,
+ PasswordVerifier passwordVerifier) {
this.session = session;
this.accountCache = accountCache;
this.accountManager = accountManager;
this.authConfig = authConfig;
+ this.authRequestFactory = authRequestFactory;
+ this.passwordVerifier = passwordVerifier;
}
@Override
@@ -155,7 +161,7 @@
GitBasicAuthPolicy gitBasicAuthPolicy = authConfig.getGitBasicAuthPolicy();
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP
|| gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP) {
- if (PasswordVerifier.checkPassword(who.externalIds(), username, password)) {
+ if (passwordVerifier.checkPassword(who.externalIds(), username, password)) {
logger.atFine().log(
"HTTP:%s %s username/password authentication succeeded",
req.getMethod(), req.getRequestURI());
@@ -167,7 +173,7 @@
return failAuthentication(rsp, username, req);
}
- AuthRequest whoAuth = AuthRequest.forUser(username);
+ AuthRequest whoAuth = authRequestFactory.createForUser(username);
whoAuth.setPassword(password);
try {
@@ -177,7 +183,7 @@
"HTTP:%s %s Realm authentication succeeded", req.getMethod(), req.getRequestURI());
return true;
} catch (NoSuchUserException e) {
- if (PasswordVerifier.checkPassword(who.externalIds(), username, password)) {
+ if (passwordVerifier.checkPassword(who.externalIds(), username, password)) {
return succeedAuthentication(who, null);
}
logger.atWarning().withCause(e).log(authenticationFailedMsg(username, req));
diff --git a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
index dab36c4..fa53053 100644
--- a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
@@ -76,6 +76,7 @@
private final AccountManager accountManager;
private final String gitOAuthProvider;
private final boolean userNameToLowerCase;
+ private final AuthRequest.Factory authRequestFactory;
private String defaultAuthPlugin;
private String defaultAuthProvider;
@@ -86,13 +87,15 @@
DynamicMap<OAuthLoginProvider> pluginsProvider,
AccountCache accountCache,
AccountManager accountManager,
- @GerritServerConfig Config gerritConfig) {
+ @GerritServerConfig Config gerritConfig,
+ AuthRequest.Factory authRequestFactory) {
this.session = session;
this.loginProviders = pluginsProvider;
this.accountCache = accountCache;
this.accountManager = accountManager;
this.gitOAuthProvider = gerritConfig.getString("auth", null, "gitOAuthProvider");
this.userNameToLowerCase = gerritConfig.getBoolean("auth", null, "userNameToLowerCase", false);
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -162,7 +165,7 @@
}
Account account = who.get().account();
- AuthRequest authRequest = AuthRequest.forExternalUser(authInfo.username);
+ AuthRequest authRequest = authRequestFactory.createForExternalUser(authInfo.username);
authRequest.setEmailAddress(account.preferredEmail());
authRequest.setDisplayName(account.fullName());
authRequest.setPassword(authInfo.tokenOrSecret);
diff --git a/java/com/google/gerrit/httpd/WebModule.java b/java/com/google/gerrit/httpd/WebModule.java
index e416075..0645aac 100644
--- a/java/com/google/gerrit/httpd/WebModule.java
+++ b/java/com/google/gerrit/httpd/WebModule.java
@@ -75,6 +75,10 @@
listener().toInstance(registerInParentInjectors());
install(UniversalWebLoginFilter.module());
+
+ // Static injection was unfortunately the best solution in this place. However, it is to be
+ // avoided if possible.
+ requestStaticInjection(WebSessionManager.Val.class);
}
private void installAuthModule() {
diff --git a/java/com/google/gerrit/httpd/WebSessionManager.java b/java/com/google/gerrit/httpd/WebSessionManager.java
index c0900ec..87bf3a6 100644
--- a/java/com/google/gerrit/httpd/WebSessionManager.java
+++ b/java/com/google/gerrit/httpd/WebSessionManager.java
@@ -32,6 +32,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
@@ -186,6 +187,8 @@
public static final class Val implements Serializable {
static final long serialVersionUID = 2L;
+ @Inject private static transient ExternalIdKeyFactory externalIdKeyFactory;
+
private transient Account.Id accountId;
private transient long refreshCookieAt;
private transient boolean persistentCookie;
@@ -295,7 +298,7 @@
persistentCookie = readVarInt32(in) != 0;
continue;
case 4:
- externalId = ExternalId.Key.parse(readString(in));
+ externalId = externalIdKeyFactory.parse(readString(in));
continue;
case 5:
sessionId = readString(in);
diff --git a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index 97bb44b..2f760f0 100644
--- a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -31,7 +31,7 @@
import com.google.gerrit.server.account.Accounts;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.query.account.InternalAccountQuery;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.inject.Inject;
@@ -62,6 +62,8 @@
private final AccountManager accountManager;
private final SiteHeaderFooter headers;
private final Provider<InternalAccountQuery> queryProvider;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
BecomeAnyAccountLoginServlet(
@@ -70,13 +72,17 @@
AccountCache ac,
AccountManager am,
SiteHeaderFooter shf,
- Provider<InternalAccountQuery> qp) {
+ Provider<InternalAccountQuery> qp,
+ ExternalIdKeyFactory eikf,
+ AuthRequest.Factory arf) {
webSession = ws;
accounts = a;
accountCache = ac;
accountManager = am;
headers = shf;
queryProvider = qp;
+ externalIdKeyFactory = eikf;
+ authRequestFactory = arf;
}
@Override
@@ -220,7 +226,8 @@
private AuthResult create() throws IOException {
try {
return accountManager.authenticate(
- new AuthRequest(ExternalId.Key.create(SCHEME_UUID, UUID.randomUUID().toString())));
+ authRequestFactory.create(
+ externalIdKeyFactory.create(SCHEME_UUID, UUID.randomUUID().toString())));
} catch (AccountException e) {
getServletContext().log("cannot create new account", e);
return null;
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java b/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
index e20c9b9..acb3282 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
@@ -26,6 +26,7 @@
import com.google.gerrit.httpd.RemoteUserUtil;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.gerrit.util.http.RequestUtil;
@@ -64,10 +65,16 @@
private final String emailHeader;
private final String externalIdHeader;
private final boolean userNameToLowerCase;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
- HttpAuthFilter(DynamicItem<WebSession> webSession, AuthConfig authConfig) throws IOException {
+ HttpAuthFilter(
+ DynamicItem<WebSession> webSession,
+ AuthConfig authConfig,
+ ExternalIdKeyFactory externalIdKeyFactory)
+ throws IOException {
this.sessionProvider = webSession;
+ this.externalIdKeyFactory = externalIdKeyFactory;
final String pageName = "LoginRedirect.html";
final String doc = HtmlDomUtil.readFile(getClass(), pageName);
@@ -124,9 +131,9 @@
return false;
}
- private static boolean correctUser(String user, WebSession session) {
+ private boolean correctUser(String user, WebSession session) {
Optional<ExternalId.Key> id = session.getUser().getLastLoginExternalIdKey();
- return id.map(i -> i.equals(ExternalId.Key.create(SCHEME_GERRIT, user))).orElse(false);
+ return id.map(i -> i.equals(externalIdKeyFactory.create(SCHEME_GERRIT, user))).orElse(false);
}
String getRemoteUser(HttpServletRequest req) {
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java b/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
index 1b7e477..53f33b5 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
@@ -28,7 +28,7 @@
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.inject.Inject;
@@ -61,6 +61,8 @@
private final AccountManager accountManager;
private final HttpAuthFilter authFilter;
private final AuthConfig authConfig;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
HttpLoginServlet(
@@ -68,12 +70,16 @@
final CanonicalWebUrl urlProvider,
final AccountManager accountManager,
final HttpAuthFilter authFilter,
- final AuthConfig authConfig) {
+ final AuthConfig authConfig,
+ final ExternalIdKeyFactory externalIdKeyFactory,
+ final AuthRequest.Factory authRequestFactory) {
this.webSession = webSession;
this.urlProvider = urlProvider;
this.accountManager = accountManager;
this.authFilter = authFilter;
this.authConfig = authConfig;
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -109,7 +115,7 @@
return;
}
- final AuthRequest areq = AuthRequest.forUser(user);
+ final AuthRequest areq = authRequestFactory.createForUser(user);
areq.setDisplayName(authFilter.getRemoteDisplayname(req));
areq.setEmailAddress(authFilter.getRemoteEmail(req));
final AuthResult arsp;
@@ -154,7 +160,7 @@
throws AccountException, IOException, ConfigInvalidException {
accountManager.updateLink(
arsp.getAccountId(),
- new AuthRequest(ExternalId.Key.create(SCHEME_EXTERNAL, remoteAuthToken)));
+ authRequestFactory.create(externalIdKeyFactory.create(SCHEME_EXTERNAL, remoteAuthToken)));
}
private void replace(Document doc, String name, String value) {
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java b/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java
index 40807c0..820c7a2 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java
@@ -42,12 +42,16 @@
private final DynamicItem<WebSession> webSession;
private final AccountManager accountManager;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
HttpsClientSslCertAuthFilter(
- final DynamicItem<WebSession> webSession, AccountManager accountManager) {
+ final DynamicItem<WebSession> webSession,
+ AccountManager accountManager,
+ final AuthRequest.Factory authRequestFactory) {
this.webSession = webSession;
this.accountManager = accountManager;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -70,7 +74,7 @@
} else {
throw new ServletException("Couldn't extract username from your certificate");
}
- final AuthRequest areq = AuthRequest.forUser(userName);
+ final AuthRequest areq = authRequestFactory.createForUser(userName);
final AuthResult arsp;
try {
arsp = accountManager.authenticate(areq);
diff --git a/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java b/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
index a09866e..6caa760 100644
--- a/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
@@ -56,17 +56,20 @@
private final DynamicItem<WebSession> webSession;
private final CanonicalWebUrl urlProvider;
private final SiteHeaderFooter headers;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
LdapLoginServlet(
AccountManager accountManager,
DynamicItem<WebSession> webSession,
CanonicalWebUrl urlProvider,
- SiteHeaderFooter headers) {
+ SiteHeaderFooter headers,
+ AuthRequest.Factory authRequestFactory) {
this.accountManager = accountManager;
this.webSession = webSession;
this.urlProvider = urlProvider;
this.headers = headers;
+ this.authRequestFactory = authRequestFactory;
}
private void sendForm(
@@ -115,7 +118,7 @@
return;
}
- AuthRequest areq = AuthRequest.forUser(username);
+ AuthRequest areq = authRequestFactory.createForUser(username);
areq.setPassword(password);
AuthResult ares;
diff --git a/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java b/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
index 70ed79b..a3f8fbda 100644
--- a/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
+++ b/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
@@ -35,7 +35,7 @@
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.servlet.SessionScoped;
@@ -65,6 +65,8 @@
private Account.Id accountId;
private String redirectToken;
private boolean linkMode;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
OAuthSession(
@@ -72,13 +74,17 @@
Provider<IdentifiedUser> identifiedUser,
AccountManager accountManager,
CanonicalWebUrl urlProvider,
- OAuthTokenCache tokenCache) {
+ OAuthTokenCache tokenCache,
+ ExternalIdKeyFactory externalIdKeyFactory,
+ AuthRequest.Factory authRequestFactory) {
this.state = generateRandomState();
this.identifiedUser = identifiedUser;
this.webSession = webSession;
this.accountManager = accountManager;
this.urlProvider = urlProvider;
this.tokenCache = tokenCache;
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
boolean isLoggedIn() {
@@ -126,7 +132,7 @@
private void authenticateAndRedirect(
HttpServletRequest req, HttpServletResponse rsp, OAuthToken token) throws IOException {
- AuthRequest areq = new AuthRequest(ExternalId.Key.parse(user.getExternalId()));
+ AuthRequest areq = authRequestFactory.create(externalIdKeyFactory.parse(user.getExternalId()));
AuthResult arsp;
try {
String claimedIdentifier = user.getClaimedIdentity();
diff --git a/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java b/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
index b987c68..df0062c 100644
--- a/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
+++ b/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
@@ -32,8 +32,9 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
+import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.servlet.SessionScoped;
@@ -63,18 +64,24 @@
private OAuthUserInfo user;
private String redirectToken;
private boolean linkMode;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
OAuthSessionOverOpenID(
DynamicItem<WebSession> webSession,
Provider<IdentifiedUser> identifiedUser,
AccountManager accountManager,
- CanonicalWebUrl urlProvider) {
+ CanonicalWebUrl urlProvider,
+ ExternalIdKeyFactory externalIdKeyFactory,
+ AuthRequest.Factory authRequestFactory) {
this.state = generateRandomState();
this.webSession = webSession;
this.identifiedUser = identifiedUser;
this.accountManager = accountManager;
this.urlProvider = urlProvider;
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
boolean isLoggedIn() {
@@ -117,8 +124,7 @@
private void authenticateAndRedirect(HttpServletRequest req, HttpServletResponse rsp)
throws IOException {
com.google.gerrit.server.account.AuthRequest areq =
- new com.google.gerrit.server.account.AuthRequest(
- ExternalId.Key.parse(user.getExternalId()));
+ authRequestFactory.create(externalIdKeyFactory.parse(user.getExternalId()));
AuthResult arsp;
try {
String claimedIdentifier = user.getClaimedIdentity();
diff --git a/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java b/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
index b685011..cf3562f 100644
--- a/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
+++ b/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
@@ -28,7 +28,7 @@
import com.google.gerrit.server.UrlEncoded;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.auth.openid.OpenIdProviderPattern;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.ConfigUtil;
@@ -92,6 +92,8 @@
private final ConsumerManager manager;
private final List<OpenIdProviderPattern> allowedOpenIDs;
private final List<String> openIdDomains;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final com.google.gerrit.server.account.AuthRequest.Factory authRequestFactory;
/** Maximum age, in seconds, before forcing re-authentication of account. */
private final int papeMaxAuthAge;
@@ -104,7 +106,9 @@
@GerritServerConfig Config config,
AuthConfig ac,
AccountManager am,
- ProxyProperties proxyProperties) {
+ ProxyProperties proxyProperties,
+ ExternalIdKeyFactory externalIdKeyFactory,
+ com.google.gerrit.server.account.AuthRequest.Factory authRequestFactory) {
if (proxyProperties.getProxyUrl() != null) {
final org.openid4java.util.ProxyProperties proxy = new org.openid4java.util.ProxyProperties();
@@ -132,6 +136,8 @@
"maxOpenIdSessionAge",
-1,
TimeUnit.SECONDS);
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
@SuppressWarnings("unchecked")
@@ -310,7 +316,7 @@
}
final com.google.gerrit.server.account.AuthRequest areq =
- new com.google.gerrit.server.account.AuthRequest(ExternalId.Key.parse(openidIdentifier));
+ authRequestFactory.create(externalIdKeyFactory.parse(openidIdentifier));
if (sregRsp != null) {
areq.setDisplayName(sregRsp.getAttributeValue("fullname"));
@@ -388,8 +394,7 @@
// was missing due to a bug in Gerrit. Link the claimed.
//
final com.google.gerrit.server.account.AuthRequest linkReq =
- new com.google.gerrit.server.account.AuthRequest(
- ExternalId.Key.parse(claimedIdentifier));
+ authRequestFactory.create(externalIdKeyFactory.parse(claimedIdentifier));
linkReq.setDisplayName(areq.getDisplayName());
linkReq.setEmailAddress(areq.getEmailAddress());
accountManager.link(actualId.get(), linkReq);
@@ -425,8 +430,7 @@
webSession.get().login(arsp, remember);
if (arsp.isNew() && claimedIdentifier != null) {
final com.google.gerrit.server.account.AuthRequest linkReq =
- new com.google.gerrit.server.account.AuthRequest(
- ExternalId.Key.parse(claimedIdentifier));
+ authRequestFactory.create(externalIdKeyFactory.parse(claimedIdentifier));
linkReq.setDisplayName(areq.getDisplayName());
linkReq.setEmailAddress(areq.getEmailAddress());
accountManager.link(arsp.getAccountId(), linkReq);
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 1fa8de7..3c39ea1 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -1817,6 +1817,10 @@
logger.atFinest().log(
"Received REST request: %s %s (parameters: %s)",
req.getMethod(), req.getRequestURI(), getParameterNames(req));
+ Optional.ofNullable(req.getHeader(X_GERRIT_DEADLINE))
+ .ifPresent(
+ clientProvidedDeadline ->
+ logger.atFine().log("%s = %s", X_GERRIT_DEADLINE, clientProvidedDeadline));
logger.atFinest().log("Calling user: %s", globals.currentUser.get().getLoggableName());
logger.atFinest().log(
"Groups: %s", lazy(() -> globals.currentUser.get().getEffectiveGroups().getKnownGroups()));
diff --git a/java/com/google/gerrit/pgm/ChangeExternalIdCaseSensitivity.java b/java/com/google/gerrit/pgm/ChangeExternalIdCaseSensitivity.java
new file mode 100644
index 0000000..fbc6065
--- /dev/null
+++ b/java/com/google/gerrit/pgm/ChangeExternalIdCaseSensitivity.java
@@ -0,0 +1,194 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.gerrit.pgm;
+
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.exceptions.DuplicateKeyException;
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.lifecycle.LifecycleManager;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.util.SiteProgram;
+import com.google.gerrit.server.account.externalids.DisabledExternalIdCache;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdNotes;
+import com.google.gerrit.server.account.externalids.ExternalIdUpsertPreprocessor;
+import com.google.gerrit.server.account.externalids.ExternalIds;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
+import com.google.gerrit.server.schema.NoteDbSchemaVersionCheck;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import java.io.IOException;
+import java.util.Collection;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.kohsuke.args4j.Option;
+
+/**
+ * Changes the case sensitivity of `username:` and `gerrit:` external IDs by recomputing the SHA-1
+ * sums used as note names.
+ */
+public class ChangeExternalIdCaseSensitivity extends SiteProgram {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ @Option(name = "--batch", usage = "Don't ask for confirmation before migrating.")
+ private boolean batch;
+
+ @Option(name = "--dryrun", usage = "Do a dryrun of the migration.")
+ private boolean dryrun;
+
+ private final LifecycleManager manager = new LifecycleManager();
+ private final TextProgressMonitor monitor = new TextProgressMonitor();
+
+ private Config globalConfig;
+ private boolean isUserNameCaseInsensitive;
+ private ConsoleUI ui;
+
+ @Inject private GitRepositoryManager repoManager;
+ @Inject private AllUsersName allUsersName;
+ @Inject private Provider<MetaDataUpdate.Server> metaDataUpdateServerFactory;
+ @Inject private ExternalIdNotes.FactoryNoReindex externalIdNotesFactory;
+ @Inject private ExternalIds externalIds;
+ @Inject private ExternalIdFactory externalIdFactory;
+
+ @Override
+ public int run() throws Exception {
+ mustHaveValidSite();
+ ui = ConsoleUI.getInstance(batch);
+
+ Injector dbInjector = createDbInjector();
+ manager.add(dbInjector, dbInjector.createChildInjector(NoteDbSchemaVersionCheck.module()));
+ dbInjector
+ .createChildInjector(
+ new FactoryModule() {
+ @Override
+ protected void configure() {
+ bind(GitReferenceUpdated.class).toInstance(GitReferenceUpdated.DISABLED);
+ factory(MetaDataUpdate.InternalFactory.class);
+ DynamicMap.mapOf(binder(), ExternalIdUpsertPreprocessor.class);
+
+ // The ChangeExternalIdCaseSensitivity program needs to access all external IDs only
+ // once to update them. After the update they are not accessed again. Hence the
+ // LocalUsernamesToLowerCase program doesn't benefit from caching external IDs and
+ // the external ID cache can be disabled.
+ install(DisabledExternalIdCache.module());
+ }
+ })
+ .injectMembers(this);
+ globalConfig = dbInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
+
+ this.isUserNameCaseInsensitive =
+ globalConfig.getBoolean("auth", "userNameCaseInsensitive", false);
+
+ String message =
+ "auth.userNameCaseInsensitive is set to %b. "
+ + "External IDs will be migrated to be case %ssensitive. Continue?";
+ if (!ui.yesno(
+ true, message, isUserNameCaseInsensitive, isUserNameCaseInsensitive ? "" : "in")) {
+ return 0;
+ }
+
+ Collection<ExternalId> todo = externalIds.all();
+ monitor.beginTask("Converting external ID note names", todo.size());
+
+ manager.start();
+ try {
+ try (Repository repo = repoManager.openRepository(allUsersName)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(repo);
+ for (ExternalId extId : todo) {
+ recomputeExternalIdNoteId(extIdNotes, extId);
+ monitor.update(1);
+ }
+ if (!dryrun) {
+ try (MetaDataUpdate metaDataUpdate =
+ metaDataUpdateServerFactory.get().create(allUsersName)) {
+ metaDataUpdate.setMessage(
+ String.format(
+ "Migration to case %ssensitive usernames",
+ isUserNameCaseInsensitive ? "" : "in"));
+ extIdNotes.commit(metaDataUpdate);
+ }
+ }
+ }
+ } finally {
+ manager.stop();
+ monitor.endTask();
+ }
+
+ int exitCode;
+ if (!dryrun) {
+ updateGerritConfig();
+
+ exitCode = reindexAccounts();
+ } else {
+ exitCode = 0;
+ }
+ return exitCode;
+ }
+
+ private void recomputeExternalIdNoteId(ExternalIdNotes extIdNotes, ExternalId extId)
+ throws DuplicateKeyException, IOException {
+ if (extId.isScheme(SCHEME_GERRIT) || extId.isScheme(SCHEME_USERNAME)) {
+ ExternalId.Key updatedKey =
+ ExternalId.Key.create(extId.key().scheme(), extId.key().id(), !isUserNameCaseInsensitive);
+ if (!extId.key().sha1().getName().equals(updatedKey.sha1().getName())) {
+ logger.atInfo().log("Converting note name of external ID: %s", extId.key());
+ ExternalId updatedExtId =
+ externalIdFactory.create(
+ updatedKey, extId.accountId(), extId.email(), extId.password(), extId.blobId());
+ extIdNotes.replace(extId, updatedExtId);
+ }
+ }
+ }
+
+ private void updateGerritConfig() throws IOException, ConfigInvalidException {
+ logger.atInfo().log("Setting auth.userNameCaseInsensitive to true in gerrit.config.");
+ FileBasedConfig config =
+ new FileBasedConfig(
+ globalConfig, getSitePath().resolve("etc/gerrit.config").toFile(), FS.DETECTED);
+ config.load();
+ config.setBoolean("auth", null, "userNameCaseInsensitive", !isUserNameCaseInsensitive);
+ config.save();
+ }
+
+ private int reindexAccounts() throws Exception {
+ monitor.beginTask("Reindex accounts", ProgressMonitor.UNKNOWN);
+ String[] reindexArgs = {
+ "--site-path", getSitePath().toString(), "--index", AccountSchemaDefinitions.NAME
+ };
+ logger.atInfo().log(
+ "Migration complete, reindexing accounts with: reindex %s", String.join(" ", reindexArgs));
+ Reindex reindexPgm = new Reindex();
+ int exitCode = reindexPgm.main(reindexArgs);
+ monitor.endTask();
+ return exitCode;
+ }
+}
diff --git a/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java b/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
index 8e2f70f..f651994 100644
--- a/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
+++ b/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
@@ -22,6 +22,7 @@
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.server.account.externalids.DisabledExternalIdCache;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllUsersName;
@@ -52,6 +53,7 @@
@Inject private AllUsersName allUsersName;
@Inject private Provider<MetaDataUpdate.Server> metaDataUpdateServerFactory;
@Inject private ExternalIdNotes.FactoryNoReindex externalIdNotesFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
@Inject private ExternalIds externalIds;
@Override
@@ -105,7 +107,7 @@
String localUserLowerCase = localUser.toLowerCase(Locale.US);
if (!localUser.equals(localUserLowerCase)) {
ExternalId extIdLowerCase =
- ExternalId.create(
+ externalIdFactory.create(
SCHEME_GERRIT,
localUserLowerCase,
extId.accountId(),
diff --git a/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java b/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java
index 9519653..e2a1f04 100644
--- a/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java
+++ b/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java
@@ -18,6 +18,7 @@
import com.google.gerrit.pgm.init.api.InitFlags;
import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.SitePaths;
@@ -39,12 +40,18 @@
private final InitFlags flags;
private final SitePaths site;
private final AllUsersName allUsers;
+ private final ExternalIdFactory externalIdFactory;
@Inject
- public ExternalIdsOnInit(InitFlags flags, SitePaths site, AllUsersNameOnInitProvider allUsers) {
+ public ExternalIdsOnInit(
+ InitFlags flags,
+ SitePaths site,
+ AllUsersNameOnInitProvider allUsers,
+ ExternalIdFactory externalIdFactory) {
this.flags = flags;
this.site = site;
this.allUsers = new AllUsersName(allUsers.get());
+ this.externalIdFactory = externalIdFactory;
}
public synchronized void insert(String commitMessage, Collection<ExternalId> extIds)
@@ -52,7 +59,8 @@
File path = getPath();
if (path != null) {
try (Repository allUsersRepo = new FileRepository(path)) {
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, allUsersRepo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(allUsers, allUsersRepo, externalIdFactory);
extIdNotes.insert(extIds);
try (MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, allUsers, allUsersRepo)) {
diff --git a/java/com/google/gerrit/pgm/init/InitAdminUser.java b/java/com/google/gerrit/pgm/init/InitAdminUser.java
index 2e32066..d6a0133 100644
--- a/java/com/google/gerrit/pgm/init/InitAdminUser.java
+++ b/java/com/google/gerrit/pgm/init/InitAdminUser.java
@@ -29,6 +29,7 @@
import com.google.gerrit.server.account.AccountSshKey;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.index.account.AccountIndex;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.index.group.GroupIndex;
@@ -52,6 +53,7 @@
private final ExternalIdsOnInit externalIds;
private final SequencesOnInit sequencesOnInit;
private final GroupsOnInit groupsOnInit;
+ private final ExternalIdFactory externalIdFactory;
private AccountIndexCollection accountIndexCollection;
private GroupIndexCollection groupIndexCollection;
@@ -63,7 +65,8 @@
VersionedAuthorizedKeysOnInit.Factory authorizedKeysFactory,
ExternalIdsOnInit externalIds,
SequencesOnInit sequencesOnInit,
- GroupsOnInit groupsOnInit) {
+ GroupsOnInit groupsOnInit,
+ ExternalIdFactory externalIdFactory) {
this.flags = flags;
this.ui = ui;
this.accounts = accounts;
@@ -71,6 +74,7 @@
this.externalIds = externalIds;
this.sequencesOnInit = sequencesOnInit;
this.groupsOnInit = groupsOnInit;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -107,10 +111,10 @@
String email = readEmail(sshKey);
List<ExternalId> extIds = new ArrayList<>(2);
- extIds.add(ExternalId.createUsername(username, id, httpPassword));
+ extIds.add(externalIdFactory.createUsername(username, id, httpPassword));
if (email != null) {
- extIds.add(ExternalId.createEmail(id, email));
+ extIds.add(externalIdFactory.createEmail(id, email));
}
externalIds.insert("Add external IDs for initial admin user", extIds);
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index 09ddcc8..188f30b 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -39,7 +39,7 @@
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
-import com.google.gerrit.server.account.externalids.ExternalIdModule;
+import com.google.gerrit.server.account.externalids.ExternalIdCacheModule;
import com.google.gerrit.server.approval.ApprovalCacheImpl;
import com.google.gerrit.server.cache.CacheRemovalListener;
import com.google.gerrit.server.cache.h2.H2CacheModule;
@@ -172,7 +172,7 @@
modules.add(new DefaultPermissionBackendModule());
modules.add(new DefaultMemoryCacheModule());
modules.add(new H2CacheModule());
- modules.add(new ExternalIdModule());
+ modules.add(new ExternalIdCacheModule());
modules.add(new GroupModule());
modules.add(new NoteDbModule());
modules.add(AccountCacheImpl.module());
diff --git a/java/com/google/gerrit/server/DeadlineChecker.java b/java/com/google/gerrit/server/DeadlineChecker.java
index 9ef5c4c..5662e50 100644
--- a/java/com/google/gerrit/server/DeadlineChecker.java
+++ b/java/com/google/gerrit/server/DeadlineChecker.java
@@ -170,6 +170,26 @@
Optional<ServerDeadline> serverSideDeadline =
getServerSideDeadline(deadlineConfigs, requestInfo);
Optional<Long> clientedProvidedTimeout = parseTimeout(clientProvidedTimeoutValue);
+ logDeadlines(serverSideDeadline, clientedProvidedTimeout);
+
+ this.cancellationReason =
+ clientedProvidedTimeout.isPresent()
+ ? RequestStateProvider.Reason.CLIENT_PROVIDED_DEADLINE_EXCEEDED
+ : RequestStateProvider.Reason.SERVER_DEADLINE_EXCEEDED;
+ this.timeoutName =
+ clientedProvidedTimeout
+ .map(clientTimeout -> "client.timeout")
+ .orElse(
+ serverSideDeadline
+ .map(serverDeadline -> serverDeadline.id() + ".timeout")
+ .orElse("timeout"));
+ this.timeout =
+ clientedProvidedTimeout.orElse(serverSideDeadline.map(ServerDeadline::timeout).orElse(0L));
+ this.deadline = timeout > 0 ? Optional.of(start + timeout) : Optional.empty();
+ }
+
+ private void logDeadlines(
+ Optional<ServerDeadline> serverSideDeadline, Optional<Long> clientedProvidedTimeout) {
if (serverSideDeadline.isPresent()) {
if (clientedProvidedTimeout.isPresent()) {
logger.atFine().log(
@@ -185,21 +205,11 @@
TimeUnit.MILLISECONDS.convert(
serverSideDeadline.get().timeout(), TimeUnit.NANOSECONDS));
}
+ } else if (clientedProvidedTimeout.isPresent()) {
+ logger.atFine().log(
+ "applying client provided deadline (timeout = %sms)",
+ TimeUnit.MILLISECONDS.convert(clientedProvidedTimeout.get(), TimeUnit.NANOSECONDS));
}
- this.cancellationReason =
- clientedProvidedTimeout.isPresent()
- ? RequestStateProvider.Reason.CLIENT_PROVIDED_DEADLINE_EXCEEDED
- : RequestStateProvider.Reason.SERVER_DEADLINE_EXCEEDED;
- this.timeoutName =
- clientedProvidedTimeout
- .map(clientTimeout -> "client.timeout")
- .orElse(
- serverSideDeadline
- .map(serverDeadline -> serverDeadline.id() + ".timeout")
- .orElse("timeout"));
- this.timeout =
- clientedProvidedTimeout.orElse(serverSideDeadline.map(ServerDeadline::timeout).orElse(0L));
- this.deadline = timeout > 0 ? Optional.of(start + timeout) : Optional.empty();
}
private Optional<ServerDeadline> getServerSideDeadline(
diff --git a/java/com/google/gerrit/server/account/AccountCacheImpl.java b/java/com/google/gerrit/server/account/AccountCacheImpl.java
index defa4c7..093af68 100644
--- a/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -24,7 +24,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.AllUsersName;
@@ -76,6 +76,7 @@
private final GitRepositoryManager repoManager;
private final AllUsersName allUsersName;
private final DefaultPreferencesCache defaultPreferenceCache;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
AccountCacheImpl(
@@ -84,12 +85,14 @@
LoadingCache<CachedAccountDetails.Key, CachedAccountDetails> accountDetailsCache,
GitRepositoryManager repoManager,
AllUsersName allUsersName,
- DefaultPreferencesCache defaultPreferenceCache) {
+ DefaultPreferencesCache defaultPreferenceCache,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.externalIds = externalIds;
this.accountDetailsCache = accountDetailsCache;
this.repoManager = repoManager;
this.allUsersName = allUsersName;
this.defaultPreferenceCache = defaultPreferenceCache;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -140,7 +143,7 @@
public Optional<AccountState> getByUsername(String username) {
try {
return externalIds
- .get(ExternalId.Key.create(SCHEME_USERNAME, username))
+ .get(externalIdKeyFactory.create(SCHEME_USERNAME, username))
.map(e -> get(e.accountId()))
.orElseGet(Optional::empty);
} catch (IOException e) {
diff --git a/java/com/google/gerrit/server/account/AccountManager.java b/java/com/google/gerrit/server/account/AccountManager.java
index 5a89a862..987e7e3 100644
--- a/java/com/google/gerrit/server/account/AccountManager.java
+++ b/java/com/google/gerrit/server/account/AccountManager.java
@@ -36,6 +36,8 @@
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.auth.NoSuchUserException;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -77,6 +79,8 @@
private final GroupsUpdate.Factory groupsUpdateFactory;
private final boolean autoUpdateAccountActiveStatus;
private final SetInactiveFlag setInactiveFlag;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@VisibleForTesting
@Inject
@@ -92,7 +96,9 @@
ProjectCache projectCache,
ExternalIds externalIds,
GroupsUpdate.Factory groupsUpdateFactory,
- SetInactiveFlag setInactiveFlag) {
+ SetInactiveFlag setInactiveFlag,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.sequences = sequences;
this.accounts = accounts;
this.accountsUpdateProvider = accountsUpdateProvider;
@@ -108,12 +114,14 @@
this.autoUpdateAccountActiveStatus =
cfg.getBoolean("auth", "autoUpdateAccountActiveStatus", false);
this.setInactiveFlag = setInactiveFlag;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
/** @return user identified by this external identity string */
public Optional<Account.Id> lookup(String externalId) throws AccountException {
try {
- return externalIds.get(ExternalId.Key.parse(externalId)).map(ExternalId::accountId);
+ return externalIds.get(externalIdKeyFactory.parse(externalId)).map(ExternalId::accountId);
} catch (IOException e) {
throw new AccountException("Cannot lookup account " + externalId, e);
}
@@ -229,7 +237,7 @@
String oldEmail = extId.email();
if (newEmail != null && !newEmail.equals(oldEmail)) {
ExternalId extIdWithNewEmail =
- ExternalId.create(extId.key(), extId.accountId(), newEmail, extId.password());
+ externalIdFactory.create(extId.key(), extId.accountId(), newEmail, extId.password());
checkEmailNotUsed(extId.accountId(), extIdWithNewEmail);
accountUpdates.add(u -> u.replaceExternalId(extId, extIdWithNewEmail));
@@ -273,7 +281,7 @@
logger.atFine().log("Assigning new Id %s to account", newId);
ExternalId extId =
- ExternalId.createWithEmail(who.getExternalIdKey(), newId, who.getEmailAddress());
+ externalIdFactory.createWithEmail(who.getExternalIdKey(), newId, who.getEmailAddress());
logger.atFine().log("Created external Id: %s", extId);
checkEmailNotUsed(newId, extId);
ExternalId userNameExtId =
@@ -348,7 +356,7 @@
"Cannot assign user name \"%s\" to account %s; name does not conform.",
username, accountId));
}
- return ExternalId.create(SCHEME_USERNAME, username, accountId);
+ return externalIdFactory.create(SCHEME_USERNAME, username, accountId);
}
private void checkEmailNotUsed(Account.Id accountId, ExternalId extIdToBeCreated)
@@ -414,7 +422,7 @@
update(who, extId);
} else {
ExternalId newExtId =
- ExternalId.createWithEmail(who.getExternalIdKey(), to, who.getEmailAddress());
+ externalIdFactory.createWithEmail(who.getExternalIdKey(), to, who.getEmailAddress());
checkEmailNotUsed(to, newExtId);
accountsUpdateProvider
.get()
diff --git a/java/com/google/gerrit/server/account/AccountModule.java b/java/com/google/gerrit/server/account/AccountModule.java
new file mode 100644
index 0000000..c1305cf
--- /dev/null
+++ b/java/com/google/gerrit/server/account/AccountModule.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.gerrit.server.account;
+
+import com.google.inject.AbstractModule;
+
+public class AccountModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(AuthRequest.Factory.class);
+ }
+}
diff --git a/java/com/google/gerrit/server/account/AuthRequest.java b/java/com/google/gerrit/server/account/AuthRequest.java
index ddb54a6..50ed532 100644
--- a/java/com/google/gerrit/server/account/AuthRequest.java
+++ b/java/com/google/gerrit/server/account/AuthRequest.java
@@ -21,6 +21,9 @@
import com.google.common.base.Strings;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
import java.util.Optional;
/**
@@ -32,31 +35,52 @@
* not all OpenID providers return them, and not all non-OpenID systems can use them.
*/
public class AuthRequest {
- /** Create a request for a local username, such as from LDAP. */
- public static AuthRequest forUser(String username) {
- AuthRequest r = new AuthRequest(ExternalId.Key.create(SCHEME_GERRIT, username));
- r.setUserName(username);
- return r;
+ @Singleton
+ public static class Factory {
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject
+ public Factory(ExternalIdKeyFactory externalIdKeyFactory) {
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ }
+
+ public AuthRequest create(ExternalId.Key externalIdKey) {
+ return new AuthRequest(externalIdKey, externalIdKeyFactory);
+ }
+
+ /** Create a request for a local username, such as from LDAP. */
+ public AuthRequest createForUser(String username) {
+ AuthRequest r =
+ new AuthRequest(
+ externalIdKeyFactory.create(SCHEME_GERRIT, username), externalIdKeyFactory);
+ r.setUserName(username);
+ return r;
+ }
+
+ /** Create a request for an external username. */
+ public AuthRequest createForExternalUser(String username) {
+ AuthRequest r =
+ new AuthRequest(
+ externalIdKeyFactory.create(SCHEME_EXTERNAL, username), externalIdKeyFactory);
+ r.setUserName(username);
+ return r;
+ }
+
+ /**
+ * Create a request for an email address registration.
+ *
+ * <p>This type of request should be used only to attach a new email address to an existing user
+ * account.
+ */
+ public AuthRequest createForEmail(String email) {
+ AuthRequest r =
+ new AuthRequest(externalIdKeyFactory.create(SCHEME_MAILTO, email), externalIdKeyFactory);
+ r.setEmailAddress(email);
+ return r;
+ }
}
- /** Create a request for an external username. */
- public static AuthRequest forExternalUser(String username) {
- AuthRequest r = new AuthRequest(ExternalId.Key.create(SCHEME_EXTERNAL, username));
- r.setUserName(username);
- return r;
- }
-
- /**
- * Create a request for an email address registration.
- *
- * <p>This type of request should be used only to attach a new email address to an existing user
- * account.
- */
- public static AuthRequest forEmail(String email) {
- AuthRequest r = new AuthRequest(ExternalId.Key.create(SCHEME_MAILTO, email));
- r.setEmailAddress(email);
- return r;
- }
+ private final ExternalIdKeyFactory externalIdKeyFactory;
private ExternalId.Key externalId;
private String password;
@@ -69,8 +93,9 @@
private boolean authProvidesAccountActiveStatus;
private boolean active;
- public AuthRequest(ExternalId.Key externalId) {
+ private AuthRequest(ExternalId.Key externalId, ExternalIdKeyFactory externalIdKeyFactory) {
this.externalId = externalId;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
public ExternalId.Key getExternalIdKey() {
@@ -86,7 +111,7 @@
public void setLocalUser(String localUser) {
if (externalId.isScheme(SCHEME_GERRIT)) {
- externalId = ExternalId.Key.create(SCHEME_GERRIT, localUser);
+ externalId = externalIdKeyFactory.create(SCHEME_GERRIT, localUser);
}
}
diff --git a/java/com/google/gerrit/server/account/externalids/AllExternalIds.java b/java/com/google/gerrit/server/account/externalids/AllExternalIds.java
index f1fc5cb..e718bcb 100644
--- a/java/com/google/gerrit/server/account/externalids/AllExternalIds.java
+++ b/java/com/google/gerrit/server/account/externalids/AllExternalIds.java
@@ -68,7 +68,8 @@
ExternalIdProto.Builder b =
ExternalIdProto.newBuilder()
.setKey(externalId.key().get())
- .setAccountId(externalId.accountId().get());
+ .setAccountId(externalId.accountId().get())
+ .setIsCaseInsensitive(externalId.isCaseInsensitive());
if (externalId.email() != null) {
b.setEmail(externalId.email());
}
@@ -91,7 +92,7 @@
private static ExternalId toExternalId(ObjectIdConverter idConverter, ExternalIdProto proto) {
return ExternalId.create(
- ExternalId.Key.parse(proto.getKey()),
+ ExternalId.Key.parse(proto.getKey(), proto.getIsCaseInsensitive()),
Account.id(proto.getAccountId()),
// ExternalId treats null and empty strings the same, so no need to distinguish here.
proto.getEmail(),
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalId.java b/java/com/google/gerrit/server/account/externalids/ExternalId.java
index 268812c..bbee1b2 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalId.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalId.java
@@ -17,35 +17,28 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Objects.requireNonNull;
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.flogger.FluentLogger;
import com.google.common.hash.Hashing;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.client.AuthType;
import com.google.gerrit.git.ObjectIds;
-import com.google.gerrit.server.account.HashedPassword;
import java.io.Serializable;
import java.util.Collection;
+import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
@AutoValue
public abstract class ExternalId implements Serializable {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
// If these regular expressions are modified the same modifications should be done to the
// corresponding regular expressions in the
// com.google.gerrit.client.account.UsernameField class.
@@ -106,10 +99,10 @@
private static final long serialVersionUID = 1L;
- private static final String EXTERNAL_ID_SECTION = "externalId";
- private static final String ACCOUNT_ID_KEY = "accountId";
- private static final String EMAIL_KEY = "email";
- private static final String PASSWORD_KEY = "password";
+ static final String EXTERNAL_ID_SECTION = "externalId";
+ static final String ACCOUNT_ID_KEY = "accountId";
+ static final String EMAIL_KEY = "email";
+ static final String PASSWORD_KEY = "password";
/**
* Scheme used for {@link AuthType#LDAP}, {@link AuthType#CLIENT_SSL_CERT_LDAP}, {@link
@@ -118,6 +111,8 @@
* <p>The name {@code gerrit:} was a very poor choice.
*
* <p>Scheme names must not contain colons (':').
+ *
+ * <p>Will be handled case insensitive, if auth.userNameCaseInsensitive = true.
*/
public static final String SCHEME_GERRIT = "gerrit";
@@ -127,7 +122,11 @@
/** Scheme used to represent only an email address. */
public static final String SCHEME_MAILTO = "mailto";
- /** Scheme for the username used to authenticate an account, e.g. over SSH. */
+ /**
+ * Scheme for the username used to authenticate an account, e.g. over SSH.
+ *
+ * <p>Will be handled case insensitive, if auth.userNameCaseInsensitive = true.
+ */
public static final String SCHEME_USERNAME = "username";
/** Scheme used for GPG public keys. */
@@ -154,10 +153,12 @@
*
* @param scheme the scheme name, must not contain colons (':'), can be {@code null}
* @param id the external ID, must not contain colons (':')
+ * @param isCaseInsensitive whether the external ID key is matched case insensitively
* @return the created external ID key
*/
- public static Key create(@Nullable String scheme, String id) {
- return new AutoValue_ExternalId_Key(Strings.emptyToNull(scheme), id);
+ @VisibleForTesting
+ public static Key create(@Nullable String scheme, String id, boolean isCaseInsensitive) {
+ return new AutoValue_ExternalId_Key(Strings.emptyToNull(scheme), id, isCaseInsensitive);
}
/**
@@ -165,18 +166,21 @@
*
* @return the parsed external ID key
*/
- public static Key parse(String externalId) {
+ @VisibleForTesting
+ public static Key parse(String externalId, boolean isCaseInsensitive) {
int c = externalId.indexOf(':');
if (c < 1 || c >= externalId.length() - 1) {
- return create(null, externalId);
+ return create(null, externalId, isCaseInsensitive);
}
- return create(externalId.substring(0, c), externalId.substring(c + 1));
+ return create(externalId.substring(0, c), externalId.substring(c + 1), isCaseInsensitive);
}
public abstract @Nullable String scheme();
public abstract String id();
+ public abstract boolean isCaseInsensitive();
+
public boolean isScheme(String scheme) {
return scheme.equals(scheme());
}
@@ -187,7 +191,8 @@
*/
@SuppressWarnings("deprecation") // Use Hashing.sha1 for compatibility.
public ObjectId sha1() {
- return ObjectId.fromRaw(Hashing.sha1().hashString(get(), UTF_8).asBytes());
+ String keyString = isCaseInsensitive() ? get().toLowerCase(Locale.US) : get();
+ return ObjectId.fromRaw(Hashing.sha1().hashString(keyString, UTF_8).asBytes());
}
/**
@@ -209,100 +214,26 @@
return get();
}
+ @Override
+ public final boolean equals(Object obj) {
+ if (!(obj instanceof ExternalId.Key)) {
+ return false;
+ }
+ ExternalId.Key o = (ExternalId.Key) obj;
+
+ return sha1().equals(o.sha1());
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(sha1());
+ }
+
public static ImmutableSet<ExternalId.Key> from(Collection<ExternalId> extIds) {
return extIds.stream().map(ExternalId::key).collect(toImmutableSet());
}
}
- /**
- * Creates an external ID.
- *
- * @param scheme the scheme name, must not contain colons (':')
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @return the created external ID
- */
- public static ExternalId create(String scheme, String id, Account.Id accountId) {
- return create(Key.create(scheme, id), accountId, null, null);
- }
-
- /**
- * Creates an external ID.
- *
- * @param scheme the scheme name, must not contain colons (':')
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @param email the email of the external ID, may be {@code null}
- * @param hashedPassword the hashed password of the external ID, may be {@code null}
- * @return the created external ID
- */
- public static ExternalId create(
- String scheme,
- String id,
- Account.Id accountId,
- @Nullable String email,
- @Nullable String hashedPassword) {
- return create(Key.create(scheme, id), accountId, email, hashedPassword);
- }
-
- public static ExternalId create(Key key, Account.Id accountId) {
- return create(key, accountId, null, null);
- }
-
- public static ExternalId create(
- Key key, Account.Id accountId, @Nullable String email, @Nullable String hashedPassword) {
- return create(
- key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), null);
- }
-
- public static ExternalId createWithPassword(
- Key key, Account.Id accountId, @Nullable String email, @Nullable String plainPassword) {
- plainPassword = Strings.emptyToNull(plainPassword);
- String hashedPassword =
- plainPassword != null ? HashedPassword.fromPassword(plainPassword).encode() : null;
- return create(key, accountId, email, hashedPassword);
- }
-
- /**
- * Create a external ID for a username (scheme "username").
- *
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @param plainPassword the plain HTTP password, may be {@code null}
- * @return the created external ID
- */
- public static ExternalId createUsername(
- String id, Account.Id accountId, @Nullable String plainPassword) {
- return createWithPassword(Key.create(SCHEME_USERNAME, id), accountId, null, plainPassword);
- }
-
- /**
- * Creates an external ID with an email.
- *
- * @param scheme the scheme name, must not contain colons (':')
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @param email the email of the external ID, may be {@code null}
- * @return the created external ID
- */
- public static ExternalId createWithEmail(
- String scheme, String id, Account.Id accountId, @Nullable String email) {
- return createWithEmail(Key.create(scheme, id), accountId, email);
- }
-
- public static ExternalId createWithEmail(Key key, Account.Id accountId, @Nullable String email) {
- return create(key, accountId, Strings.emptyToNull(email), null);
- }
-
- public static ExternalId createEmail(Account.Id accountId, String email) {
- return createWithEmail(SCHEME_MAILTO, email, accountId, requireNonNull(email));
- }
-
- static ExternalId create(ExternalId extId, @Nullable ObjectId blobId) {
- return new AutoValue_ExternalId(
- extId.key(), extId.accountId(), extId.email(), extId.password(), blobId);
- }
-
@VisibleForTesting
public static ExternalId create(
Key key,
@@ -311,111 +242,20 @@
@Nullable String hashedPassword,
@Nullable ObjectId blobId) {
return new AutoValue_ExternalId(
- key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), blobId);
- }
-
- /**
- * Parses an external ID from a byte array that contain the external ID as an Git config file
- * text.
- *
- * <p>The Git config must have exactly one externalId subsection with an accountId and optionally
- * email and password:
- *
- * <pre>
- * [externalId "username:jdoe"]
- * accountId = 1003407
- * email = jdoe@example.com
- * password = bcrypt:4:LCbmSBDivK/hhGVQMfkDpA==:XcWn0pKYSVU/UJgOvhidkEtmqCp6oKB7
- * </pre>
- */
- public static ExternalId parse(String noteId, byte[] raw, ObjectId blobId)
- throws ConfigInvalidException {
- requireNonNull(blobId);
-
- Config externalIdConfig = new Config();
- try {
- externalIdConfig.fromText(new String(raw, UTF_8));
- } catch (ConfigInvalidException e) {
- throw invalidConfig(noteId, e.getMessage());
- }
-
- Set<String> externalIdKeys = externalIdConfig.getSubsections(EXTERNAL_ID_SECTION);
- if (externalIdKeys.size() != 1) {
- throw invalidConfig(
- noteId,
- String.format(
- "Expected exactly 1 '%s' section, found %d",
- EXTERNAL_ID_SECTION, externalIdKeys.size()));
- }
-
- String externalIdKeyStr = Iterables.getOnlyElement(externalIdKeys);
- Key externalIdKey = Key.parse(externalIdKeyStr);
- if (externalIdKey == null) {
- throw invalidConfig(noteId, String.format("External ID %s is invalid", externalIdKeyStr));
- }
-
- if (!externalIdKey.sha1().getName().equals(noteId)) {
- throw invalidConfig(
- noteId,
- String.format(
- "SHA1 of external ID '%s' does not match note ID '%s'", externalIdKeyStr, noteId));
- }
-
- String email = externalIdConfig.getString(EXTERNAL_ID_SECTION, externalIdKeyStr, EMAIL_KEY);
- String password =
- externalIdConfig.getString(EXTERNAL_ID_SECTION, externalIdKeyStr, PASSWORD_KEY);
- int accountId = readAccountId(noteId, externalIdConfig, externalIdKeyStr);
-
- return create(
- externalIdKey,
- Account.id(accountId),
+ key,
+ accountId,
+ key.isCaseInsensitive(),
Strings.emptyToNull(email),
- Strings.emptyToNull(password),
+ Strings.emptyToNull(hashedPassword),
blobId);
}
- private static int readAccountId(String noteId, Config externalIdConfig, String externalIdKeyStr)
- throws ConfigInvalidException {
- String accountIdStr =
- externalIdConfig.getString(EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY);
- if (accountIdStr == null) {
- throw invalidConfig(
- noteId,
- String.format(
- "Value for '%s.%s.%s' is missing, expected account ID",
- EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY));
- }
-
- try {
- int accountId =
- externalIdConfig.getInt(EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY, -1);
- if (accountId < 0) {
- throw invalidConfig(
- noteId,
- String.format(
- "Value %s for '%s.%s.%s' is invalid, expected account ID",
- accountIdStr, EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY));
- }
- return accountId;
- } catch (IllegalArgumentException e) {
- String msg =
- String.format(
- "Value %s for '%s.%s.%s' is invalid, expected account ID",
- accountIdStr, EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY);
- logger.atSevere().withCause(e).log(msg);
- throw invalidConfig(noteId, msg);
- }
- }
-
- private static ConfigInvalidException invalidConfig(String noteId, String message) {
- return new ConfigInvalidException(
- String.format("Invalid external ID config for note '%s': %s", noteId, message));
- }
-
public abstract Key key();
public abstract Account.Id accountId();
+ public abstract boolean isCaseInsensitive();
+
public abstract @Nullable String email();
public abstract @Nullable String password();
@@ -456,13 +296,14 @@
ExternalId o = (ExternalId) obj;
return Objects.equals(key(), o.key())
&& Objects.equals(accountId(), o.accountId())
+ && Objects.equals(isCaseInsensitive(), o.isCaseInsensitive())
&& Objects.equals(email(), o.email())
&& Objects.equals(password(), o.password());
}
@Override
public final int hashCode() {
- return Objects.hash(key(), accountId(), email(), password());
+ return Objects.hash(key(), accountId(), isCaseInsensitive(), email(), password());
}
/**
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java
index 902c18b..5d81a25 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java
@@ -73,6 +73,7 @@
private final Timer0 reloadDifferential;
private final boolean enablePartialReloads;
private final boolean isPersistentCache;
+ private final ExternalIdFactory externalIdFactory;
@Inject
ExternalIdCacheLoader(
@@ -82,7 +83,8 @@
@Named(ExternalIdCacheImpl.CACHE_NAME)
Provider<Cache<ObjectId, AllExternalIds>> externalIdCache,
MetricMaker metricMaker,
- @GerritServerConfig Config config) {
+ @GerritServerConfig Config config,
+ ExternalIdFactory externalIdFactory) {
this.externalIdReader = externalIdReader;
this.externalIdCache = externalIdCache;
this.gitRepositoryManager = gitRepositoryManager;
@@ -105,6 +107,7 @@
config.getBoolean("cache", ExternalIdCacheImpl.CACHE_NAME, "enablePartialReloads", true);
this.isPersistentCache =
config.getInt("cache", ExternalIdCacheImpl.CACHE_NAME, "diskLimit", 0) > 0;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -216,7 +219,7 @@
* @param additions map of name to blob ID for each external ID that should be added
* @param removals set of name {@link ObjectId}s that should be removed
*/
- private static AllExternalIds buildAllExternalIds(
+ private AllExternalIds buildAllExternalIds(
Repository repo,
AllExternalIds oldExternalIds,
Map<ObjectId, ObjectId> additions,
@@ -245,7 +248,7 @@
ExternalId parsedExternalId;
try {
parsedExternalId =
- ExternalId.parse(
+ externalIdFactory.parse(
nameToBlob.getKey().name(),
reader.open(nameToBlob.getValue()).getCachedBytes(),
nameToBlob.getValue());
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdCacheModule.java b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheModule.java
new file mode 100644
index 0000000..f0ad1b2
--- /dev/null
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheModule.java
@@ -0,0 +1,47 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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.gerrit.server.account.externalids;
+
+import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.cache.serialize.ObjectIdCacheSerializer;
+import com.google.inject.TypeLiteral;
+import java.time.Duration;
+import org.eclipse.jgit.lib.ObjectId;
+
+public class ExternalIdCacheModule extends CacheModule {
+ @Override
+ protected void configure() {
+ persist(ExternalIdCacheImpl.CACHE_NAME, ObjectId.class, new TypeLiteral<AllExternalIds>() {})
+ // The cached data is potentially pretty large and we are always only interested
+ // in the latest value. However, due to a race condition, it is possible for different
+ // threads to observe different values of the meta ref, and hence request different keys
+ // from the cache. Extend the cache size by 1 to cover this case, but expire the extra
+ // object after a short period of time, since it may be a potentially large amount of
+ // memory.
+ // When loading a new value because the primary data advanced, we want to leverage the old
+ // cache state to recompute only what changed. This doesn't affect cache size though as
+ // Guava calls the loader first and evicts later on.
+ .maximumWeight(2)
+ .expireFromMemoryAfterAccess(Duration.ofMinutes(1))
+ .loader(ExternalIdCacheLoader.class)
+ .diskLimit(-1)
+ .version(1)
+ .keySerializer(ObjectIdCacheSerializer.INSTANCE)
+ .valueSerializer(AllExternalIds.Serializer.INSTANCE);
+
+ bind(ExternalIdCacheImpl.class);
+ bind(ExternalIdCache.class).to(ExternalIdCacheImpl.class);
+ }
+}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdFactory.java b/java/com/google/gerrit/server/account/externalids/ExternalIdFactory.java
new file mode 100644
index 0000000..0c96f58
--- /dev/null
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdFactory.java
@@ -0,0 +1,314 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.gerrit.server.account.externalids;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.account.HashedPassword;
+import com.google.gerrit.server.account.externalids.ExternalId.Key;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.Set;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+
+@Singleton
+public class ExternalIdFactory {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject
+ public ExternalIdFactory(ExternalIdKeyFactory externalIdKeyFactory) {
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @return the created external ID
+ */
+ public ExternalId create(String scheme, String id, Account.Id accountId) {
+ return create(externalIdKeyFactory.create(scheme, id), accountId, null, null);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param hashedPassword the hashed password of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId create(
+ String scheme,
+ String id,
+ Account.Id accountId,
+ @Nullable String email,
+ @Nullable String hashedPassword) {
+ return create(externalIdKeyFactory.create(scheme, id), accountId, email, hashedPassword);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @return the created external ID
+ */
+ public ExternalId create(Key key, Account.Id accountId) {
+ return create(key, accountId, null, null);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param hashedPassword the hashed password of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId create(
+ Key key, Account.Id accountId, @Nullable String email, @Nullable String hashedPassword) {
+ return create(
+ key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), null);
+ }
+
+ /**
+ * Creates an external ID adding a hashed password computed from a plain password.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param plainPassword the plain HTTP password, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createWithPassword(
+ Key key, Account.Id accountId, @Nullable String email, @Nullable String plainPassword) {
+ plainPassword = Strings.emptyToNull(plainPassword);
+ String hashedPassword =
+ plainPassword != null ? HashedPassword.fromPassword(plainPassword).encode() : null;
+ return create(key, accountId, email, hashedPassword);
+ }
+
+ /**
+ * Create a external ID for a username (scheme "username").
+ *
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param plainPassword the plain HTTP password, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createUsername(
+ String id, Account.Id accountId, @Nullable String plainPassword) {
+ return createWithPassword(
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, id),
+ accountId,
+ null,
+ plainPassword);
+ }
+
+ /**
+ * Creates an external ID with an email.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createWithEmail(
+ String scheme, String id, Account.Id accountId, @Nullable String email) {
+ return createWithEmail(externalIdKeyFactory.create(scheme, id), accountId, email);
+ }
+
+ /**
+ * Creates an external ID with an email.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createWithEmail(Key key, Account.Id accountId, @Nullable String email) {
+ return create(key, accountId, Strings.emptyToNull(email), null);
+ }
+
+ /**
+ * Creates an external ID using the `mailto`-scheme.
+ *
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createEmail(Account.Id accountId, String email) {
+ return createWithEmail(ExternalId.SCHEME_MAILTO, email, accountId, requireNonNull(email));
+ }
+
+ ExternalId create(ExternalId extId, @Nullable ObjectId blobId) {
+ return create(extId.key(), extId.accountId(), extId.email(), extId.password(), blobId);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param hashedPassword the hashed password of the external ID, may be {@code null}
+ * @param blobId the ID of the note blob in the external IDs branch that stores this external ID.
+ * {@code null} if the external ID was created in code and is not yet stored in Git.
+ * @return the created external ID
+ */
+ public ExternalId create(
+ Key key,
+ Account.Id accountId,
+ @Nullable String email,
+ @Nullable String hashedPassword,
+ @Nullable ObjectId blobId) {
+ return ExternalId.create(
+ key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), blobId);
+ }
+
+ /**
+ * Parses an external ID from a byte array that contains the external ID as a Git config file
+ * text.
+ *
+ * <p>The Git config must have exactly one externalId subsection with an accountId and optionally
+ * email and password:
+ *
+ * <pre>
+ * [externalId "username:jdoe"]
+ * accountId = 1003407
+ * email = jdoe@example.com
+ * password = bcrypt:4:LCbmSBDivK/hhGVQMfkDpA==:XcWn0pKYSVU/UJgOvhidkEtmqCp6oKB7
+ * </pre>
+ *
+ * @param noteId the SHA-1 sum of the external ID used as the note's ID
+ * @param raw a byte array that contains the external ID as a Git config file text.
+ * @param blobId the ID of the note blob in the external IDs branch that stores this external ID.
+ * {@code null} if the external ID was created in code and is not yet stored in Git.
+ * @return the parsed external ID
+ */
+ public ExternalId parse(String noteId, byte[] raw, ObjectId blobId)
+ throws ConfigInvalidException {
+ requireNonNull(blobId);
+
+ Config externalIdConfig = new Config();
+ try {
+ externalIdConfig.fromText(new String(raw, UTF_8));
+ } catch (ConfigInvalidException e) {
+ throw invalidConfig(noteId, e.getMessage());
+ }
+
+ Set<String> externalIdKeys = externalIdConfig.getSubsections(ExternalId.EXTERNAL_ID_SECTION);
+ if (externalIdKeys.size() != 1) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "Expected exactly 1 '%s' section, found %d",
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeys.size()));
+ }
+
+ String externalIdKeyStr = Iterables.getOnlyElement(externalIdKeys);
+ Key externalIdKey = externalIdKeyFactory.parse(externalIdKeyStr);
+ if (externalIdKey == null) {
+ throw invalidConfig(noteId, String.format("External ID %s is invalid", externalIdKeyStr));
+ }
+
+ if (!externalIdKey.sha1().getName().equals(noteId)) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "SHA1 of external ID '%s' does not match note ID '%s'", externalIdKeyStr, noteId));
+ }
+
+ String email =
+ externalIdConfig.getString(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.EMAIL_KEY);
+ String password =
+ externalIdConfig.getString(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.PASSWORD_KEY);
+ int accountId = readAccountId(noteId, externalIdConfig, externalIdKeyStr);
+
+ return create(
+ externalIdKey,
+ Account.id(accountId),
+ Strings.emptyToNull(email),
+ Strings.emptyToNull(password),
+ blobId);
+ }
+
+ private static int readAccountId(String noteId, Config externalIdConfig, String externalIdKeyStr)
+ throws ConfigInvalidException {
+ String accountIdStr =
+ externalIdConfig.getString(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.ACCOUNT_ID_KEY);
+ if (accountIdStr == null) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "Value for '%s.%s.%s' is missing, expected account ID",
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.ACCOUNT_ID_KEY));
+ }
+
+ try {
+ int accountId =
+ externalIdConfig.getInt(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.ACCOUNT_ID_KEY, -1);
+ if (accountId < 0) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "Value %s for '%s.%s.%s' is invalid, expected account ID",
+ accountIdStr,
+ ExternalId.EXTERNAL_ID_SECTION,
+ externalIdKeyStr,
+ ExternalId.ACCOUNT_ID_KEY));
+ }
+ return accountId;
+ } catch (IllegalArgumentException e) {
+ String msg =
+ String.format(
+ "Value %s for '%s.%s.%s' is invalid, expected account ID",
+ accountIdStr,
+ ExternalId.EXTERNAL_ID_SECTION,
+ externalIdKeyStr,
+ ExternalId.ACCOUNT_ID_KEY);
+ logger.atSevere().withCause(e).log(msg);
+ throw invalidConfig(noteId, msg);
+ }
+ }
+
+ private static ConfigInvalidException invalidConfig(String noteId, String message) {
+ return new ConfigInvalidException(
+ String.format("Invalid external ID config for note '%s': %s", noteId, message));
+ }
+}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdKeyFactory.java b/java/com/google/gerrit/server/account/externalids/ExternalIdKeyFactory.java
new file mode 100644
index 0000000..37c2604
--- /dev/null
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdKeyFactory.java
@@ -0,0 +1,61 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.gerrit.server.account.externalids;
+
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.server.config.AuthConfig;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class ExternalIdKeyFactory {
+ private final boolean isUserNameCaseInsensitive;
+
+ @Inject
+ public ExternalIdKeyFactory(AuthConfig authConfig) {
+ this.isUserNameCaseInsensitive = authConfig.isUserNameCaseInsensitive();
+ }
+
+ /**
+ * Creates an external ID key.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @return the created external ID key
+ */
+ public ExternalId.Key create(@Nullable String scheme, String id) {
+ if (scheme != null
+ && (scheme.equals(ExternalId.SCHEME_USERNAME) || scheme.equals(ExternalId.SCHEME_GERRIT))) {
+ return ExternalId.Key.create(scheme, id, isUserNameCaseInsensitive);
+ }
+
+ return ExternalId.Key.create(scheme, id, false);
+ }
+
+ /**
+ * Parses an external ID key from its String representation
+ *
+ * @param externalId String representation of external ID key (e.g. username:johndoe)
+ * @return the external Id key object
+ */
+ public ExternalId.Key parse(String externalId) {
+ int c = externalId.indexOf(':');
+ if (c < 1 || c >= externalId.length() - 1) {
+ return create(null, externalId);
+ }
+ return create(externalId.substring(0, c), externalId.substring(c + 1));
+ }
+}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java b/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java
index 3e5d7b8..da7b357 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,34 +14,13 @@
package com.google.gerrit.server.account.externalids;
-import com.google.gerrit.server.cache.CacheModule;
-import com.google.gerrit.server.cache.serialize.ObjectIdCacheSerializer;
-import com.google.inject.TypeLiteral;
-import java.time.Duration;
-import org.eclipse.jgit.lib.ObjectId;
+import com.google.inject.AbstractModule;
-public class ExternalIdModule extends CacheModule {
+public class ExternalIdModule extends AbstractModule {
@Override
protected void configure() {
- persist(ExternalIdCacheImpl.CACHE_NAME, ObjectId.class, new TypeLiteral<AllExternalIds>() {})
- // The cached data is potentially pretty large and we are always only interested
- // in the latest value. However, due to a race condition, it is possible for different
- // threads to observe different values of the meta ref, and hence request different keys
- // from the cache. Extend the cache size by 1 to cover this case, but expire the extra
- // object after a short period of time, since it may be a potentially large amount of
- // memory.
- // When loading a new value because the primary data advanced, we want to leverage the old
- // cache state to recompute only what changed. This doesn't affect cache size though as
- // Guava calls the loader first and evicts later on.
- .maximumWeight(2)
- .expireFromMemoryAfterAccess(Duration.ofMinutes(1))
- .loader(ExternalIdCacheLoader.class)
- .diskLimit(-1)
- .version(1)
- .keySerializer(ObjectIdCacheSerializer.INSTANCE)
- .valueSerializer(AllExternalIds.Serializer.INSTANCE);
-
- bind(ExternalIdCacheImpl.class);
- bind(ExternalIdCache.class).to(ExternalIdCacheImpl.class);
+ bind(ExternalIdFactory.class);
+ bind(ExternalIdKeyFactory.class);
+ bind(PasswordVerifier.class);
}
}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
index 435a524..2b9c00a9 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
@@ -99,16 +99,19 @@
protected final MetricMaker metricMaker;
protected final AllUsersName allUsersName;
protected final DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors;
+ protected final ExternalIdFactory externalIdFactory;
protected ExternalIdNotesLoader(
ExternalIdCache externalIdCache,
MetricMaker metricMaker,
AllUsersName allUsersName,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
this.externalIdCache = externalIdCache;
this.metricMaker = metricMaker;
this.allUsersName = allUsersName;
this.upsertPreprocessors = upsertPreprocessors;
+ this.externalIdFactory = externalIdFactory;
}
/**
@@ -199,22 +202,25 @@
Provider<AccountIndexer> accountIndexer,
MetricMaker metricMaker,
AllUsersName allUsersName,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
- super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors);
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
+ super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors, externalIdFactory);
this.accountIndexer = accountIndexer;
}
@Override
public ExternalIdNotes load(Repository allUsersRepo)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.load();
}
@Override
public ExternalIdNotes load(Repository allUsersRepo, @Nullable ObjectId rev)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.load(rev);
}
@@ -232,14 +238,16 @@
ExternalIdCache externalIdCache,
MetricMaker metricMaker,
AllUsersName allUsersName,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
- super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors);
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
+ super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors, externalIdFactory);
}
@Override
public ExternalIdNotes load(Repository allUsersRepo)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.setNoReindex()
.load();
}
@@ -247,7 +255,8 @@
@Override
public ExternalIdNotes load(Repository allUsersRepo, @Nullable ObjectId rev)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.setNoReindex()
.load(rev);
}
@@ -269,10 +278,17 @@
* @return read-only {@link ExternalIdNotes} instance
*/
public static ExternalIdNotes loadReadOnly(
- AllUsersName allUsersName, Repository allUsersRepo, @Nullable ObjectId rev)
+ AllUsersName allUsersName,
+ Repository allUsersRepo,
+ @Nullable ObjectId rev,
+ ExternalIdFactory externalIdFactory)
throws IOException, ConfigInvalidException {
return new ExternalIdNotes(
- new DisabledMetricMaker(), allUsersName, allUsersRepo, DynamicMap.emptyMap())
+ new DisabledMetricMaker(),
+ allUsersName,
+ allUsersRepo,
+ DynamicMap.emptyMap(),
+ externalIdFactory)
.setReadOnly()
.setNoCacheUpdate()
.setNoReindex()
@@ -290,10 +306,14 @@
* @return {@link ExternalIdNotes} instance that doesn't updates caches on save
*/
public static ExternalIdNotes loadNoCacheUpdate(
- AllUsersName allUsersName, Repository allUsersRepo)
+ AllUsersName allUsersName, Repository allUsersRepo, ExternalIdFactory externalIdFactory)
throws IOException, ConfigInvalidException {
return new ExternalIdNotes(
- new DisabledMetricMaker(), allUsersName, allUsersRepo, DynamicMap.emptyMap())
+ new DisabledMetricMaker(),
+ allUsersName,
+ allUsersRepo,
+ DynamicMap.emptyMap(),
+ externalIdFactory)
.setNoCacheUpdate()
.setNoReindex()
.load();
@@ -304,6 +324,7 @@
private final Repository repo;
private final DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors;
private final CallerFinder callerFinder;
+ private final ExternalIdFactory externalIdFactory;
private NoteMap noteMap;
private ObjectId oldRev;
@@ -334,7 +355,8 @@
MetricMaker metricMaker,
AllUsersName allUsersName,
Repository allUsersRepo,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
this.updateCount =
metricMaker.newCounter(
"notedb/external_id_update_count",
@@ -355,6 +377,7 @@
// 3. direct callers
.addTarget(ExternalIdNotes.class)
.build();
+ this.externalIdFactory = externalIdFactory;
}
public ExternalIdNotes setAfterReadRevision(Runnable afterReadRevision) {
@@ -434,7 +457,7 @@
try (RevWalk rw = new RevWalk(repo)) {
ObjectId noteDataId = noteMap.get(noteId);
byte[] raw = readNoteData(rw, noteDataId);
- return Optional.of(ExternalId.parse(noteId.name(), raw, noteDataId));
+ return Optional.of(externalIdFactory.parse(noteId.name(), raw, noteDataId));
}
}
@@ -468,7 +491,7 @@
for (Note note : noteMap) {
byte[] raw = readNoteData(rw, note.getData());
try {
- b.add(ExternalId.parse(note.getName(), raw, note.getData()));
+ b.add(externalIdFactory.parse(note.getName(), raw, note.getData()));
} catch (ConfigInvalidException | RuntimeException e) {
logger.atSevere().withCause(e).log(
"Ignoring invalid external ID note %s", note.getName());
@@ -840,8 +863,7 @@
*
* <p>If the external ID already exists, it is overwritten.
*/
- private static ExternalId upsert(
- RevWalk rw, ObjectInserter ins, NoteMap noteMap, ExternalId extId)
+ private ExternalId upsert(RevWalk rw, ObjectInserter ins, NoteMap noteMap, ExternalId extId)
throws IOException, ConfigInvalidException {
ObjectId noteId = extId.key().sha1();
Config c = new Config();
@@ -859,7 +881,7 @@
byte[] raw = c.toText().getBytes(UTF_8);
ObjectId noteData = ins.insert(OBJ_BLOB, raw);
noteMap.set(noteId, noteData);
- return ExternalId.create(extId, noteData);
+ return externalIdFactory.create(extId, noteData);
}
/**
@@ -868,7 +890,7 @@
* @throws IllegalStateException is thrown if there is an existing external ID that has the same
* key, but otherwise doesn't match the specified external ID.
*/
- private static void remove(RevWalk rw, NoteMap noteMap, ExternalId extId)
+ private void remove(RevWalk rw, NoteMap noteMap, ExternalId extId)
throws IOException, ConfigInvalidException {
ObjectId noteId = extId.key().sha1();
if (!noteMap.contains(noteId)) {
@@ -877,7 +899,7 @@
ObjectId noteDataId = noteMap.get(noteId);
byte[] raw = readNoteData(rw, noteDataId);
- ExternalId actualExtId = ExternalId.parse(noteId.name(), raw, noteDataId);
+ ExternalId actualExtId = externalIdFactory.parse(noteId.name(), raw, noteDataId);
checkState(
extId.equals(actualExtId),
"external id %s should be removed, but it doesn't match the actual external id %s",
@@ -894,8 +916,7 @@
* @return the external ID that was removed, {@code null} if no external ID with the specified key
* exists
*/
- @Nullable
- private static ExternalId remove(
+ private ExternalId remove(
RevWalk rw, NoteMap noteMap, ExternalId.Key extIdKey, Account.Id expectedAccountId)
throws IOException, ConfigInvalidException {
ObjectId noteId = extIdKey.sha1();
@@ -905,7 +926,7 @@
ObjectId noteDataId = noteMap.get(noteId);
byte[] raw = readNoteData(rw, noteDataId);
- ExternalId extId = ExternalId.parse(noteId.name(), raw, noteDataId);
+ ExternalId extId = externalIdFactory.parse(noteId.name(), raw, noteDataId);
if (expectedAccountId != null) {
checkState(
expectedAccountId.equals(extId.accountId()),
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java b/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java
index f2505fa..0d715ae 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java
@@ -69,10 +69,14 @@
private boolean failOnLoad = false;
private final Timer0 readAllLatency;
private final Timer0 readSingleLatency;
+ private final ExternalIdFactory externalIdFactory;
@Inject
ExternalIdReader(
- GitRepositoryManager repoManager, AllUsersName allUsersName, MetricMaker metricMaker) {
+ GitRepositoryManager repoManager,
+ AllUsersName allUsersName,
+ MetricMaker metricMaker,
+ ExternalIdFactory externalIdFactory) {
this.repoManager = repoManager;
this.allUsersName = allUsersName;
this.readAllLatency =
@@ -87,6 +91,7 @@
new Description("Latency for reading a single external ID from NoteDb.")
.setCumulative()
.setUnit(Units.MILLISECONDS));
+ this.externalIdFactory = externalIdFactory;
}
@VisibleForTesting
@@ -106,7 +111,7 @@
try (Timer0.Context ctx = readAllLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, null).all();
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, null, externalIdFactory).all();
}
}
@@ -125,7 +130,7 @@
try (Timer0.Context ctx = readAllLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev).all();
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev, externalIdFactory).all();
}
}
@@ -135,7 +140,7 @@
try (Timer0.Context ctx = readSingleLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, null).get(key);
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, null, externalIdFactory).get(key);
}
}
@@ -146,7 +151,7 @@
try (Timer0.Context ctx = readSingleLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev).get(key);
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev, externalIdFactory).get(key);
}
}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java b/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
index 6a4da09..cf0e5d3 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
@@ -43,29 +43,32 @@
private final AllUsersName allUsers;
private final AccountCache accountCache;
private final OutgoingEmailValidator validator;
+ private final ExternalIdFactory externalIdFactory;
@Inject
ExternalIdsConsistencyChecker(
GitRepositoryManager repoManager,
AllUsersName allUsers,
AccountCache accountCache,
- OutgoingEmailValidator validator) {
+ OutgoingEmailValidator validator,
+ ExternalIdFactory externalIdFactory) {
this.repoManager = repoManager;
this.allUsers = allUsers;
this.accountCache = accountCache;
this.validator = validator;
+ this.externalIdFactory = externalIdFactory;
}
public List<ConsistencyProblemInfo> check() throws IOException, ConfigInvalidException {
try (Repository repo = repoManager.openRepository(allUsers)) {
- return check(ExternalIdNotes.loadReadOnly(allUsers, repo, null));
+ return check(ExternalIdNotes.loadReadOnly(allUsers, repo, null, externalIdFactory));
}
}
public List<ConsistencyProblemInfo> check(ObjectId rev)
throws IOException, ConfigInvalidException {
try (Repository repo = repoManager.openRepository(allUsers)) {
- return check(ExternalIdNotes.loadReadOnly(allUsers, repo, rev));
+ return check(ExternalIdNotes.loadReadOnly(allUsers, repo, rev, externalIdFactory));
}
}
@@ -79,7 +82,7 @@
for (Note note : noteMap) {
byte[] raw = ExternalIdNotes.readNoteData(rw, note.getData());
try {
- ExternalId extId = ExternalId.parse(note.getName(), raw, note.getData());
+ ExternalId extId = externalIdFactory.parse(note.getName(), raw, note.getData());
problems.addAll(validateExternalId(extId));
if (extId.email() != null) {
diff --git a/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java b/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java
index 3f2f774..33443c1 100644
--- a/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java
+++ b/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java
@@ -20,21 +20,30 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.server.account.HashedPassword;
+import com.google.inject.Inject;
import java.util.Collection;
/** Checks if a given username and password match a user's external IDs. */
public class PasswordVerifier {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject
+ public PasswordVerifier(ExternalIdKeyFactory externalIdKeyFactory) {
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ }
+
/** Returns {@code true} if there is an external ID matching both the username and password. */
- public static boolean checkPassword(
+ public boolean checkPassword(
Collection<ExternalId> externalIds, String username, @Nullable String password) {
if (password == null) {
return false;
}
for (ExternalId id : externalIds) {
// Only process the "username:$USER" entry, which is unique.
- if (!id.isScheme(SCHEME_USERNAME) || !username.equals(id.key().id())) {
+ if (!id.isScheme(SCHEME_USERNAME)
+ || !id.key().equals(externalIdKeyFactory.create(SCHEME_USERNAME, username))) {
continue;
}
diff --git a/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java b/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java
index b8040f7..a42afc3 100644
--- a/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java
+++ b/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java
@@ -45,7 +45,9 @@
rw,
ident,
(ins, noteMap) -> {
- ExternalId extId = ExternalId.create(ExternalId.Key.parse(externalId), accountId);
+ ExternalId extId =
+ ExternalId.create(
+ ExternalId.Key.parse(externalId, false), accountId, null, null, null);
ObjectId noteId = extId.key().sha1();
Config c = new Config();
extId.writeToConfig(c);
@@ -65,8 +67,10 @@
rw,
ident,
(ins, noteMap) -> {
- ExternalId extId = ExternalId.create(ExternalId.Key.parse(externalId), accountId);
- ObjectId noteId = ExternalId.Key.parse(externalId + "x").sha1();
+ ExternalId extId =
+ ExternalId.create(
+ ExternalId.Key.parse(externalId, false), accountId, null, null, null);
+ ObjectId noteId = ExternalId.Key.parse(externalId + "x", false).sha1();
Config c = new Config();
extId.writeToConfig(c);
byte[] raw = c.toText().getBytes(UTF_8);
@@ -83,7 +87,7 @@
rw,
ident,
(ins, noteMap) -> {
- ObjectId noteId = ExternalId.Key.parse(externalId).sha1();
+ ObjectId noteId = ExternalId.Key.parse(externalId, false).sha1();
byte[] raw = "bad-config".getBytes(UTF_8);
ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
noteMap.set(noteId, dataBlob);
@@ -98,7 +102,7 @@
rw,
ident,
(ins, noteMap) -> {
- ObjectId noteId = ExternalId.Key.parse(externalId).sha1();
+ ObjectId noteId = ExternalId.Key.parse(externalId, false).sha1();
byte[] raw = "".getBytes(UTF_8);
ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
noteMap.set(noteId, dataBlob);
diff --git a/java/com/google/gerrit/server/args4j/AccountIdHandler.java b/java/com/google/gerrit/server/args4j/AccountIdHandler.java
index 73a970b..5df4d28 100644
--- a/java/com/google/gerrit/server/args4j/AccountIdHandler.java
+++ b/java/com/google/gerrit/server/args4j/AccountIdHandler.java
@@ -44,12 +44,14 @@
private final AccountResolver accountResolver;
private final AccountManager accountManager;
private final AuthType authType;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
public AccountIdHandler(
AccountResolver accountResolver,
AccountManager accountManager,
AuthConfig authConfig,
+ AuthRequest.Factory authRequestFactory,
@Assisted CmdLineParser parser,
@Assisted OptionDef option,
@Assisted Setter<Account.Id> setter) {
@@ -57,6 +59,7 @@
this.accountResolver = accountResolver;
this.accountManager = accountManager;
this.authType = authConfig.getAuthType();
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -105,7 +108,7 @@
}
try {
- AuthRequest req = AuthRequest.forUser(user);
+ AuthRequest req = authRequestFactory.createForUser(user);
req.setSkipAuthentication(true);
return accountManager.authenticate(req).getAccountId();
} catch (AccountException e) {
diff --git a/java/com/google/gerrit/server/auth/InternalAuthBackend.java b/java/com/google/gerrit/server/auth/InternalAuthBackend.java
index 2f8886b..ce536f6 100644
--- a/java/com/google/gerrit/server/auth/InternalAuthBackend.java
+++ b/java/com/google/gerrit/server/auth/InternalAuthBackend.java
@@ -26,11 +26,14 @@
public class InternalAuthBackend implements AuthBackend {
private final AccountCache accountCache;
private final AuthConfig authConfig;
+ private final PasswordVerifier passwordVerifier;
@Inject
- InternalAuthBackend(AccountCache accountCache, AuthConfig authConfig) {
+ InternalAuthBackend(
+ AccountCache accountCache, AuthConfig authConfig, PasswordVerifier passwordVerifier) {
this.accountCache = accountCache;
this.authConfig = authConfig;
+ this.passwordVerifier = passwordVerifier;
}
@Override
@@ -63,7 +66,7 @@
+ ": account inactive or not provisioned in Gerrit");
}
- if (!PasswordVerifier.checkPassword(who.externalIds(), username, req.getPassword().get())) {
+ if (!passwordVerifier.checkPassword(who.externalIds(), username, req.getPassword().get())) {
throw new InvalidCredentialsException();
}
return new AuthUser(AuthUser.UUID.create(username), username);
diff --git a/java/com/google/gerrit/server/config/AuthConfig.java b/java/com/google/gerrit/server/config/AuthConfig.java
index de57d04..2ac551d 100644
--- a/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/java/com/google/gerrit/server/config/AuthConfig.java
@@ -64,6 +64,7 @@
private final boolean cookieSecure;
private final SignedToken emailReg;
private final boolean allowRegisterNewEmail;
+ private final boolean userNameCaseInsensitive;
private GitBasicAuthPolicy gitBasicAuthPolicy;
@Inject
@@ -95,6 +96,7 @@
useContributorAgreements = cfg.getBoolean("auth", "contributoragreements", false);
userNameToLowerCase = cfg.getBoolean("auth", "userNameToLowerCase", false);
allowRegisterNewEmail = cfg.getBoolean("auth", "allowRegisterNewEmail", true);
+ userNameCaseInsensitive = cfg.getBoolean("auth", "userNameCaseInsensitive", false);
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP
&& authType != AuthType.LDAP
@@ -237,6 +239,11 @@
return userNameToLowerCase;
}
+ /** Whether user name should be matched case insenitive */
+ public boolean isUserNameCaseInsensitive() {
+ return userNameCaseInsensitive;
+ }
+
public GitBasicAuthPolicy getGitBasicAuthPolicy() {
return gitBasicAuthPolicy;
}
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 48c03a0..ef1c0ae 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -92,6 +92,7 @@
import com.google.gerrit.server.account.AccountDeactivator;
import com.google.gerrit.server.account.AccountExternalIdCreator;
import com.google.gerrit.server.account.AccountManager;
+import com.google.gerrit.server.account.AccountModule;
import com.google.gerrit.server.account.AccountTagProvider;
import com.google.gerrit.server.account.AccountVisibilityProvider;
import com.google.gerrit.server.account.CapabilityCollection;
@@ -101,6 +102,7 @@
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
+import com.google.gerrit.server.account.externalids.ExternalIdCacheModule;
import com.google.gerrit.server.account.externalids.ExternalIdModule;
import com.google.gerrit.server.account.externalids.ExternalIdUpsertPreprocessor;
import com.google.gerrit.server.approval.ApprovalCacheImpl;
@@ -266,8 +268,10 @@
install(SubmitRequirementsEvaluatorImpl.module());
install(new AccessControlModule());
+ install(new AccountModule());
install(new CmdLineParserModule());
install(new EmailModule());
+ install(new ExternalIdCacheModule());
install(new ExternalIdModule());
install(new GitModule());
install(new GroupDbModule());
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 1e77cc4..42fc916 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -637,10 +637,10 @@
tracePushOption.isPresent(),
tracePushOption.orElse(null),
(tagName, traceId) -> addMessage(tagName + ": " + traceId));
- TraceTimer traceTimer =
- newTimer("processCommands", Metadata.builder().resourceCount(commandCount));
PerformanceLogContext performanceLogContext =
- new PerformanceLogContext(config, performanceLoggers)) {
+ new PerformanceLogContext(config, performanceLoggers);
+ TraceTimer traceTimer =
+ newTimer("processCommands", Metadata.builder().resourceCount(commandCount))) {
RequestInfo requestInfo =
RequestInfo.builder(RequestInfo.RequestType.GIT_RECEIVE, user, traceContext)
.project(project.getNameKey())
diff --git a/java/com/google/gerrit/server/mail/EmailTokenVerifier.java b/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
index 2ff5fc3..ead4c06 100644
--- a/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
+++ b/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
@@ -56,10 +56,13 @@
class ParsedToken {
private final Account.Id accountId;
private final String emailAddress;
+ private final AuthRequest.Factory authRequestFactory;
- public ParsedToken(Account.Id accountId, String emailAddress) {
+ public ParsedToken(
+ Account.Id accountId, String emailAddress, AuthRequest.Factory authRequestFactory) {
this.accountId = accountId;
this.emailAddress = emailAddress;
+ this.authRequestFactory = authRequestFactory;
}
public Account.Id getAccountId() {
@@ -71,7 +74,7 @@
}
public AuthRequest toAuthRequest() {
- return AuthRequest.forEmail(getEmailAddress());
+ return authRequestFactory.createForEmail(getEmailAddress());
}
@Override
diff --git a/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java b/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
index 77be665..bdfaf6d 100644
--- a/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
+++ b/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
@@ -19,6 +19,7 @@
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.mail.send.RegisterNewEmailSender;
import com.google.inject.AbstractModule;
@@ -31,6 +32,7 @@
@Singleton
public class SignedTokenEmailTokenVerifier implements EmailTokenVerifier {
private final SignedToken emailRegistrationToken;
+ private final AuthRequest.Factory authRequestFactory;
public static class Module extends AbstractModule {
@Override
@@ -40,8 +42,9 @@
}
@Inject
- SignedTokenEmailTokenVerifier(AuthConfig config) {
+ SignedTokenEmailTokenVerifier(AuthConfig config, AuthRequest.Factory authRequestFactory) {
emailRegistrationToken = config.getEmailRegistrationToken();
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -77,7 +80,7 @@
}
Account.Id id = Account.Id.tryParse(matcher.group(1)).orElseThrow(InvalidTokenException::new);
String newEmail = matcher.group(2);
- return new ParsedToken(id, newEmail);
+ return new ParsedToken(id, newEmail, authRequestFactory);
}
private void checkEmailRegistrationToken() {
diff --git a/java/com/google/gerrit/server/mail/send/ChangeEmail.java b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
index 48ab397..1a2e150 100644
--- a/java/com/google/gerrit/server/mail/send/ChangeEmail.java
+++ b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
@@ -41,11 +41,10 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.mail.send.ProjectWatch.Watchers;
import com.google.gerrit.server.notedb.ReviewerStateInternal;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListEntry;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.FilePathAdapter;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -66,6 +65,7 @@
import org.apache.james.mime4j.dom.field.FieldName;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.TemporaryBuffer;
@@ -269,17 +269,23 @@
if (patchSet != null) {
detail.append("---\n");
- PatchList patchList = getPatchList();
- for (PatchListEntry p : patchList.getPatches()) {
- if (Patch.isMagic(p.getNewName())) {
+ Map<String, FileDiffOutput> modifiedFiles = listModifiedFiles();
+ for (FileDiffOutput fileDiff : modifiedFiles.values()) {
+ if (fileDiff.newPath().isPresent() && Patch.isMagic(fileDiff.newPath().get())) {
continue;
}
detail
- .append(p.getChangeType().getCode())
+ .append(fileDiff.changeType().getCode())
.append(" ")
- .append(p.getNewName())
+ .append(
+ FilePathAdapter.getNewPath(
+ fileDiff.oldPath(), fileDiff.newPath(), fileDiff.changeType()))
.append("\n");
}
+ Integer insertions =
+ modifiedFiles.values().stream().map(FileDiffOutput::insertions).reduce(0, Integer::sum);
+ Integer deletions =
+ modifiedFiles.values().stream().map(FileDiffOutput::deletions).reduce(0, Integer::sum);
detail.append(
MessageFormat.format(
"" //
@@ -287,9 +293,9 @@
+ "{1,choice,0#0 insertions|1#1 insertion|1<{1} insertions}(+), " //
+ "{2,choice,0#0 deletions|1#1 deletion|1<{2} deletions}(-)" //
+ "\n",
- patchList.getPatches().size() - 1, //
- patchList.getInsertions(), //
- patchList.getDeletions()));
+ modifiedFiles.size() - 1, //
+ insertions, //
+ deletions));
detail.append("\n");
}
return detail.toString();
@@ -300,7 +306,8 @@
}
/** Get the patch list corresponding to patch set patchSetId of this change. */
- protected PatchList getPatchList(int patchSetId) throws PatchListNotAvailableException {
+ protected Map<String, FileDiffOutput> listModifiedFiles(int patchSetId)
+ throws DiffNotAvailableException {
PatchSet ps;
if (patchSetId == patchSet.number()) {
ps = patchSet;
@@ -308,18 +315,20 @@
try {
ps = args.patchSetUtil.get(changeData.notes(), PatchSet.id(change.getId(), patchSetId));
} catch (StorageException e) {
- throw new PatchListNotAvailableException("Failed to get patchSet", e);
+ throw new DiffNotAvailableException("Failed to get patchSet", e);
}
}
- return args.patchListCache.get(change, ps);
+ return args.diffOperations.listModifiedFilesAgainstParent(
+ change.getProject(), ps.commitId(), /* parentNum= */ 0);
}
/** Get the patch list corresponding to this patch set. */
- protected PatchList getPatchList() throws PatchListNotAvailableException {
+ protected Map<String, FileDiffOutput> listModifiedFiles() throws DiffNotAvailableException {
if (patchSet != null) {
- return args.patchListCache.get(change, patchSet);
+ return args.diffOperations.listModifiedFilesAgainstParent(
+ change.getProject(), patchSet.commitId(), /* parentNum= */ 0);
}
- throw new PatchListNotAvailableException("no patchSet specified");
+ throw new DiffNotAvailableException("no patchSet specified");
}
/** Get the project entity the change is in; null if its been deleted. */
@@ -566,18 +575,15 @@
/** Show patch set as unified difference. */
public String getUnifiedDiff() {
- PatchList patchList;
+ Map<String, FileDiffOutput> modifiedFiles;
try {
- patchList = getPatchList();
- if (patchList.getOldId() == null) {
+ modifiedFiles = listModifiedFiles();
+ if (modifiedFiles.isEmpty()) {
// Octopus merges are not well supported for diff output by Gerrit.
// Currently these always have a null oldId in the PatchList.
return "[Octopus merge; cannot be formatted as a diff.]\n";
}
- } catch (PatchListObjectTooLargeException e) {
- logger.atWarning().log("Cannot format patch %s", e.getMessage());
- return "";
- } catch (PatchListNotAvailableException e) {
+ } catch (DiffNotAvailableException e) {
logger.atSevere().withCause(e).log("Cannot format patch");
return "";
}
@@ -587,9 +593,11 @@
try (DiffFormatter fmt = new DiffFormatter(buf)) {
try (Repository git = args.server.openRepository(change.getProject())) {
try {
+ ObjectId oldId = modifiedFiles.values().iterator().next().oldCommitId();
+ ObjectId newId = modifiedFiles.values().iterator().next().newCommitId();
fmt.setRepository(git);
fmt.setDetectRenames(true);
- fmt.format(patchList.getOldId(), patchList.getNewId());
+ fmt.format(oldId, newId);
return RawParseUtils.decode(buf.toByteArray());
} catch (IOException e) {
if (JGitText.get().inMemoryBufferLimitExceeded.equals(e.getMessage())) {
diff --git a/java/com/google/gerrit/server/mail/send/CommentSender.java b/java/com/google/gerrit/server/mail/send/CommentSender.java
index ac6c2f3..4593584 100644
--- a/java/com/google/gerrit/server/mail/send/CommentSender.java
+++ b/java/com/google/gerrit/server/mail/send/CommentSender.java
@@ -36,10 +36,9 @@
import com.google.gerrit.server.CommentsUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.mail.receive.Protocol;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.PatchFile;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.util.LabelVote;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -198,24 +197,24 @@
currentGroup = new FileCommentGroup();
currentGroup.filename = c.key.filename;
currentGroup.patchSetId = c.key.patchSetId;
- // Get the patch list:
- PatchList patchList = null;
+ // Get the modified files:
+ Map<String, FileDiffOutput> modifiedFiles = null;
try {
- patchList = getPatchList(c.key.patchSetId);
- } catch (PatchListObjectTooLargeException e) {
- logger.atWarning().log("Failed to get patch list: %s", e.getMessage());
- } catch (PatchListNotAvailableException e) {
- logger.atSevere().withCause(e).log("Failed to get patch list");
+ modifiedFiles = listModifiedFiles(c.key.patchSetId);
+ } catch (DiffNotAvailableException e) {
+ logger.atSevere().withCause(e).log("Failed to get modified files");
}
groups.add(currentGroup);
- if (patchList != null) {
+ if (modifiedFiles != null && !modifiedFiles.isEmpty()) {
try {
- currentGroup.fileData = new PatchFile(repo, patchList, c.key.filename);
+ currentGroup.fileData = new PatchFile(repo, modifiedFiles, c.key.filename);
} catch (IOException e) {
logger.atWarning().withCause(e).log(
"Cannot load %s from %s in %s",
- c.key.filename, patchList.getNewId().name(), projectState.getName());
+ c.key.filename,
+ modifiedFiles.values().iterator().next().newCommitId().name(),
+ projectState.getName());
currentGroup.fileData = null;
}
}
diff --git a/java/com/google/gerrit/server/mail/send/EmailArguments.java b/java/com/google/gerrit/server/mail/send/EmailArguments.java
index 258c9af..96effc1 100644
--- a/java/com/google/gerrit/server/mail/send/EmailArguments.java
+++ b/java/com/google/gerrit/server/mail/send/EmailArguments.java
@@ -35,7 +35,7 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.mail.EmailSettings;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.project.ProjectCache;
@@ -43,6 +43,7 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
+import com.google.gerrit.server.update.RetryHelper;
import com.google.gerrit.server.validators.OutgoingEmailValidationListener;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -71,7 +72,7 @@
final PermissionBackend permissionBackend;
final GroupBackend groupBackend;
final AccountCache accountCache;
- final PatchListCache patchListCache;
+ final DiffOperations diffOperations;
final PatchSetUtil patchSetUtil;
final ApprovalsUtil approvalsUtil;
final Provider<FromAddressGenerator> fromAddressGenerator;
@@ -86,7 +87,6 @@
final AllProjectsName allProjectsName;
final List<String> sshAddresses;
final SitePaths site;
-
final Provider<ChangeQueryBuilder> queryBuilder;
final ChangeData.Factory changeDataFactory;
final Provider<SoySauce> soySauce;
@@ -97,6 +97,7 @@
final boolean addInstanceNameInSubject;
final Provider<String> instanceNameProvider;
final Provider<CurrentUser> currentUserProvider;
+ final RetryHelper retryHelper;
@Inject
EmailArguments(
@@ -105,7 +106,7 @@
PermissionBackend permissionBackend,
GroupBackend groupBackend,
AccountCache accountCache,
- PatchListCache patchListCache,
+ DiffOperations diffOperations,
PatchSetUtil patchSetUtil,
ApprovalsUtil approvalsUtil,
Provider<FromAddressGenerator> fromAddressGenerator,
@@ -129,13 +130,14 @@
OutgoingEmailValidator validator,
@GerritInstanceName Provider<String> instanceNameProvider,
@GerritServerConfig Config cfg,
- Provider<CurrentUser> currentUserProvider) {
+ Provider<CurrentUser> currentUserProvider,
+ RetryHelper retryHelper) {
this.server = server;
this.projectCache = projectCache;
this.permissionBackend = permissionBackend;
this.groupBackend = groupBackend;
this.accountCache = accountCache;
- this.patchListCache = patchListCache;
+ this.diffOperations = diffOperations;
this.patchSetUtil = patchSetUtil;
this.approvalsUtil = approvalsUtil;
this.fromAddressGenerator = fromAddressGenerator;
@@ -158,8 +160,8 @@
this.accountQueryProvider = accountQueryProvider;
this.validator = validator;
this.instanceNameProvider = instanceNameProvider;
-
this.addInstanceNameInSubject = cfg.getBoolean("sendemail", "addInstanceNameInSubject", false);
this.currentUserProvider = currentUserProvider;
+ this.retryHelper = retryHelper;
}
}
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index ddcc0cf..8547336 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -18,6 +18,7 @@
import static com.google.gerrit.extensions.client.GeneralPreferencesInfo.EmailStrategy.DISABLED;
import static java.util.Objects.requireNonNull;
+import com.google.common.base.Throwables;
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
@@ -34,6 +35,7 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.change.NotifyResolver;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.update.RetryableAction.ActionType;
import com.google.gerrit.server.validators.OutgoingEmailValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.template.soy.jbcsrc.api.SoySauce;
@@ -99,6 +101,25 @@
* @throws EmailException
*/
public void send() throws EmailException {
+ try {
+ args.retryHelper
+ .action(
+ ActionType.SEND_EMAIL,
+ "sendEmail",
+ () -> {
+ sendImpl();
+ return null;
+ })
+ .retryWithTrace(Exception.class::isInstance)
+ .call();
+ } catch (Exception e) {
+ Throwables.throwIfUnchecked(e);
+ Throwables.throwIfInstanceOf(e, EmailException.class);
+ throw new EmailException("sending email failed", e);
+ }
+ }
+
+ private void sendImpl() throws EmailException {
if (!args.emailSender.isEnabled()) {
// Server has explicitly disabled email sending.
//
diff --git a/java/com/google/gerrit/server/patch/PatchFile.java b/java/com/google/gerrit/server/patch/PatchFile.java
index ca5223d..3cc89f85 100644
--- a/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/java/com/google/gerrit/server/patch/PatchFile.java
@@ -18,7 +18,9 @@
import com.google.gerrit.entities.Patch;
import com.google.gerrit.exceptions.NoSuchEntityException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import java.io.IOException;
+import java.util.Map;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -35,7 +37,7 @@
/** State supporting processing of a single {@link Patch} instance. */
public class PatchFile {
private final Repository repo;
- private final PatchListEntry entry;
+ private final FileDiffOutput diff;
private final RevTree aTree;
private final RevTree bTree;
@@ -51,21 +53,25 @@
private Text a;
private Text b;
- public PatchFile(Repository repo, PatchList patchList, String fileName)
- throws MissingObjectException, IncorrectObjectTypeException, IOException {
+ public PatchFile(Repository repo, Map<String, FileDiffOutput> modifiedFiles, String fileName)
+ throws IOException {
this.repo = repo;
- this.entry = patchList.get(fileName);
+ this.diff =
+ modifiedFiles.values().stream()
+ .filter(f -> f.newPath().isPresent() && f.newPath().get().equals(fileName))
+ .findFirst()
+ .orElse(FileDiffOutput.empty(fileName, ObjectId.zeroId(), ObjectId.zeroId()));
try (ObjectReader reader = repo.newObjectReader();
RevWalk rw = new RevWalk(reader)) {
- final RevCommit bCommit = rw.parseCommit(patchList.getNewId());
+ final RevCommit bCommit = rw.parseCommit(diff.newCommitId());
if (Patch.COMMIT_MSG.equals(fileName)) {
- if (patchList.getComparisonType().isAgainstParentOrAutoMerge()) {
+ if (diff.comparisonType().isAgainstParentOrAutoMerge()) {
a = Text.EMPTY;
} else {
// For the initial commit, we have an empty tree on Side A
- RevObject object = rw.parseAny(patchList.getOldId());
+ RevObject object = rw.parseAny(diff.oldCommitId());
a = object instanceof RevCommit ? Text.forCommit(reader, object) : Text.EMPTY;
}
b = Text.forCommit(reader, bCommit);
@@ -74,18 +80,18 @@
bTree = null;
} else if (Patch.MERGE_LIST.equals(fileName)) {
// For the initial commit, we have an empty tree on Side A
- RevObject object = rw.parseAny(patchList.getOldId());
+ RevObject object = rw.parseAny(diff.oldCommitId());
a =
object instanceof RevCommit
- ? Text.forMergeList(patchList.getComparisonType(), reader, object)
+ ? Text.forMergeList(diff.comparisonType(), reader, object)
: Text.EMPTY;
- b = Text.forMergeList(patchList.getComparisonType(), reader, bCommit);
+ b = Text.forMergeList(diff.comparisonType(), reader, bCommit);
aTree = null;
bTree = null;
} else {
- if (patchList.getOldId() != null) {
- aTree = rw.parseTree(patchList.getOldId());
+ if (diff.oldCommitId() != null) {
+ aTree = rw.parseTree(diff.oldCommitId());
} else {
final RevCommit p = bCommit.getParent(0);
rw.parseHeaders(p);
@@ -97,11 +103,11 @@
}
private String getOldName() {
- String name = entry.getOldName();
+ String name = FilePathAdapter.getOldPath(diff.oldPath(), diff.changeType());
if (name != null) {
return name;
}
- return entry.getNewName();
+ return FilePathAdapter.getNewPath(diff.oldPath(), diff.newPath(), diff.changeType());
}
/**
@@ -123,7 +129,10 @@
case 1:
if (b == null) {
- b = load(bTree, entry.getNewName());
+ b =
+ load(
+ bTree,
+ FilePathAdapter.getNewPath(diff.oldPath(), diff.newPath(), diff.changeType()));
}
return b.getString(line - 1);
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
index 76f6eb7..242c1a4 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
@@ -37,7 +37,10 @@
public abstract class FileDiffOutput implements Serializable {
private static final long serialVersionUID = 1L;
- /** The 20 bytes SHA-1 object ID of the old git commit used in the diff. */
+ /**
+ * The 20 bytes SHA-1 object ID of the old git commit used in the diff, or {@link
+ * ObjectId#zeroId()} if {@link #newCommitId()} was a root commit.
+ */
public abstract ObjectId oldCommitId();
/** The 20 bytes SHA-1 object ID of the new git commit used in the diff. */
diff --git a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
index a502a46..2f23c8c 100644
--- a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
+++ b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
@@ -34,6 +34,7 @@
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.patch.FileHeader;
/**
@@ -120,7 +121,10 @@
/** The file name at the new git tree identified by {@link #newId()} */
public abstract Optional<String> newPath();
- /** The 20 bytes SHA-1 object ID of the old git tree of the diff. */
+ /**
+ * The 20 bytes SHA-1 object ID of the old git tree of the diff, or {@link ObjectId#zeroId()} if
+ * {@link #newId()} was a root git tree (i.e. has no parents).
+ */
public abstract AbbreviatedObjectId oldId();
/** The 20 bytes SHA-1 object ID of the new git tree of the diff. */
diff --git a/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java b/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
index 5d8b99a..0383cdc 100644
--- a/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
+++ b/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
@@ -70,7 +70,7 @@
private static List<SubmitRequirementResult> createFromCustomSubmitRecord(
SubmitRecord record, ObjectId psCommitId) {
- if (record.labels.isEmpty()) {
+ if (record.labels == null || record.labels.isEmpty()) {
SubmitRequirement sr =
SubmitRequirement.builder()
.setName(record.ruleName)
diff --git a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
index b7f8b45..1d67009 100644
--- a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
+++ b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
@@ -31,6 +31,7 @@
import com.google.gerrit.index.query.InternalQuery;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.index.account.AccountField;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.inject.Inject;
@@ -46,12 +47,16 @@
public class InternalAccountQuery extends InternalQuery<AccountState, InternalAccountQuery> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
@Inject
InternalAccountQuery(
AccountQueryProcessor queryProcessor,
AccountIndexCollection indexes,
- IndexConfig indexConfig) {
+ IndexConfig indexConfig,
+ ExternalIdKeyFactory externalIdKeyFactory) {
super(queryProcessor, indexes, indexConfig);
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
public List<AccountState> byDefault(String query, boolean canSeeSecondaryEmails) {
@@ -59,7 +64,7 @@
}
public List<AccountState> byExternalId(String scheme, String id) {
- return byExternalId(ExternalId.Key.create(scheme, id));
+ return byExternalId(externalIdKeyFactory.create(scheme, id));
}
public List<AccountState> byExternalId(ExternalId.Key externalId) {
diff --git a/java/com/google/gerrit/server/restapi/account/CreateAccount.java b/java/com/google/gerrit/server/restapi/account/CreateAccount.java
index baa2951..b4946c4 100644
--- a/java/com/google/gerrit/server/restapi/account/CreateAccount.java
+++ b/java/com/google/gerrit/server/restapi/account/CreateAccount.java
@@ -44,6 +44,7 @@
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.group.GroupResolver;
import com.google.gerrit.server.group.db.GroupDelta;
@@ -85,6 +86,7 @@
private final Provider<GroupsUpdate> groupsUpdate;
private final OutgoingEmailValidator validator;
private final AuthConfig authConfig;
+ private final ExternalIdFactory externalIdFactory;
@Inject
CreateAccount(
@@ -97,7 +99,8 @@
PluginSetContext<AccountExternalIdCreator> externalIdCreators,
@UserInitiated Provider<GroupsUpdate> groupsUpdate,
OutgoingEmailValidator validator,
- AuthConfig authConfig) {
+ AuthConfig authConfig,
+ ExternalIdFactory externalIdFactory) {
this.seq = seq;
this.groupResolver = groupResolver;
this.authorizedKeys = authorizedKeys;
@@ -108,6 +111,7 @@
this.groupsUpdate = groupsUpdate;
this.validator = validator;
this.authConfig = authConfig;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -142,10 +146,10 @@
if (!validator.isValid(input.email)) {
throw new BadRequestException("invalid email address");
}
- extIds.add(ExternalId.createEmail(accountId, input.email));
+ extIds.add(externalIdFactory.createEmail(accountId, input.email));
}
- extIds.add(ExternalId.createUsername(username, accountId, input.httpPassword));
+ extIds.add(externalIdFactory.createUsername(username, accountId, input.httpPassword));
externalIdCreators.runEach(c -> extIds.addAll(c.create(accountId, username, input.email)));
try {
diff --git a/java/com/google/gerrit/server/restapi/account/CreateEmail.java b/java/com/google/gerrit/server/restapi/account/CreateEmail.java
index 6ee4539..70fbb26 100644
--- a/java/com/google/gerrit/server/restapi/account/CreateEmail.java
+++ b/java/com/google/gerrit/server/restapi/account/CreateEmail.java
@@ -83,6 +83,7 @@
private final OutgoingEmailValidator validator;
private final MessageIdGenerator messageIdGenerator;
private final boolean isDevMode;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
CreateEmail(
@@ -94,7 +95,8 @@
RegisterNewEmailSender.Factory registerNewEmailFactory,
PutPreferred putPreferred,
OutgoingEmailValidator validator,
- MessageIdGenerator messageIdGenerator) {
+ MessageIdGenerator messageIdGenerator,
+ AuthRequest.Factory authRequestFactory) {
this.self = self;
this.realm = realm;
this.permissionBackend = permissionBackend;
@@ -104,6 +106,7 @@
this.validator = validator;
this.isDevMode = authConfig.getAuthType() == DEVELOPMENT_BECOME_ANY_ACCOUNT;
this.messageIdGenerator = messageIdGenerator;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -151,7 +154,7 @@
logger.atWarning().log("skipping email validation in developer mode");
}
try {
- accountManager.link(user.getAccountId(), AuthRequest.forEmail(email));
+ accountManager.link(user.getAccountId(), authRequestFactory.createForEmail(email));
} catch (AccountException e) {
throw new ResourceConflictException(e.getMessage());
}
diff --git a/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java b/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
index 445a5d6..e099a70 100644
--- a/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
+++ b/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
@@ -18,6 +18,8 @@
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
@@ -29,6 +31,7 @@
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -56,17 +59,20 @@
private final AccountManager accountManager;
private final ExternalIds externalIds;
private final Provider<CurrentUser> self;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
DeleteExternalIds(
PermissionBackend permissionBackend,
AccountManager accountManager,
ExternalIds externalIds,
- Provider<CurrentUser> self) {
+ Provider<CurrentUser> self,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.permissionBackend = permissionBackend;
this.accountManager = accountManager;
this.externalIds = externalIds;
this.self = self;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -87,15 +93,24 @@
List<ExternalId> toDelete = new ArrayList<>();
Optional<ExternalId.Key> last = resource.getUser().getLastLoginExternalIdKey();
for (String externalIdStr : extIds) {
- ExternalId id = externalIdMap.get(ExternalId.Key.parse(externalIdStr));
+ ExternalId id = externalIdMap.get(externalIdKeyFactory.parse(externalIdStr));
if (id == null) {
throw new UnprocessableEntityException(
String.format("External id %s does not exist", externalIdStr));
}
- if ((!id.isScheme(SCHEME_USERNAME))
- && (!last.isPresent() || (!last.get().equals(id.key())))) {
+ if (!last.isPresent() || !last.get().equals(id.key())) {
+ if (id.isScheme(SCHEME_USERNAME)) {
+ if (self.get().hasSameAccountId(resource.getUser())) {
+ throw new AuthException("User cannot delete its own externalId in 'username:' scheme");
+ }
+ permissionBackend
+ .currentUser()
+ .checkAny(
+ ImmutableSet.of(
+ GlobalPermission.ADMINISTRATE_SERVER, GlobalPermission.MAINTAIN_SERVER));
+ }
toDelete.add(id);
} else {
throw new ResourceConflictException(
diff --git a/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java b/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java
index 2427def..9361e27 100644
--- a/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java
+++ b/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java
@@ -34,6 +34,8 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.mail.send.HttpPasswordUpdateSender;
import com.google.gerrit.server.permissions.GlobalPermission;
@@ -77,6 +79,8 @@
private final ExternalIds externalIds;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
PutHttpPassword(
@@ -84,12 +88,16 @@
PermissionBackend permissionBackend,
ExternalIds externalIds,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider,
- HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory) {
+ HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.self = self;
this.permissionBackend = permissionBackend;
this.externalIds = externalIds;
this.accountsUpdateProvider = accountsUpdateProvider;
this.httpPasswordUpdateSenderFactory = httpPasswordUpdateSenderFactory;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -125,7 +133,7 @@
String userName =
user.getUserName().orElseThrow(() -> new ResourceConflictException("username must be set"));
Optional<ExternalId> optionalExtId =
- externalIds.get(ExternalId.Key.create(SCHEME_USERNAME, userName));
+ externalIds.get(externalIdKeyFactory.create(SCHEME_USERNAME, userName));
ExternalId extId = optionalExtId.orElseThrow(ResourceNotFoundException::new);
accountsUpdateProvider
.get()
@@ -134,7 +142,7 @@
extId.accountId(),
u ->
u.updateExternalId(
- ExternalId.createWithPassword(
+ externalIdFactory.createWithPassword(
extId.key(), extId.accountId(), extId.email(), newPassword)));
try {
diff --git a/java/com/google/gerrit/server/restapi/account/PutPreferred.java b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
index 32b5ff2..aee0b78 100644
--- a/java/com/google/gerrit/server/restapi/account/PutPreferred.java
+++ b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
@@ -30,6 +30,7 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -62,17 +63,20 @@
private final PermissionBackend permissionBackend;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final ExternalIds externalIds;
+ private final ExternalIdFactory externalIdFactory;
@Inject
PutPreferred(
Provider<CurrentUser> self,
PermissionBackend permissionBackend,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider,
- ExternalIds externalIds) {
+ ExternalIds externalIds,
+ ExternalIdFactory externalIdFactory) {
this.self = self;
this.permissionBackend = permissionBackend;
this.accountsUpdateProvider = accountsUpdateProvider;
this.externalIds = externalIds;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -137,7 +141,8 @@
}
// claim the email now
- u.addExternalId(ExternalId.createEmail(a.account().id(), preferredEmail));
+ u.addExternalId(
+ externalIdFactory.createEmail(a.account().id(), preferredEmail));
matchingEmail = preferredEmail;
} else {
// Realm says that the email doesn't belong to the user. This can only happen as
diff --git a/java/com/google/gerrit/server/restapi/account/PutUsername.java b/java/com/google/gerrit/server/restapi/account/PutUsername.java
index 05bf1fd..f295389 100644
--- a/java/com/google/gerrit/server/restapi/account/PutUsername.java
+++ b/java/com/google/gerrit/server/restapi/account/PutUsername.java
@@ -34,6 +34,8 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -65,6 +67,8 @@
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final SshKeyCache sshKeyCache;
private final Realm realm;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
PutUsername(
@@ -73,13 +77,17 @@
ExternalIds externalIds,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider,
SshKeyCache sshKeyCache,
- Realm realm) {
+ Realm realm,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.self = self;
this.permissionBackend = permissionBackend;
this.externalIds = externalIds;
this.accountsUpdateProvider = accountsUpdateProvider;
this.sshKeyCache = sshKeyCache;
this.realm = realm;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -107,14 +115,14 @@
throw new UnprocessableEntityException("invalid username");
}
- ExternalId.Key key = ExternalId.Key.create(SCHEME_USERNAME, input.username);
+ ExternalId.Key key = externalIdKeyFactory.create(SCHEME_USERNAME, input.username);
try {
accountsUpdateProvider
.get()
.update(
"Set Username via API",
accountId,
- u -> u.addExternalId(ExternalId.create(key, accountId, null, null)));
+ u -> u.addExternalId(externalIdFactory.create(key, accountId, null, null)));
} catch (DuplicateKeyException dupeErr) {
// If we are using this identity, don't report the exception.
Optional<ExternalId> other = externalIds.get(key);
diff --git a/java/com/google/gerrit/server/restapi/group/AddMembers.java b/java/com/google/gerrit/server/restapi/group/AddMembers.java
index f44abec..4cb2f47 100644
--- a/java/com/google/gerrit/server/restapi/group/AddMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/AddMembers.java
@@ -94,6 +94,7 @@
private final AccountCache accountCache;
private final AccountLoader.Factory infoFactory;
private final Provider<GroupsUpdate> groupsUpdateProvider;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
AddMembers(
@@ -102,13 +103,15 @@
AccountResolver accountResolver,
AccountCache accountCache,
AccountLoader.Factory infoFactory,
- @UserInitiated Provider<GroupsUpdate> groupsUpdateProvider) {
+ @UserInitiated Provider<GroupsUpdate> groupsUpdateProvider,
+ AuthRequest.Factory authRequestFactory) {
this.accountManager = accountManager;
this.authType = authConfig.getAuthType();
this.accountResolver = accountResolver;
this.accountCache = accountCache;
this.infoFactory = infoFactory;
this.groupsUpdateProvider = groupsUpdateProvider;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -190,7 +193,7 @@
}
try {
- AuthRequest req = AuthRequest.forUser(user);
+ AuthRequest req = authRequestFactory.createForUser(user);
req.setSkipAuthentication(true);
return accountCache
.get(accountManager.authenticate(req).getAccountId())
diff --git a/java/com/google/gerrit/server/rules/PrologEnvironment.java b/java/com/google/gerrit/server/rules/PrologEnvironment.java
index 7d626da..bc0bb1a 100644
--- a/java/com/google/gerrit/server/rules/PrologEnvironment.java
+++ b/java/com/google/gerrit/server/rules/PrologEnvironment.java
@@ -22,7 +22,7 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.project.ProjectCache;
@@ -173,7 +173,7 @@
private final PermissionBackend permissionBackend;
private final GitRepositoryManager repositoryManager;
private final PluginConfigFactory pluginConfigFactory;
- private final PatchListCache patchListCache;
+ private final DiffOperations diffOperations;
private final PatchSetInfoFactory patchSetInfoFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final Provider<AnonymousUser> anonymousUser;
@@ -188,7 +188,7 @@
PermissionBackend permissionBackend,
GitRepositoryManager repositoryManager,
PluginConfigFactory pluginConfigFactory,
- PatchListCache patchListCache,
+ DiffOperations diffOperations,
PatchSetInfoFactory patchSetInfoFactory,
IdentifiedUser.GenericFactory userFactory,
Provider<AnonymousUser> anonymousUser,
@@ -199,7 +199,7 @@
this.permissionBackend = permissionBackend;
this.repositoryManager = repositoryManager;
this.pluginConfigFactory = pluginConfigFactory;
- this.patchListCache = patchListCache;
+ this.diffOperations = diffOperations;
this.patchSetInfoFactory = patchSetInfoFactory;
this.userFactory = userFactory;
this.anonymousUser = anonymousUser;
@@ -237,8 +237,8 @@
return pluginConfigFactory;
}
- public PatchListCache getPatchListCache() {
- return patchListCache;
+ public DiffOperations getDiffOperations() {
+ return diffOperations;
}
public PatchSetInfoFactory getPatchSetInfoFactory() {
diff --git a/java/com/google/gerrit/server/rules/StoredValues.java b/java/com/google/gerrit/server/rules/StoredValues.java
index 1e08a24..1d10c1f 100644
--- a/java/com/google/gerrit/server/rules/StoredValues.java
+++ b/java/com/google/gerrit/server/rules/StoredValues.java
@@ -21,7 +21,6 @@
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PatchSetUtil;
@@ -30,10 +29,9 @@
import com.google.gerrit.server.account.Emails;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.DiffOperations;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
@@ -87,24 +85,27 @@
}
};
- public static final StoredValue<PatchList> PATCH_LIST =
- new StoredValue<PatchList>() {
+ public static final StoredValue<Map<String, FileDiffOutput>> DIFF_LIST =
+ new StoredValue<Map<String, FileDiffOutput>>() {
@Override
- public PatchList createValue(Prolog engine) {
+ public Map<String, FileDiffOutput> createValue(Prolog engine) {
PrologEnvironment env = (PrologEnvironment) engine.control;
PatchSet ps = getPatchSet(engine);
- PatchListCache plCache = env.getArgs().getPatchListCache();
+ DiffOperations diffOperations = env.getArgs().getDiffOperations();
Change change = getChange(engine);
Project.NameKey project = change.getProject();
- Whitespace ws = Whitespace.IGNORE_NONE;
- PatchListKey plKey = PatchListKey.againstDefaultBase(ps.commitId(), ws);
- PatchList patchList;
+ Map<String, FileDiffOutput> diffList;
try {
- patchList = plCache.get(plKey, project);
- } catch (PatchListNotAvailableException e) {
- throw new SystemException(String.format("Cannot create %s: %s", plKey, e.getMessage()));
+ diffList =
+ diffOperations.listModifiedFilesAgainstParent(
+ project, ps.commitId(), /* parentNum= */ 0);
+ } catch (DiffNotAvailableException e) {
+ throw new SystemException(
+ String.format(
+ "Cannot create modified files for project %s, commit Id %s: %s",
+ project, ps.commitId(), e.getMessage()));
}
- return patchList;
+ return diffList;
}
};
diff --git a/java/com/google/gerrit/server/update/RetryableAction.java b/java/com/google/gerrit/server/update/RetryableAction.java
index fbb643e..f79a849 100644
--- a/java/com/google/gerrit/server/update/RetryableAction.java
+++ b/java/com/google/gerrit/server/update/RetryableAction.java
@@ -57,6 +57,7 @@
PLUGIN_UPDATE,
REST_READ_REQUEST,
REST_WRITE_REQUEST,
+ SEND_EMAIL,
}
@FunctionalInterface
diff --git a/java/com/google/gerrit/sshd/SshKeyCacheImpl.java b/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
index d5f0ee8..628a050 100644
--- a/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
+++ b/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
@@ -22,6 +22,7 @@
import com.google.gerrit.server.account.AccountSshKey;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.logging.Metadata;
@@ -97,11 +98,16 @@
static class Loader extends CacheLoader<String, Iterable<SshKeyCacheEntry>> {
private final ExternalIds externalIds;
private final VersionedAuthorizedKeys.Accessor authorizedKeys;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
- Loader(ExternalIds externalIds, VersionedAuthorizedKeys.Accessor authorizedKeys) {
+ Loader(
+ ExternalIds externalIds,
+ VersionedAuthorizedKeys.Accessor authorizedKeys,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.externalIds = externalIds;
this.authorizedKeys = authorizedKeys;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -111,7 +117,7 @@
"Loading SSH keys for account with username",
Metadata.builder().username(username).build())) {
Optional<ExternalId> user =
- externalIds.get(ExternalId.Key.create(SCHEME_USERNAME, username));
+ externalIds.get(externalIdKeyFactory.create(SCHEME_USERNAME, username));
if (!user.isPresent()) {
return NO_SUCH_USER;
}
diff --git a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index 43a1670..0c286ca 100644
--- a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -15,6 +15,7 @@
package com.google.gerrit.sshd.commands;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
import com.google.common.base.Strings;
import com.google.gerrit.common.RawInputUtil;
@@ -36,6 +37,7 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountSshKey;
+import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -43,6 +45,7 @@
import com.google.gerrit.server.restapi.account.CreateEmail;
import com.google.gerrit.server.restapi.account.DeleteActive;
import com.google.gerrit.server.restapi.account.DeleteEmail;
+import com.google.gerrit.server.restapi.account.DeleteExternalIds;
import com.google.gerrit.server.restapi.account.DeleteSshKey;
import com.google.gerrit.server.restapi.account.GetEmails;
import com.google.gerrit.server.restapi.account.GetSshKeys;
@@ -122,10 +125,18 @@
@Option(name = "--generate-http-password", usage = "generate a new HTTP password for the account")
private boolean generateHttpPassword;
+ @Option(
+ name = "--delete-external-id",
+ metaVar = "EXTERNALID",
+ usage = "external id to delete from the account")
+ private List<String> externalIdsToDelete = new ArrayList<>();
+
@Inject private IdentifiedUser.GenericFactory genericUserFactory;
@Inject private CreateEmail createEmail;
+ @Inject private DeleteExternalIds deleteExternalIds;
+
@Inject private GetEmails getEmails;
@Inject private DeleteEmail deleteEmail;
@@ -150,6 +161,8 @@
@Inject private Provider<CurrentUser> userProvider;
+ @Inject private ExternalIds externalIds;
+
private AccountResource rsrc;
@Override
@@ -210,6 +223,9 @@
"--preferred-email and --delete-email options are mutually "
+ "exclusive for the same email address.");
}
+ if (externalIdsToDelete.contains("ALL")) {
+ externalIdsToDelete = Collections.singletonList("ALL");
+ }
}
private void setAccount() throws Failure {
@@ -265,6 +281,10 @@
if (!deleteSshKeys.isEmpty()) {
deleteSshKeys(deleteSshKeys);
}
+
+ for (String externalId : externalIdsToDelete) {
+ deleteExternalId(externalId);
+ }
} catch (RestApiException e) {
throw die(e.getMessage());
} catch (Exception e) {
@@ -355,4 +375,21 @@
}
return sshKeys;
}
+
+ private void deleteExternalId(String externalId)
+ throws IOException, RestApiException, ConfigInvalidException, PermissionBackendException {
+ List<String> ids;
+ if (externalId.equals("ALL")) {
+ ids =
+ externalIds.byAccount(rsrc.getUser().getAccountId()).stream()
+ .map(e -> e.key().get())
+ .collect(toList());
+ if (ids.isEmpty()) {
+ throw new ResourceNotFoundException("Account has no external Ids");
+ }
+ } else {
+ ids = Collections.singletonList(externalId);
+ }
+ deleteExternalIds.apply(rsrc, ids);
+ }
}
diff --git a/java/com/google/gerrit/testing/InMemoryTestEnvironment.java b/java/com/google/gerrit/testing/InMemoryTestEnvironment.java
index 44d5cea..77df46c 100644
--- a/java/com/google/gerrit/testing/InMemoryTestEnvironment.java
+++ b/java/com/google/gerrit/testing/InMemoryTestEnvironment.java
@@ -46,6 +46,7 @@
@Inject private IdentifiedUser.GenericFactory userFactory;
@Inject private SchemaCreator schemaCreator;
@Inject private ThreadLocalRequestContext requestContext;
+ @Inject private AuthRequest.Factory authRequestFactory;
private LifecycleManager lifecycle;
@@ -99,7 +100,8 @@
schemaCreator.create();
// The first user is added to the "Administrators" group. See AccountManager#create().
- setApiUser(accountManager.authenticate(AuthRequest.forUser("admin")).getAccountId());
+ setApiUser(
+ accountManager.authenticate(authRequestFactory.createForUser("admin")).getAccountId());
// Inject target members after setting API user, so it can @Inject request-scoped objects if it
// wants.
diff --git a/java/gerrit/BUILD b/java/gerrit/BUILD
index db831b7..fea2696 100644
--- a/java/gerrit/BUILD
+++ b/java/gerrit/BUILD
@@ -5,6 +5,7 @@
srcs = glob(["**/*.java"]),
visibility = ["//visibility:public"],
deps = [
+ "//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/entities",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/server",
diff --git a/java/gerrit/PRED_commit_edits_2.java b/java/gerrit/PRED_commit_edits_2.java
index 12e7086..6083010 100644
--- a/java/gerrit/PRED_commit_edits_2.java
+++ b/java/gerrit/PRED_commit_edits_2.java
@@ -14,10 +14,13 @@
package gerrit;
+import com.google.common.collect.Iterables;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gerrit.server.patch.FilePathAdapter;
import com.google.gerrit.server.patch.Text;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
+import com.google.gerrit.server.patch.filediff.TaggedEdit;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
import com.googlecode.prolog_cafe.exceptions.JavaException;
@@ -31,7 +34,9 @@
import com.googlecode.prolog_cafe.lang.VariableTerm;
import java.io.IOException;
import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -40,7 +45,6 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
@@ -69,27 +73,26 @@
Pattern fileRegex = getRegexParameter(a1);
Pattern editRegex = getRegexParameter(a2);
- PatchList pl = StoredValues.PATCH_LIST.get(engine);
+ Map<String, FileDiffOutput> modifiedFiles = StoredValues.DIFF_LIST.get(engine);
+ FileDiffOutput firstDiff = Iterables.getFirst(modifiedFiles.values(), /* defaultValue= */ null);
+ if (firstDiff == null) {
+ // No available diffs. We cannot identify old and new commit IDs.
+ engine.fail();
+ }
Repository repo = StoredValues.REPOSITORY.get(engine);
try (ObjectReader reader = repo.newObjectReader();
RevWalk rw = new RevWalk(reader)) {
- final RevTree aTree;
- final RevTree bTree;
- final RevCommit bCommit = rw.parseCommit(pl.getNewId());
+ final RevTree aTree =
+ firstDiff.oldCommitId().equals(ObjectId.zeroId())
+ ? null
+ : rw.parseTree(firstDiff.oldCommitId());
+ final RevTree bTree = rw.parseCommit(firstDiff.newCommitId()).getTree();
- if (pl.getOldId() != null) {
- aTree = rw.parseTree(pl.getOldId());
- } else {
- // Octopus merge with unknown automatic merge result, since the
- // web UI returns no files to match against, just fail.
- return engine.fail();
- }
- bTree = bCommit.getTree();
-
- for (PatchListEntry entry : pl.getPatches()) {
- String newName = entry.getNewName();
- String oldName = entry.getOldName();
+ for (FileDiffOutput entry : modifiedFiles.values()) {
+ String newName =
+ FilePathAdapter.getNewPath(entry.oldPath(), entry.newPath(), entry.changeType());
+ String oldName = FilePathAdapter.getOldPath(entry.oldPath(), entry.changeType());
if (Patch.isMagic(newName)) {
continue;
@@ -97,7 +100,8 @@
if (fileRegex.matcher(newName).find()
|| (oldName != null && fileRegex.matcher(oldName).find())) {
- List<Edit> edits = entry.getEdits();
+ List<Edit> edits =
+ entry.edits().stream().map(TaggedEdit::jgitEdit).collect(Collectors.toList());
if (edits.isEmpty()) {
continue;
}
@@ -141,10 +145,10 @@
return Pattern.compile(term.name(), Pattern.MULTILINE);
}
- private Text load(ObjectId tree, String path, ObjectReader reader)
+ private Text load(@Nullable ObjectId tree, String path, ObjectReader reader)
throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
IOException {
- if (path == null) {
+ if (tree == null || path == null) {
return Text.EMPTY;
}
final TreeWalk tw = TreeWalk.forPath(reader, path, tree);
diff --git a/java/gerrit/PRED_commit_stats_3.java b/java/gerrit/PRED_commit_stats_3.java
index 286bc2c..82fad3d 100644
--- a/java/gerrit/PRED_commit_stats_3.java
+++ b/java/gerrit/PRED_commit_stats_3.java
@@ -15,8 +15,7 @@
package gerrit;
import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
@@ -24,7 +23,8 @@
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.Term;
-import java.util.List;
+import java.util.Collection;
+import java.util.Map;
/**
* Exports basic commit statistics.
@@ -49,25 +49,30 @@
Term a2 = arg2.dereference();
Term a3 = arg3.dereference();
- PatchList pl = StoredValues.PATCH_LIST.get(engine);
+ Map<String, FileDiffOutput> modifiedFiles = StoredValues.DIFF_LIST.get(engine);
// Account for magic files
if (!a1.unify(
- new IntegerTerm(pl.getPatches().size() - countMagicFiles(pl.getPatches())), engine.trail)) {
+ new IntegerTerm(modifiedFiles.size() - countMagicFiles(modifiedFiles.values())),
+ engine.trail)) {
return engine.fail();
}
- if (!a2.unify(new IntegerTerm(pl.getInsertions()), engine.trail)) {
+ Integer insertions =
+ modifiedFiles.values().stream().map(FileDiffOutput::insertions).reduce(0, Integer::sum);
+ Integer deletions =
+ modifiedFiles.values().stream().map(FileDiffOutput::deletions).reduce(0, Integer::sum);
+ if (!a2.unify(new IntegerTerm(insertions), engine.trail)) {
return engine.fail();
}
- if (!a3.unify(new IntegerTerm(pl.getDeletions()), engine.trail)) {
+ if (!a3.unify(new IntegerTerm(deletions), engine.trail)) {
return engine.fail();
}
return cont;
}
- private int countMagicFiles(List<PatchListEntry> entries) {
+ private int countMagicFiles(Collection<FileDiffOutput> entries) {
int count = 0;
- for (PatchListEntry e : entries) {
- if (Patch.isMagic(e.getNewName())) {
+ for (FileDiffOutput e : entries) {
+ if (e.newPath().isPresent() && Patch.isMagic(e.newPath().get())) {
count++;
}
}
diff --git a/java/gerrit/PRED_files_1.java b/java/gerrit/PRED_files_1.java
index ac45449..dbf96da 100644
--- a/java/gerrit/PRED_files_1.java
+++ b/java/gerrit/PRED_files_1.java
@@ -15,7 +15,8 @@
package gerrit;
import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gerrit.server.patch.FilePathAdapter;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.ListTerm;
@@ -26,8 +27,8 @@
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
import java.io.IOException;
+import java.util.Collection;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.FileMode;
@@ -54,17 +55,20 @@
try (RevWalk revWalk = new RevWalk(StoredValues.REPOSITORY.get(engine))) {
RevCommit commit = revWalk.parseCommit(StoredValues.getPatchSet(engine).commitId());
- List<PatchListEntry> patches = StoredValues.PATCH_LIST.get(engine).getPatches();
+ Collection<FileDiffOutput> modifiedFiles = StoredValues.DIFF_LIST.get(engine).values();
Set<String> submodules =
- getAllSubmodulePaths(StoredValues.REPOSITORY.get(engine), commit, patches);
- for (PatchListEntry entry : patches) {
- if (Patch.isMagic(entry.getNewName())) {
+ getAllSubmodulePaths(StoredValues.REPOSITORY.get(engine), commit, modifiedFiles);
+ for (FileDiffOutput fileDiff : modifiedFiles) {
+ if (fileDiff.newPath().isPresent() && Patch.isMagic(fileDiff.newPath().get())) {
continue;
}
- SymbolTerm fileNameTerm = SymbolTerm.create(entry.getNewName());
- SymbolTerm changeType = SymbolTerm.create(entry.getChangeType().getCode());
+ String newPath =
+ FilePathAdapter.getNewPath(
+ fileDiff.oldPath(), fileDiff.newPath(), fileDiff.changeType());
+ SymbolTerm fileNameTerm = SymbolTerm.create(newPath);
+ SymbolTerm changeType = SymbolTerm.create(fileDiff.changeType().getCode());
SymbolTerm fileType;
- if (submodules.contains(entry.getNewName())) {
+ if (submodules.contains(newPath)) {
fileType = SymbolTerm.create("SUBMODULE");
} else {
fileType = SymbolTerm.create("REGULAR");
@@ -83,14 +87,14 @@
/** Returns the paths for all {@code GITLINK} files. */
private static Set<String> getAllSubmodulePaths(
- Repository repository, RevCommit commit, List<PatchListEntry> patches)
+ Repository repository, RevCommit commit, Collection<FileDiffOutput> modifiedFiles)
throws PrologException, IOException {
Set<String> submodules = new HashSet<>();
try (TreeWalk treeWalk = new TreeWalk(repository)) {
treeWalk.addTree(commit.getTree());
Set<String> allPaths =
- patches.stream()
- .map(PatchListEntry::getNewName)
+ modifiedFiles.stream()
+ .map(f -> FilePathAdapter.getNewPath(f.oldPath(), f.newPath(), f.changeType()))
.filter(f -> !Patch.isMagic(f))
.collect(Collectors.toSet());
treeWalk.setFilter(PathFilterGroup.createFromStrings(allPaths));
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 8982a2b..1da2176c 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -131,6 +131,8 @@
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
@@ -229,6 +231,8 @@
@Inject private VersionedAuthorizedKeys.Accessor authorizedKeys;
@Inject private ExtensionRegistry extensionRegistry;
@Inject private PluginSetContext<ExceptionHook> exceptionHooks;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
@Inject protected Emails emails;
@@ -372,8 +376,8 @@
accountIndexedCounter.assertReindexOf(accountId, 1);
assertThat(externalIds.byAccount(accountId))
.containsExactly(
- ExternalId.createUsername(input.username, accountId, null),
- ExternalId.createEmail(accountId, input.email));
+ externalIdFactory.createUsername(input.username, accountId, null),
+ externalIdFactory.createEmail(accountId, input.email));
}
}
@@ -426,7 +430,7 @@
public void createAtomically() throws Exception {
Account.Id accountId = Account.id(seq.nextAccountId());
String fullName = "Foo";
- ExternalId extId = ExternalId.createEmail(accountId, "foo@example.com");
+ ExternalId extId = externalIdFactory.createEmail(accountId, "foo@example.com");
AccountState accountState =
accountsUpdateProvider
.get()
@@ -1278,11 +1282,11 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(extId1), admin.id(), email))
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId1), admin.id(), email))
.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(extId2), admin.id(), email)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId2), admin.id(), email)));
accountIndexedCounter.assertReindexOf(admin);
assertThat(
gApi.accounts().self().getExternalIds().stream()
@@ -1318,8 +1322,8 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(ldapExternalId), admin.id(), ldapEmail)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(ldapExternalId), admin.id(), ldapEmail)));
assertThat(
gApi.accounts().self().getExternalIds().stream().map(e -> e.identity).collect(toSet()))
.contains(ldapExternalId);
@@ -1353,11 +1357,13 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(nonLdapExternalId), admin.id(), nonLdapEMail))
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(nonLdapExternalId),
+ admin.id(),
+ nonLdapEMail))
.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(ldapExternalId), admin.id(), ldapEmail)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(ldapExternalId), admin.id(), ldapEmail)));
assertThat(
gApi.accounts().self().getExternalIds().stream().map(e -> e.identity).collect(toSet()))
.containsAtLeast(ldapExternalId, nonLdapExternalId);
@@ -1420,8 +1426,8 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse("foo:bar"), admin.id(), email)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), email)));
assertEmail(emails.getAccountFor(email), admin);
// wrong case doesn't match
@@ -1737,7 +1743,7 @@
.update(
"Add External ID",
user.id(),
- u -> u.addExternalId(ExternalId.create("foo", "myId", user.id())));
+ u -> u.addExternalId(externalIdFactory.create("foo", "myId", user.id())));
accountIndexedCounter.assertReindexOf(user);
TestKey key = validKeyWithSecondUserId();
@@ -2040,7 +2046,7 @@
.update(
"Delete External ID",
account.id(),
- u -> u.deleteExternalId(ExternalId.createEmail(account.id(), email)));
+ u -> u.deleteExternalId(externalIdFactory.createEmail(account.id(), email)));
expectedProblems.add(
new ConsistencyProblemInfo(
ConsistencyProblemInfo.Status.ERROR,
@@ -2375,7 +2381,7 @@
.update();
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId extIdA1 = ExternalId.create("foo", "A-1", accountId);
+ ExternalId extIdA1 = externalIdFactory.create("foo", "A-1", accountId);
accountsUpdateProvider
.get()
.insert("Create Test Account", accountId, u -> u.addExternalId(extIdA1));
@@ -2383,7 +2389,7 @@
AtomicInteger bgCounterA1 = new AtomicInteger(0);
AtomicInteger bgCounterA2 = new AtomicInteger(0);
PersonIdent ident = serverIdent.get();
- ExternalId extIdA2 = ExternalId.create("foo", "A-2", accountId);
+ ExternalId extIdA2 = externalIdFactory.create("foo", "A-2", accountId);
AccountsUpdate update =
new AccountsUpdate(
repoManager,
@@ -2424,8 +2430,8 @@
.collect(toSet()))
.containsExactly(extIdA1.key().get());
- ExternalId extIdB1 = ExternalId.create("foo", "B-1", accountId);
- ExternalId extIdB2 = ExternalId.create("foo", "B-2", accountId);
+ ExternalId extIdB1 = externalIdFactory.create("foo", "B-1", accountId);
+ ExternalId extIdB2 = externalIdFactory.create("foo", "B-2", accountId);
Optional<AccountState> updatedAccount =
update.update(
"Update External ID",
@@ -2488,23 +2494,24 @@
// Manually inserting/updating/deleting an external ID of the user makes the index document
// stale.
try (Repository repo = repoManager.openRepository(allUsers)) {
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
- ExternalId.Key key = ExternalId.Key.create("foo", "foo");
- extIdNotes.insert(ExternalId.create(key, accountId));
+ ExternalId.Key key = externalIdKeyFactory.create("foo", "foo");
+ extIdNotes.insert(externalIdFactory.create(key, accountId));
try (MetaDataUpdate update = metaDataUpdateFactory.create(allUsers)) {
extIdNotes.commit(update);
}
assertStaleAccountAndReindex(accountId);
- extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
- extIdNotes.upsert(ExternalId.createWithEmail(key, accountId, "foo@example.com"));
+ extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
+ extIdNotes.upsert(externalIdFactory.createWithEmail(key, accountId, "foo@example.com"));
try (MetaDataUpdate update = metaDataUpdateFactory.create(allUsers)) {
extIdNotes.commit(update);
}
assertStaleAccountAndReindex(accountId);
- extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
+ extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
extIdNotes.delete(accountId, key);
try (MetaDataUpdate update = metaDataUpdateFactory.create(allUsers)) {
extIdNotes.commit(update);
@@ -2765,9 +2772,11 @@
String extId1String = "foo:bar";
String extId2String = "foo:baz";
ExternalId extId1 =
- ExternalId.createWithEmail(ExternalId.Key.parse(extId1String), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId1String), admin.id(), "1@foo.com");
ExternalId extId2 =
- ExternalId.createWithEmail(ExternalId.Key.parse(extId2String), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId2String), user.id(), "2@foo.com");
ObjectId revBefore;
try (Repository repo = repoManager.openRepository(allUsers)) {
@@ -2807,9 +2816,11 @@
@Test
public void externalIdBatchUpdates_fail_sameAccount() {
ExternalId extId1 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
ExternalId extId2 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:baz"), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:baz"), user.id(), "2@foo.com");
AccountsUpdate.UpdateArguments ua1 =
new AccountsUpdate.UpdateArguments(
@@ -2828,9 +2839,11 @@
@Test
public void externalIdBatchUpdates_fail_duplicateKey() {
ExternalId extIdAdmin =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
ExternalId extIdUser =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), user.id(), "2@foo.com");
AccountsUpdate.UpdateArguments ua1 =
new AccountsUpdate.UpdateArguments(
@@ -2848,9 +2861,11 @@
@Test
public void externalIdBatchUpdates_commitMsg_multipleAccounts() throws Exception {
ExternalId extId1 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
ExternalId extId2 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:baz"), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:baz"), user.id(), "2@foo.com");
AccountsUpdate.UpdateArguments ua1 =
new AccountsUpdate.UpdateArguments(
@@ -2872,7 +2887,8 @@
@Test
public void externalIdBatchUpdates_commitMsg_singleAccount() throws Exception {
ExternalId extId =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
accountsUpdateProvider.get().update("foobar", admin.id(), (a, u) -> u.addExternalId(extId));
@@ -3029,7 +3045,7 @@
account.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(name("test"), email, account.id(), email)));
+ externalIdFactory.createWithEmail(name("test"), email, account.id(), email)));
accountIndexedCounter.assertReindexOf(account);
requestScopeOperations.setApiUser(account.id());
}
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
index b41a2f3..7e23f0e 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
@@ -37,6 +37,8 @@
import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.account.SetInactiveFlag;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -62,14 +64,17 @@
@Inject private SshKeyCache sshKeyCache;
@Inject private GroupsUpdate.Factory groupsUpdateFactory;
@Inject private SetInactiveFlag setInactiveFlag;
+ @Inject private AuthRequest.Factory authRequestFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
@Test
public void authenticateNewAccountWithEmail() throws Exception {
String email = "foo@example.com";
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
assertNoSuchExternalIds(mailtoExtIdKey);
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForNewAccount(authResult, mailtoExtIdKey);
assertExternalId(mailtoExtIdKey, email);
@@ -78,11 +83,12 @@
@Test
public void authenticateNewAccountWithUsername() throws Exception {
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
assertNoSuchExternalIds(gerritExtIdKey, usernameExtIdKey);
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForNewAccount(authResult, gerritExtIdKey);
assertExternalIdsWithoutEmail(gerritExtIdKey, usernameExtIdKey);
@@ -91,11 +97,12 @@
@Test
public void authenticateNewAccountWithUsernameAndEmail() throws Exception {
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
assertNoSuchExternalIds(gerritExtIdKey, usernameExtIdKey);
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
String email = "foo@example.com";
who.setEmailAddress(email);
AuthResult authResult = accountManager.authenticate(who);
@@ -107,12 +114,14 @@
@Test
public void authenticateNewAccountWithExternalUser() throws Exception {
String username = "foo";
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
assertNoSuchExternalIds(externalExtIdKey, usernameExtIdKey, gerritExtIdKey);
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForNewAccount(authResult, externalExtIdKey);
assertExternalIdsWithoutEmail(externalExtIdKey, usernameExtIdKey);
@@ -122,12 +131,14 @@
@Test
public void authenticateNewAccountWithExternalUserAndEmail() throws Exception {
String username = "foo";
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
assertNoSuchExternalIds(externalExtIdKey, usernameExtIdKey, gerritExtIdKey);
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
String email = "foo@example.com";
who.setEmailAddress(email);
AuthResult authResult = accountManager.authenticate(who);
@@ -141,13 +152,13 @@
public void authenticateWithEmail() throws Exception {
String email = "foo@example.com";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(mailtoExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(mailtoExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForExistingAccount(authResult, accountId, mailtoExtIdKey);
}
@@ -156,13 +167,13 @@
public void authenticateWithUsername() throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForExistingAccount(authResult, accountId, gerritExtIdKey);
}
@@ -171,13 +182,14 @@
public void authenticateWithExternalUser() throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(externalExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(externalExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForExistingAccount(authResult, accountId, externalExtIdKey);
}
@@ -187,15 +199,16 @@
String username = "foo";
String email = "foo@example.com";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.setPreferredEmail(email)
- .addExternalId(ExternalId.createWithEmail(gerritExtIdKey, accountId, email)));
+ .addExternalId(
+ externalIdFactory.createWithEmail(gerritExtIdKey, accountId, email)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
String newEmail = "bar@example.com";
who.setEmailAddress(newEmail);
AuthResult authResult = accountManager.authenticate(who);
@@ -233,23 +246,26 @@
projectCache,
externalIds,
groupsUpdateFactory,
- setInactiveFlag));
+ setInactiveFlag,
+ externalIdFactory,
+ externalIdKeyFactory));
}
private void authenticateWithUsernameAndUpdateDisplayName(AccountManager am) throws Exception {
String username = "foo";
String email = "foo@example.com";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.setFullName("Initial Name")
.setPreferredEmail(email)
- .addExternalId(ExternalId.createWithEmail(gerritExtIdKey, accountId, email)));
+ .addExternalId(
+ externalIdFactory.createWithEmail(gerritExtIdKey, accountId, email)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
String newName = "Updated Name";
who.setDisplayName(newName);
AuthResult authResult = am.authenticate(who);
@@ -263,12 +279,12 @@
@Test
public void cannotAuthenticateWithOrphanedExtId() throws Exception {
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
assertNoSuchExternalIds(gerritExtIdKey);
// Create orphaned SCHEME_GERRIT external ID.
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId gerritExtId = ExternalId.create(gerritExtIdKey, accountId);
+ ExternalId gerritExtId = externalIdFactory.create(gerritExtIdKey, accountId);
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
ExternalIdNotes extIdNotes = extIdNotesFactory.load(allUsersRepo);
@@ -276,7 +292,7 @@
extIdNotes.commit(md);
}
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
assertThat(thrown).hasMessageThat().contains("Authentication error, account not found");
@@ -286,13 +302,13 @@
public void cannotAuthenticateWithInactiveAccount() throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.setActive(false).addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.setActive(false).addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
assertThat(thrown).hasMessageThat().contains("Authentication error, account inactive");
@@ -303,13 +319,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.setActive(false).addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.setActive(false).addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(true);
who.setAuthProvidesAccountActiveStatus(true);
AccountException thrown =
@@ -323,13 +339,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.setActive(false).addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.setActive(false).addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(true);
who.setAuthProvidesAccountActiveStatus(true);
AuthResult authResult = accountManager.authenticate(who);
@@ -344,13 +360,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(false);
who.setAuthProvidesAccountActiveStatus(true);
AuthResult authResult = accountManager.authenticate(who);
@@ -366,13 +382,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(false);
who.setAuthProvidesAccountActiveStatus(true);
AccountException thrown =
@@ -391,15 +407,17 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
// Try to authenticate with this email to create a new account with a SCHEME_MAILTO external ID.
// Expect that this fails because the email is already assigned to the other account.
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
assertThat(thrown)
@@ -414,15 +432,17 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
// Try to authenticate with a new username and claim the same email.
// Expect that this fails because the email is already assigned to the other account.
- AuthRequest who = AuthRequest.forUser("bar");
+ AuthRequest who = authRequestFactory.createForUser("bar");
who.setEmailAddress(email);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
@@ -439,25 +459,29 @@
// Create an account with a SCHEME_GERRIT external ID and an email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.setPreferredEmail(email)
- .addExternalId(ExternalId.createWithEmail(gerritExtIdKey, accountId, email)));
+ .addExternalId(
+ externalIdFactory.createWithEmail(gerritExtIdKey, accountId, email)));
// Create another account with an SCHEME_EXTERNAL external ID that occupies the new email.
Account.Id accountId2 = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, "bar");
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, "bar");
accountsUpdate.insert(
"Create Test Account",
accountId2,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId2, newEmail)));
+ u ->
+ u.addExternalId(
+ externalIdFactory.createWithEmail(externalExtIdKey, accountId2, newEmail)));
// Try to authenticate and update the email for the first account.
// Expect that this fails because the new email is already assigned to the other account.
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setEmailAddress(newEmail);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
@@ -482,21 +506,21 @@
// Create an account with a SCHEME_GERRIT external ID
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
Account.Id accountId = Account.id(seq.nextAccountId());
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
// Add the additional mail external ID with SCHEME_EMAIL
- accountManager.link(accountId, AuthRequest.forEmail(email));
+ accountManager.link(accountId, authRequestFactory.createForEmail(email));
// Try to authenticate and update the email for the account.
// Expect that this to succeed because even if the email already exist
// it is associated to the same account-id and thus is not really
// a duplicate but simply a promotion of external id to preferred email.
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setEmailAddress(email);
AuthResult authResult = accountManager.authenticate(who);
@@ -519,20 +543,20 @@
// Create an account with a SCHEME_GERRIT external ID and no email
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
// Check that email is not used yet.
String email = "foo@example.com";
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
assertNoSuchExternalIds(mailtoExtIdKey);
// Link the email to the account.
// Expect that a MAILTO external ID is created.
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult authResult = accountManager.link(accountId, who);
assertAuthResultForExistingAccount(authResult, accountId, mailtoExtIdKey);
assertExternalId(mailtoExtIdKey, accountId, email);
@@ -543,17 +567,18 @@
// Create an account with a SCHEME_GERRIT external ID and no email
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.addExternalId(
- ExternalId.createWithEmail(externalExtIdKey, accountId, "old@example.com")));
+ externalIdFactory.createWithEmail(externalExtIdKey, accountId, "old@example.com")));
// Link the email to the existing SCHEME_EXTERNAL external ID, but with a new email.
// Expect that the email of the existing external ID is updated.
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
String newEmail = "new@example.com";
who.setEmailAddress(newEmail);
AuthResult authResult = accountManager.link(accountId, who);
@@ -566,24 +591,26 @@
// Create an account with a SCHEME_EXTERNAL external ID
String username1 = "foo";
Account.Id accountId1 = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey1 = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username1);
+ ExternalId.Key externalExtIdKey1 =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username1);
accountsUpdate.insert(
"Create Test Account",
accountId1,
- u -> u.addExternalId(ExternalId.create(externalExtIdKey1, accountId1)));
+ u -> u.addExternalId(externalIdFactory.create(externalExtIdKey1, accountId1)));
// Create another account with a SCHEME_EXTERNAL external ID
String username2 = "bar";
Account.Id accountId2 = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey2 = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username2);
+ ExternalId.Key externalExtIdKey2 =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username2);
accountsUpdate.insert(
"Create Test Account",
accountId2,
- u -> u.addExternalId(ExternalId.create(externalExtIdKey2, accountId2)));
+ u -> u.addExternalId(externalIdFactory.create(externalExtIdKey2, accountId2)));
// Try to link external ID of the first account to the second account.
// Expect that this fails because the external ID is already assigned to the first account.
- AuthRequest who = AuthRequest.forExternalUser(username1);
+ AuthRequest who = authRequestFactory.createForExternalUser(username1);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.link(accountId2, who));
assertThat(thrown)
@@ -598,24 +625,27 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
// Create another account with a SCHEME_GERRIT external ID and no email
String username2 = "foo";
Account.Id accountId2 = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username2);
+ ExternalId.Key gerritExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username2);
accountsUpdate.insert(
"Create Test Account",
accountId2,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId2)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId2)));
// Try to link the email to the second account (via a new MAILTO external ID) and expect that
// this fails because the email is already assigned to the first account.
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.link(accountId2, who));
assertThat(thrown)
@@ -630,13 +660,15 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult result = accountManager.link(accountId, who);
assertThat(result.isNew()).isFalse();
assertThat(result.getAccountId().get()).isEqualTo(accountId.get());
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index ac43078..95a8950 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -4410,7 +4410,7 @@
value =
ExperimentFeaturesConstants
.GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_LEGACY_SUBMIT_REQUIREMENTS)
- public void submitRequirements_ReturnForLegacySubmitRecords_IfEnabled() throws Exception {
+ public void submitRequirements_returnForLegacySubmitRecords_ifEnabled() throws Exception {
configLabel("build-cop-override", LabelFunction.MAX_WITH_BLOCK);
projectOperations
.project(project)
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
index a2d18fb..eadd259 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
@@ -1322,7 +1322,7 @@
}
@Test
- public void addedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase() throws Exception {
+ public void addedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase() throws Exception {
ObjectId commit2 = addCommit(commit1, "file_added_in_another_commit.txt", "Some file content");
rebaseChangeOn(changeId, commit2);
@@ -1334,7 +1334,7 @@
}
@Test
- public void removedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase() throws Exception {
+ public void removedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase() throws Exception {
ObjectId commit2 = addCommitRemovingFiles(commit1, FILE_NAME2);
rebaseChangeOn(changeId, commit2);
@@ -1346,7 +1346,7 @@
}
@Test
- public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase() throws Exception {
+ public void renamedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase() throws Exception {
ObjectId commit2 = addCommitRenamingFile(commit1, FILE_NAME2, "a_new_file_name.txt");
rebaseChangeOn(changeId, commit2);
@@ -1358,7 +1358,7 @@
}
@Test
- public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase_WhenEquallyModifiedInBoth()
+ public void renamedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase_whenEquallyModifiedInBoth()
throws Exception {
// TODO(ghareeb): fix this test for the new diff cache implementation
assume().that(useNewDiffCache).isFalse();
@@ -1384,7 +1384,7 @@
}
@Test
- public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase_WhenModifiedDuringRebase()
+ public void renamedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase_whenModifiedDuringRebase()
throws Exception {
String renamedFilePath = "renamed_some_file.txt";
ObjectId commit2 =
@@ -2176,7 +2176,7 @@
}
@Test
- public void rebaseHunkInRenamedFileIsIdentified_WhenFileIsRenamedDuringRebase() throws Exception {
+ public void rebaseHunkInRenamedFileIsIdentified_whenFileIsRenamedDuringRebase() throws Exception {
String renamedFilePath = "renamed_some_file.txt";
ObjectId commit2 =
addCommit(commit1, FILE_NAME, FILE_CONTENT.replace("Line 1\n", "Line one\n"));
@@ -2205,7 +2205,7 @@
}
@Test
- public void rebaseHunkInRenamedFileIsIdentified_WhenFileIsRenamedInPatchSets() throws Exception {
+ public void rebaseHunkInRenamedFileIsIdentified_whenFileIsRenamedInPatchSets() throws Exception {
String renamedFilePath = "renamed_some_file.txt";
gApi.changes().id(changeId).edit().renameFile(FILE_NAME, renamedFilePath);
gApi.changes().id(changeId).edit().publish();
@@ -2244,7 +2244,7 @@
}
@Test
- public void renamedFileWithOnlyRebaseHunksIsIdentified_WhenRenamedBetweenPatchSets()
+ public void renamedFileWithOnlyRebaseHunksIsIdentified_whenRenamedBetweenPatchSets()
throws Exception {
String newFilePath1 = "renamed_some_file.txt";
gApi.changes().id(changeId).edit().renameFile(FILE_NAME, newFilePath1);
@@ -2279,7 +2279,7 @@
}
@Test
- public void renamedFileWithOnlyRebaseHunksIsIdentified_WhenRenamedForRebaseAndForPatchSets()
+ public void renamedFileWithOnlyRebaseHunksIsIdentified_whenRenamedForRebaseAndForPatchSets()
throws Exception {
String newFilePath1 = "renamed_some_file.txt";
gApi.changes().id(changeId).edit().renameFile(FILE_NAME, newFilePath1);
@@ -2834,7 +2834,7 @@
}
@Test
- public void addDeleteByJgit_IsIdentifiedAsRewritten() throws Exception {
+ public void addDeleteByJgit_isIdentifiedAsRewritten() throws Exception {
String target = "file.txt";
String symlink = "link.lnk";
@@ -2871,7 +2871,7 @@
}
@Test
- public void renameDeleteByJgit_IsIdentifiedAsRewritten6() throws Exception {
+ public void renameDeleteByJgit_isIdentifiedAsRewritten6() throws Exception {
String target = "file.txt";
String symlink = "link.lnk";
PushOneCommit push =
diff --git a/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java
index a90cd56..0e0168e 100644
--- a/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java
+++ b/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -281,7 +281,7 @@
}
@Test
- public void rebaseEditWithConflictsRest_Conflict() throws Exception {
+ public void rebaseEditWithConflictsRest_conflict() throws Exception {
PatchSet currentPatchSet = getCurrentPatchSet(changeId2);
createEmptyEditFor(changeId2);
gApi.changes().id(changeId2).edit().modifyFile(FILE_NAME, RawInputUtil.create(CONTENT_NEW));
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 5cf0403..2253202 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -1266,13 +1266,13 @@
}
@Test
- public void pushForMasterWithApprovals_MissingLabel() throws Exception {
+ public void pushForMasterWithApprovals_missingLabel() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master%l=Verify");
r.assertErrorStatus("label \"Verify\" is not a configured label");
}
@Test
- public void pushForMasterWithApprovals_ValueOutOfRange() throws Exception {
+ public void pushForMasterWithApprovals_valueOutOfRange() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master%l=Code-Review-3");
r.assertErrorStatus("label \"Code-Review\": -3 is not a valid value");
}
diff --git a/javatests/com/google/gerrit/acceptance/pgm/ChangeExternalIdCaseSensitivityIT.java b/javatests/com/google/gerrit/acceptance/pgm/ChangeExternalIdCaseSensitivityIT.java
new file mode 100644
index 0000000..83df896
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/pgm/ChangeExternalIdCaseSensitivityIT.java
@@ -0,0 +1,239 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.gerrit.acceptance.pgm;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_EXTERNAL;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_UUID;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.StandaloneSiteTest;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdNotes;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import java.io.IOException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.junit.After;
+import org.junit.Test;
+
+@NoHttpd
+public class ChangeExternalIdCaseSensitivityIT extends StandaloneSiteTest {
+
+ private static final boolean CASE_SENSITIVE = false;
+ private static final boolean CASE_INSENSITIVE = true;
+
+ private ServerContext ctx;
+ private ExternalIdNotes extIdNotes;
+ private ExternalIdFactory extIdFactory;
+ private MetaDataUpdate md;
+ private FileBasedConfig config;
+
+ @After
+ public void cleanup() throws Exception {
+ if (ctx != null) {
+ ctx.close();
+ }
+ }
+
+ @Test
+ public void externalIdNoteNameIsMigratedToCaseInsensitive() throws Exception {
+ prepareExternalIdNotes(CASE_SENSITIVE);
+
+ ctx.close();
+ runChangeExternalIdCaseSensitivity();
+ ctx = startServer();
+ extIdNotes = getExternalIdNotes(ctx);
+
+ assertExternalIdNotes(CASE_INSENSITIVE);
+ }
+
+ @Test
+ public void externalIdNoteNameIsMigratedToCaseSensitive() throws Exception {
+ prepareExternalIdNotes(CASE_INSENSITIVE);
+
+ ctx.close();
+ runChangeExternalIdCaseSensitivity();
+ ctx = startServer();
+ extIdNotes = getExternalIdNotes(ctx);
+
+ assertExternalIdNotes(CASE_SENSITIVE);
+ }
+
+ @Test
+ public void migrationFailsWithDuplicates() throws Exception {
+ prepareExternalIdNotes(CASE_SENSITIVE);
+ extIdNotes.insert(extIdFactory.create(SCHEME_USERNAME, "JohnDoe", Account.id(1)));
+ extIdNotes.commit(md);
+
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:johndoe", false)).isPresent())
+ .isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:JohnDoe", false)).isPresent())
+ .isTrue();
+
+ ctx.close();
+ assertThrows(DuplicateExternalIdKeyException.class, () -> runChangeExternalIdCaseSensitivity());
+ ctx = startServer();
+ extIdNotes = getExternalIdNotes(ctx);
+
+ assertExternalIdNotes(CASE_SENSITIVE);
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:johndoe", false)).isPresent())
+ .isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:JohnDoe", false)).isPresent())
+ .isTrue();
+ }
+
+ @Test
+ public void userNameCaseInsensitiveOptionIsSwitched() throws Exception {
+ configureUserNameCaseInsensitive(CASE_SENSITIVE);
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+ runChangeExternalIdCaseSensitivity();
+ config.load();
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isTrue();
+ runChangeExternalIdCaseSensitivity();
+ config.load();
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+ }
+
+ @Test
+ public void dryrunDoesNotPersistChanges() throws Exception {
+ prepareExternalIdNotes(CASE_SENSITIVE);
+ ctx.close();
+ runGerrit("ChangeExternalIdCaseSensitivity", "-d", sitePaths.site_path.toString(), "--dryrun");
+
+ config.load();
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+
+ ctx = startServer();
+ assertExternalIdNotes(CASE_SENSITIVE);
+ }
+
+ private void prepareExternalIdNotes(boolean userNameCaseInsensitive) throws Exception {
+ configureUserNameCaseInsensitive(userNameCaseInsensitive);
+ initSite();
+ ctx = startServer();
+ extIdFactory = ctx.getInjector().getInstance(ExternalIdFactory.class);
+ Project.NameKey allUsers = ctx.getInjector().getInstance(AllUsersName.class);
+ extIdNotes = getExternalIdNotes(ctx, allUsers);
+ md = getMetaDataUpdate(ctx, allUsers);
+
+ extIdNotes.insert(extIdFactory.create(SCHEME_USERNAME, "johndoe", Account.id(0)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_GERRIT, "johndoe", Account.id(0)));
+
+ extIdNotes.insert(extIdFactory.create(SCHEME_USERNAME, "JaneDoe", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_GERRIT, "JaneDoe", Account.id(1)));
+
+ extIdNotes.insert(extIdFactory.create(SCHEME_MAILTO, "Jane@Doe.com", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_UUID, "Abc123", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_GPGKEY, "Abc123", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_EXTERNAL, "saml/JaneDoe", Account.id(1)));
+ extIdNotes.commit(md);
+
+ assertExternalIdNotes(userNameCaseInsensitive);
+ }
+
+ private void assertExternalIdNotes(boolean userNameCaseInsensitive) throws Exception {
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("username:johndoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("username:JaneDoe", !userNameCaseInsensitive))
+ .isPresent())
+ .isFalse();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("username:JaneDoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("gerrit:johndoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("gerrit:JaneDoe", !userNameCaseInsensitive))
+ .isPresent())
+ .isFalse();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("gerrit:JaneDoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+
+ assertThat(extIdNotes.get(ExternalId.Key.parse("mailto:Jane@Doe.com", false)).isPresent())
+ .isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("uuid:Abc123", false)).isPresent()).isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("gpgkey:Abc123", false)).isPresent()).isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("external:saml/JaneDoe", false)).isPresent())
+ .isTrue();
+ }
+
+ private void configureUserNameCaseInsensitive(boolean userNameCaseInsensitive)
+ throws IOException, ConfigInvalidException {
+ config = new FileBasedConfig(baseConfig, sitePaths.gerrit_config.toFile(), FS.DETECTED);
+ config.load();
+ config.setBoolean("auth", null, "userNameCaseInsensitive", userNameCaseInsensitive);
+ config.save();
+ if (userNameCaseInsensitive) {
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isTrue();
+ } else {
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+ }
+ }
+
+ private void initSite() throws Exception {
+ runGerrit("init", "-d", sitePaths.site_path.toString(), "--show-stack-trace");
+ }
+
+ private void runChangeExternalIdCaseSensitivity() throws Exception {
+ runGerrit("ChangeExternalIdCaseSensitivity", "-d", sitePaths.site_path.toString(), "--batch");
+ }
+
+ private static ExternalIdNotes getExternalIdNotes(ServerContext ctx) throws Exception {
+ return getExternalIdNotes(ctx, ctx.getInjector().getInstance(AllUsersName.class));
+ }
+
+ private static ExternalIdNotes getExternalIdNotes(ServerContext ctx, Project.NameKey allUsers)
+ throws Exception {
+ GitRepositoryManager repoManager = ctx.getInjector().getInstance(GitRepositoryManager.class);
+ ExternalIdNotes.FactoryNoReindex extIdNotesFactory =
+ ctx.getInjector().getInstance(ExternalIdNotes.FactoryNoReindex.class);
+ return extIdNotesFactory.load(repoManager.openRepository(allUsers));
+ }
+
+ private static MetaDataUpdate getMetaDataUpdate(ServerContext ctx, Project.NameKey allUsers)
+ throws Exception {
+ MetaDataUpdate.Server metaDataUpdateFactory =
+ ctx.getInjector().getInstance(MetaDataUpdate.Server.class);
+ return metaDataUpdateFactory.create(allUsers);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java b/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java
index 8feac20..d055875 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java
@@ -40,6 +40,8 @@
import com.google.gerrit.server.account.Emails;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AuthConfig;
@@ -63,6 +65,8 @@
@Inject private ExternalIds externalIds;
@Inject private Provider<Emails> emails;
@Inject private RequestScopeOperations requestScopeOperations;
+ @Inject private ExternalIdFactory externalIdFactory;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
@Test
public void addEmail() throws Exception {
@@ -138,7 +142,7 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
+ externalIdFactory.createWithEmail(
ExternalId.SCHEME_EXTERNAL, "foo", admin.id(), email)));
assertThat(gApi.accounts().self().get().email).isNotEqualTo(email);
@@ -182,7 +186,7 @@
public void setPreferredEmailToEmailFromCustomRealmThatDoesntExistAsExternalId()
throws Exception {
String email = "foo@example.com";
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
assertThat(externalIds.get(mailtoExtIdKey)).isEmpty();
assertThat(gApi.accounts().self().get().email).isNotEqualTo(email);
@@ -200,7 +204,7 @@
@Test
public void setPreferredEmailToEmailFromCustomRealmThatBelongsToOtherAccount() throws Exception {
- ExternalId mailToExtId = ExternalId.createEmail(user.id(), user.email());
+ ExternalId mailToExtId = externalIdFactory.createEmail(user.id(), user.email());
assertThat(externalIds.get(mailToExtId.key())).isPresent();
Context oldCtx =
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java b/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
index 20b378b..cd123aa 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
@@ -21,6 +21,8 @@
import static com.google.gerrit.acceptance.GitUtil.pushHead;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_UUID;
@@ -37,6 +39,8 @@
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.common.data.GlobalCapability;
@@ -53,7 +57,10 @@
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
+import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIdReader;
import com.google.gerrit.server.account.externalids.ExternalIds;
@@ -92,6 +99,8 @@
@Inject private ExternalIdNotes.Factory externalIdNotesFactory;
@Inject private ProjectOperations projectOperations;
@Inject private RequestScopeOperations requestScopeOperations;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
@ConfigSuite.Default
public static Config partialCacheReloadingEnabled() {
@@ -194,7 +203,7 @@
}
@Test
- public void deleteExternalIdOfOtherUserUnderOwnAccount_UnprocessableEntity() throws Exception {
+ public void deleteExternalIdOfOtherUserUnderOwnAccount_unprocessableEntity() throws Exception {
List<AccountExternalIdInfo> extIds = gApi.accounts().self().getExternalIds();
requestScopeOperations.setApiUser(user.id());
UnprocessableEntityException thrown =
@@ -249,19 +258,60 @@
gApi.accounts()
.self()
.deleteExternalIds(
- ImmutableList.of(ExternalId.Key.create(SCHEME_MAILTO, preferredEmail).get()));
+ ImmutableList.of(externalIdKeyFactory.create(SCHEME_MAILTO, preferredEmail).get()));
assertThat(gApi.accounts().self().get().email).isNull();
}
@Test
- public void deleteExternalIds_Conflict() throws Exception {
+ public void deleteExternalIdOfUsernameByNonAdminForbidden() throws Exception {
List<String> toDelete = new ArrayList<>();
String externalIdStr = "username:" + user.username();
toDelete.add(externalIdStr);
- RestResponse response = userRestSession.post("/accounts/self/external.ids:delete", toDelete);
- response.assertConflict();
- assertThat(response.getEntityContent())
- .isEqualTo(String.format("External id %s cannot be deleted", externalIdStr));
+ RestResponse response =
+ userRestSession.post("/accounts/" + admin.id() + "/external.ids:delete", toDelete);
+ response.assertForbidden();
+ }
+
+ @Test
+ public void deleteExternalIdOfUsernameSelfForbidden() throws Exception {
+ List<String> toDelete = new ArrayList<>();
+ String externalIdStr = "username:" + admin.username();
+ toDelete.add(externalIdStr);
+ RestResponse response = adminRestSession.post("/accounts/self/external.ids:delete", toDelete);
+ response.assertForbidden();
+ }
+
+ @Test
+ public void deleteExternalIdOfUsernameByAdmin() throws Exception {
+ List<String> toDelete = new ArrayList<>();
+ String externalIdStr = "username:" + user.username();
+ toDelete.add(externalIdStr);
+ RestResponse response =
+ adminRestSession.post("/accounts/" + user.id() + "/external.ids:delete", toDelete);
+ response.assertNoContent();
+ List<AccountExternalIdInfo> results = gApi.accounts().id(user.id().get()).getExternalIds();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).identity).isEqualTo("mailto:user1@example.com");
+ }
+
+ @Test
+ public void deleteExternalIdOfUsernameMaintainServer() throws Exception {
+ projectOperations
+ .allProjectsForUpdate()
+ .add(allowCapability(GlobalCapability.MAINTAIN_SERVER).group(REGISTERED_USERS))
+ .add(allowCapability(GlobalCapability.MODIFY_ACCOUNT).group(REGISTERED_USERS))
+ .update();
+
+ List<String> toDelete = new ArrayList<>();
+ TestAccount user2 = accountCreator.user2();
+ String externalIdStr = "username:" + user2.username();
+ toDelete.add(externalIdStr);
+ RestResponse response =
+ userRestSession.post("/accounts/" + user2.id() + "/external.ids:delete", toDelete);
+ response.assertNoContent();
+ List<AccountExternalIdInfo> results = gApi.accounts().id(user2.id().get()).getExternalIds();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).identity).isEqualTo("mailto:user2@example.com");
}
@Test
@@ -525,12 +575,12 @@
// create valid external IDs
insertExtId(
- ExternalId.createWithPassword(
- ExternalId.Key.parse(nextId(scheme, i)),
+ externalIdFactory.createWithPassword(
+ externalIdKeyFactory.parse(nextId(scheme, i)),
admin.id(),
"admin.other@example.com",
"secret-password"));
- insertExtId(ExternalId.createEmail(admin.id(), "admin.other@example.com"));
+ insertExtId(externalIdFactory.createEmail(admin.id(), "admin.other@example.com"));
insertExtId(createExternalIdWithOtherCaseEmail(nextId(scheme, i)));
}
@@ -630,29 +680,30 @@
}
private ExternalId createExternalIdWithOtherCaseEmail(String externalId) {
- return ExternalId.createWithPassword(
- ExternalId.Key.parse(externalId),
+ return externalIdFactory.createWithPassword(
+ externalIdKeyFactory.parse(externalId),
admin.id(),
admin.email().toUpperCase(Locale.US),
"password");
}
private ExternalId createExternalIdForNonExistingAccount(String externalId) {
- return ExternalId.create(ExternalId.Key.parse(externalId), Account.id(1));
+ return externalIdFactory.create(externalIdKeyFactory.parse(externalId), Account.id(1));
}
private ExternalId createExternalIdWithInvalidEmail(String externalId) {
- return ExternalId.createWithEmail(
- ExternalId.Key.parse(externalId), admin.id(), "invalid-email");
+ return externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(externalId), admin.id(), "invalid-email");
}
private ExternalId createExternalIdWithDuplicateEmail(String externalId) {
- return ExternalId.createWithEmail(ExternalId.Key.parse(externalId), user.id(), admin.email());
+ return externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(externalId), user.id(), admin.email());
}
private ExternalId createExternalIdWithBadPassword(String username) {
- return ExternalId.create(
- ExternalId.Key.create(SCHEME_USERNAME, username),
+ return externalIdFactory.create(
+ externalIdKeyFactory.create(SCHEME_USERNAME, username),
admin.id(),
null,
"non-hashed-password-is-not-allowed");
@@ -664,14 +715,14 @@
@Test
public void readExternalIdWithAccountIdThatCanBeExpressedInKiB() throws Exception {
- ExternalId.Key extIdKey = ExternalId.Key.parse("foo:bar");
+ ExternalId.Key extIdKey = externalIdKeyFactory.parse("foo:bar");
Account.Id accountId = Account.id(1024 * 100);
accountsUpdateProvider
.get()
.insert(
"Create Account with Bad External ID",
accountId,
- u -> u.addExternalId(ExternalId.create(extIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(extIdKey, accountId)));
Optional<ExternalId> extId = externalIds.get(extIdKey);
assertThat(extId.map(ExternalId::accountId)).hasValue(accountId);
}
@@ -681,7 +732,7 @@
Set<ExternalId> expectedExtIds = new HashSet<>(externalIds.byAccount(admin.id()));
try (AutoCloseable ctx = createFailOnLoadContext()) {
// insert external ID
- ExternalId extId = ExternalId.create("foo", "bar", admin.id());
+ ExternalId extId = externalIdFactory.create("foo", "bar", admin.id());
insertExtId(extId);
expectedExtIds.add(extId);
assertThat(externalIds.byAccount(admin.id())).containsExactlyElementsIn(expectedExtIds);
@@ -689,7 +740,7 @@
// update external ID
expectedExtIds.remove(extId);
ExternalId extId2 =
- ExternalId.createWithEmail("foo", "bar", admin.id(), "foo.bar@example.com");
+ externalIdFactory.createWithEmail("foo", "bar", admin.id(), "foo.bar@example.com");
accountsUpdateProvider
.get()
.update("Update External ID", admin.id(), u -> u.updateExternalId(extId2));
@@ -711,7 +762,7 @@
try (AutoCloseable ctx = createFailOnLoadContext()) {
// update external ID branch so that external IDs need to be reloaded
- insertExtIdBehindGerritsBack(ExternalId.create("foo", "bar", admin.id()));
+ insertExtIdBehindGerritsBack(externalIdFactory.create("foo", "bar", admin.id()));
assertThrows(IOException.class, () -> externalIds.byAccount(admin.id()));
}
@@ -723,7 +774,7 @@
try (AutoCloseable ctx = createFailOnLoadContext()) {
// update external ID branch so that external IDs need to be reloaded
- insertExtIdBehindGerritsBack(ExternalId.create("foo", "bar", admin.id()));
+ insertExtIdBehindGerritsBack(externalIdFactory.create("foo", "bar", admin.id()));
assertThrows(IOException.class, () -> externalIds.byEmail(admin.email()));
}
@@ -732,7 +783,7 @@
@Test
public void byAccountUpdateExternalIdsBehindGerritsBack() throws Exception {
Set<ExternalId> expectedExternalIds = new HashSet<>(externalIds.byAccount(admin.id()));
- ExternalId newExtId = ExternalId.create("foo", "bar", admin.id());
+ ExternalId newExtId = externalIdFactory.create("foo", "bar", admin.id());
insertExtIdBehindGerritsBack(newExtId);
expectedExternalIds.add(newExtId);
assertThat(externalIds.byAccount(admin.id())).containsExactlyElementsIn(expectedExternalIds);
@@ -740,10 +791,10 @@
@Test
public void unsetEmail() throws Exception {
- ExternalId extId = ExternalId.createWithEmail("x", "1", user.id(), "x@example.com");
+ ExternalId extId = externalIdFactory.createWithEmail("x", "1", user.id(), "x@example.com");
insertExtId(extId);
- ExternalId extIdWithoutEmail = ExternalId.create("x", "1", user.id());
+ ExternalId extIdWithoutEmail = externalIdFactory.create("x", "1", user.id());
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
@@ -757,10 +808,11 @@
@Test
public void unsetHttpPassword() throws Exception {
ExternalId extId =
- ExternalId.createWithPassword(ExternalId.Key.create("y", "1"), user.id(), null, "secret");
+ externalIdFactory.createWithPassword(
+ externalIdKeyFactory.create("y", "1"), user.id(), null, "secret");
insertExtId(extId);
- ExternalId extIdWithoutPassword = ExternalId.create("y", "1", user.id());
+ ExternalId extIdWithoutPassword = externalIdFactory.create("y", "1", user.id());
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
@@ -771,6 +823,75 @@
}
}
+ @Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void createCaseInsensitiveExternalId_DuplicateKey() throws Exception {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsers);
+ MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
+ testCaseInsensitiveExternalIdKey(md, extIdNotes, SCHEME_USERNAME, "JohnDoe", Account.id(42));
+ assertThrows(
+ DuplicateExternalIdKeyException.class,
+ () ->
+ extIdNotes.insert(
+ externalIdFactory.create(SCHEME_USERNAME, "johndoe", Account.id(23))));
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void createCaseInsensitiveExternalId_SchemeWithUsername() throws Exception {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsers);
+ MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
+
+ testCaseInsensitiveExternalIdKey(md, extIdNotes, SCHEME_USERNAME, "janedoe", Account.id(66));
+ testCaseInsensitiveExternalIdKey(md, extIdNotes, SCHEME_GERRIT, "JaneDoe", Account.id(66));
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void createCaseSensitiveExternalId_SchemeWithoutUsername() throws Exception {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsers);
+ MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
+
+ testCaseSensitiveExternalIdKey(md, extIdNotes, SCHEME_MAILTO, "Jane@doe.com", Account.id(66));
+ testCaseSensitiveExternalIdKey(md, extIdNotes, SCHEME_UUID, "1234ABCD", Account.id(66));
+ testCaseSensitiveExternalIdKey(md, extIdNotes, SCHEME_GPGKEY, "1234ABCD", Account.id(66));
+ }
+ }
+
+ private void testCaseSensitiveExternalIdKey(
+ MetaDataUpdate md, ExternalIdNotes extIdNotes, String scheme, String id, Account.Id accountId)
+ throws DuplicateExternalIdKeyException, IOException, ConfigInvalidException {
+ ExternalId extId = externalIdFactory.create(scheme, id, accountId);
+ extIdNotes.insert(extId);
+ extIdNotes.commit(md);
+ assertThat(extIdNotes.get(externalIdKeyFactory.create(scheme, id)).get().accountId().get())
+ .isEqualTo(accountId.get());
+ assertThat(extIdNotes.get(externalIdKeyFactory.create(scheme, id.toLowerCase())).isPresent())
+ .isFalse();
+ }
+
+ private void testCaseInsensitiveExternalIdKey(
+ MetaDataUpdate md, ExternalIdNotes extIdNotes, String scheme, String id, Account.Id accountId)
+ throws DuplicateExternalIdKeyException, IOException, ConfigInvalidException {
+ ExternalId extId = externalIdFactory.create(scheme, id, accountId);
+ extIdNotes.insert(extId);
+ extIdNotes.commit(md);
+ assertThat(extIdNotes.get(externalIdKeyFactory.create(scheme, id)).get().accountId().get())
+ .isEqualTo(accountId.get());
+ assertThat(
+ extIdNotes
+ .get(externalIdKeyFactory.create(scheme, id.toLowerCase()))
+ .get()
+ .accountId()
+ .get())
+ .isEqualTo(accountId.get());
+ }
+
private boolean isPartialCacheReloadingEnabled() {
return cfg.getBoolean("cache", "external_ids_map", "enablePartialReloads", true);
}
@@ -796,7 +917,8 @@
private void insertExtIdBehindGerritsBack(ExternalId extId) throws Exception {
try (Repository repo = repoManager.openRepository(allUsers)) {
// Inserting an external ID "behind Gerrit's back" means that the caches are not updated.
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
extIdNotes.insert(extId);
try (MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, null, repo)) {
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java b/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java
index e05d0db..f46cf0c 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java
@@ -18,6 +18,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.extensions.api.accounts.UsernameInput;
import org.junit.Test;
@@ -42,6 +43,16 @@
}
@Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void setExistingCaseInsensitive_Conflict() throws Exception {
+ UsernameInput in = new UsernameInput();
+ in.username = admin.username().toUpperCase();
+ adminRestSession
+ .put("/accounts/" + accountCreator.create().id().get() + "/username", in)
+ .assertConflict();
+ }
+
+ @Test
public void setNew_MethodNotAllowed() throws Exception {
UsernameInput in = new UsernameInput();
in.username = "newUsername";
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java
index 0b2cba9..13353bd 100644
--- a/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java
@@ -29,7 +29,7 @@
import com.google.gerrit.gpg.testing.TestKey;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.junit.Test;
@@ -43,6 +43,7 @@
public class AccountsRestApiBindingsIT extends AbstractDaemonTest {
@Inject private @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider;
@Inject private RequestScopeOperations requestScopeOperations;
+ @Inject private ExternalIdFactory externalIdFactory;
/**
* Account REST endpoints to be tested, each URL contains a placeholder for the account
@@ -166,7 +167,7 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(name("test"), email, admin.id(), email)));
+ externalIdFactory.createWithEmail(name("test"), email, admin.id(), email)));
requestScopeOperations.setApiUser(admin.id());
gApi.accounts()
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java b/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
index daeb032..ef5e7dc 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
@@ -52,14 +52,14 @@
}
@Test
- public void flushAll_Forbidden() throws Exception {
+ public void flushAll_forbidden() throws Exception {
userRestSession
.post("/config/server/caches/", new PostCaches.Input(FLUSH_ALL))
.assertForbidden();
}
@Test
- public void flushAll_BadRequest() throws Exception {
+ public void flushAll_badRequest() throws Exception {
adminRestSession
.post("/config/server/caches/", new PostCaches.Input(FLUSH_ALL, Arrays.asList("projects")))
.assertBadRequest();
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index 02db412..5f60250 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -102,12 +102,12 @@
}
@Test
- public void createProjectHttpWhenProjectAlreadyExists_Conflict() throws Exception {
+ public void createProjectHttpWhenProjectAlreadyExists_conflict() throws Exception {
adminRestSession.put("/projects/" + allProjects.get()).assertConflict();
}
@Test
- public void createProjectHttpWhenProjectAlreadyExists_PreconditionFailed() throws Exception {
+ public void createProjectHttpWhenProjectAlreadyExists_preconditionFailed() throws Exception {
adminRestSession
.putWithHeaders(
"/projects/" + allProjects.get(), new BasicHeader(HttpHeaders.IF_NONE_MATCH, "*"))
@@ -140,7 +140,7 @@
@Test
@UseLocalDisk
- public void createProjectHttpWithUnreasonableName_BadRequest() throws Exception {
+ public void createProjectHttpWithUnreasonableName_badRequest() throws Exception {
ImmutableList<String> forbiddenStrings =
ImmutableList.of(
"/../", "/./", "//", ".git/", "?", "%", "*", ":", "<", ">", "|", "$", "/+", "~");
@@ -153,14 +153,14 @@
}
@Test
- public void createProjectHttpWithNameMismatch_BadRequest() throws Exception {
+ public void createProjectHttpWithNameMismatch_badRequest() throws Exception {
ProjectInput in = new ProjectInput();
in.name = name("otherName");
adminRestSession.put("/projects/" + name("someName"), in).assertBadRequest();
}
@Test
- public void createProjectHttpWithInvalidRefName_BadRequest() throws Exception {
+ public void createProjectHttpWithInvalidRefName_badRequest() throws Exception {
ProjectInput in = new ProjectInput();
in.branches = Collections.singletonList(name("invalid ref name"));
adminRestSession.put("/projects/" + name("newProject"), in).assertBadRequest();
diff --git a/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java b/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
index c7beb2d..0cfa0f8 100644
--- a/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
@@ -23,6 +23,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.account.TestAccount;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
@@ -160,6 +161,22 @@
}
@Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void byUsernameCaseInsensitive() throws Exception {
+ String existingUsername = "myusername";
+ Account.Id idWithUsername = accountOperations.newAccount().username(existingUsername).create();
+
+ String existingMixedCaseUsername = "MyMixedCaseUsername";
+ Account.Id idWithMixedCaseUsername =
+ accountOperations.newAccount().username(existingMixedCaseUsername).create();
+
+ assertThat(resolve(existingUsername)).containsExactly(idWithUsername);
+ assertThat(resolve(existingMixedCaseUsername)).containsExactly(idWithMixedCaseUsername);
+ assertThat(resolve(existingMixedCaseUsername.toLowerCase()))
+ .containsExactly(idWithMixedCaseUsername);
+ }
+
+ @Test
public void byNameAndEmail() throws Exception {
String email = name("user@example.com");
Account.Id idWithEmail = accountOperations.newAccount().preferredEmail(email).create();
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
index 81cb7159..a2765d9 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
@@ -425,7 +425,7 @@
}
@Test
- public void commentContextReturnsCorrectContentType_Java() throws Exception {
+ public void commentContextReturnsCorrectContentType_java() throws Exception {
String javaContent =
"public class Main {\n"
+ " public static void main(String[]args){\n"
@@ -448,7 +448,7 @@
}
@Test
- public void commentContextReturnsCorrectContentType_Cpp() throws Exception {
+ public void commentContextReturnsCorrectContentType_cpp() throws Exception {
String cppContent =
"#include <iostream>\n"
+ "\n"
diff --git a/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java b/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java
index 0fc42ff..277c0e6 100644
--- a/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java
@@ -26,6 +26,7 @@
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIdUpsertPreprocessor;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -49,6 +50,7 @@
@Inject private Sequences sequences;
@Inject private @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider;
@Inject private ExternalIdNotes.Factory extIdNotesFactory;
+ @Inject private ExternalIdFactory extIdFactory;
public static class Module extends AbstractModule {
@Override
@@ -70,7 +72,7 @@
@Test
public void insertAccount() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId));
assertThat(testPreprocessor.upserted).containsExactly(extId);
}
@@ -78,8 +80,8 @@
@Test
public void replaceByKeys() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar1", id);
- ExternalId extId2 = ExternalId.create("foo", "bar2", id);
+ ExternalId extId1 = extIdFactory.create("foo", "bar1", id);
+ ExternalId extId2 = extIdFactory.create("foo", "bar2", id);
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
testPreprocessor.reset();
@@ -95,7 +97,7 @@
@Test
public void insert() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
@@ -109,7 +111,7 @@
@Test
public void upsert() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
@@ -123,8 +125,8 @@
@Test
public void replace() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar1", id);
- ExternalId extId2 = ExternalId.create("foo", "bar2", id);
+ ExternalId extId1 = extIdFactory.create("foo", "bar1", id);
+ ExternalId extId2 = extIdFactory.create("foo", "bar2", id);
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
testPreprocessor.reset();
@@ -140,8 +142,8 @@
@Test
public void replace_viaAccountsUpdate() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar", id, "email1@foo", "hash");
- ExternalId extId2 = ExternalId.create("foo", "bar", id, "email2@foo", "hash");
+ ExternalId extId1 = extIdFactory.create("foo", "bar", id, "email1@foo", "hash");
+ ExternalId extId2 = extIdFactory.create("foo", "bar", id, "email2@foo", "hash");
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
testPreprocessor.reset();
@@ -152,7 +154,7 @@
@Test
public void blockUpsert() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
testPreprocessor.throwException = true;
StorageException e =
assertThrows(
@@ -165,8 +167,8 @@
@Test
public void blockUpsert_replace() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar", id, "email1@foo", "hash");
- ExternalId extId2 = ExternalId.create("foo", "bar", id, "email2@foo", "hash");
+ ExternalId extId1 = extIdFactory.create("foo", "bar", id, "email1@foo", "hash");
+ ExternalId extId2 = extIdFactory.create("foo", "bar", id, "email2@foo", "hash");
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
assertThat(accounts.get(id).get().externalIds()).containsExactly(extId1);
diff --git a/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java b/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java
index 9e4907c..46687e3 100644
--- a/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java
@@ -44,7 +44,7 @@
import com.google.gerrit.server.PropertyMap;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupMembership;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -70,6 +70,7 @@
@Inject private ChangeNotes.Factory changeNotesFactory;
@Inject private ExternalUser.Factory externalUserFactory;
@Inject private GroupOperations groupOperations;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
@Before
public void setUp() {
@@ -295,7 +296,7 @@
ExternalUser createUserInGroup(String userId, String groupId) {
return externalUserFactory.create(
ImmutableSet.of(),
- ImmutableSet.of(ExternalId.Key.parse("company-auth:" + groupId + "-" + userId)),
+ ImmutableSet.of(externalIdKeyFactory.parse("company-auth:" + groupId + "-" + userId)),
PropertyMap.EMPTY);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/SetAccountIT.java b/javatests/com/google/gerrit/acceptance/ssh/SetAccountIT.java
new file mode 100644
index 0000000..a82876e
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/ssh/SetAccountIT.java
@@ -0,0 +1,93 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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.gerrit.acceptance.ssh;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.server.account.externalids.ExternalIds;
+import com.google.inject.Inject;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+@UseSsh
+@NoHttpd
+public class SetAccountIT extends AbstractDaemonTest {
+ @Inject private ExternalIds externalIds;
+ @Inject private ProjectOperations projectOperations;
+
+ @Test
+ public void setAccount_deleteExternalId_all() throws Exception {
+ TestAccount testAccount = accountCreator.create("user1", "user1@example.com", null, null);
+ adminSshSession.exec("gerrit set-account --delete-external-id ALL user1");
+ adminSshSession.assertSuccess();
+ assertThat(externalIds.byAccount(testAccount.id()).isEmpty()).isTrue();
+ }
+
+ @Test
+ public void setAccount_deleteExternalId_single() throws Exception {
+ TestAccount testAccount = accountCreator.create("user2", "user2@example.com", null, null);
+ List<String> extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user2")).isTrue();
+ assertThat(extIdKeys.contains("mailto:user2@example.com")).isTrue();
+ adminSshSession.exec("gerrit set-account --delete-external-id username:user2 user2");
+ adminSshSession.assertSuccess();
+ extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user3")).isFalse();
+ assertThat(extIdKeys.contains("mailto:user3@example.com")).isFalse();
+ }
+
+ @Test
+ public void setAccount_deleteExternalId_multiple() throws Exception {
+ TestAccount testAccount = accountCreator.create("user3", "user3@example.com", null, null);
+ List<String> extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user3")).isTrue();
+ assertThat(extIdKeys.contains("mailto:user3@example.com")).isTrue();
+ adminSshSession.exec(
+ "gerrit set-account --delete-external-id username:user3 --delete-external-id mailto:user3@example.com user3");
+ adminSshSession.assertSuccess();
+ extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user3")).isFalse();
+ assertThat(extIdKeys.contains("mailto:user3@example.com")).isFalse();
+ }
+
+ @Test
+ public void setAccount_deleteExternalId_byUser() throws Exception {
+ userSshSession.exec("gerrit set-account --delete-external-id mailto:admin@example.com admin");
+ userSshSession.assertFailure();
+ projectOperations
+ .allProjectsForUpdate()
+ .add(allowCapability(GlobalCapability.MODIFY_ACCOUNT).group(REGISTERED_USERS))
+ .update();
+ userSshSession.exec("gerrit set-account --delete-external-id mailto:admin@example.com admin");
+ userSshSession.assertSuccess();
+ userSshSession.exec("gerrit set-account --delete-external-id username:admin admin");
+ userSshSession.assertFailure();
+ }
+
+ private List<String> getExternalIdKeys(TestAccount account) throws Exception {
+ return externalIds.byAccount(account.id()).stream()
+ .map(e -> e.key().get())
+ .collect(Collectors.toList());
+ }
+}
diff --git a/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java b/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java
index 7a61626..0883033 100644
--- a/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java
+++ b/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java
@@ -30,6 +30,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Guice;
@@ -44,6 +45,7 @@
public final class LdapRealmTest {
@Inject private LdapRealm ldapRealm = null;
+ @Inject private ExternalIdFactory externalIdFactory;
@Before
public void setUpInjector() throws Exception {
@@ -67,7 +69,7 @@
}
private ExternalId id(String scheme, String id) {
- return ExternalId.create(scheme, id, Account.id(1000));
+ return externalIdFactory.create(scheme, id, Account.id(1000));
}
private boolean accountBelongsToRealm(ExternalId... ids) {
diff --git a/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java b/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java
index 1af78e3..3ec6f28 100644
--- a/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java
+++ b/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java
@@ -24,6 +24,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
@@ -34,6 +35,7 @@
public final class OAuthRealmTest {
@Inject private OAuthRealm oauthRealm = null;
+ @Inject private ExternalIdFactory externalIdFactory;
@Before
public void setUpInjector() throws Exception {
@@ -42,7 +44,7 @@
}
private ExternalId id(String scheme, String id) {
- return ExternalId.create(scheme, id, Account.id(1000));
+ return externalIdFactory.create(scheme, id, Account.id(1000));
}
private boolean accountBelongsToRealm(ExternalId... ids) {
diff --git a/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java b/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java
index 05b0ec0..f83409b 100644
--- a/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java
+++ b/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java
@@ -25,6 +25,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
@@ -35,6 +36,7 @@
public final class OpenIdRealmTest {
@Inject private OpenIdRealm openidRealm = null;
+ @Inject private ExternalIdFactory extIdFactory;
@Before
public void setUpInjector() throws Exception {
@@ -43,7 +45,7 @@
}
private ExternalId id(String scheme, String id) {
- return ExternalId.create(scheme, id, Account.id(1000));
+ return extIdFactory.create(scheme, id, Account.id(1000));
}
private boolean accountBelongsToRealm(ExternalId... ids) {
diff --git a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
index 45b3419..05e9808 100644
--- a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
+++ b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
@@ -15,7 +15,6 @@
package com.google.gerrit.gpg;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.gpg.GerritPublicKeyChecker.toExtIdKey;
import static com.google.gerrit.gpg.PublicKeyStore.keyToString;
import static com.google.gerrit.gpg.testing.TestKeys.validKeyWithSecondUserId;
import static com.google.gerrit.gpg.testing.TestTrustKeys.keyA;
@@ -39,6 +38,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gerrit.testing.InMemoryModule;
@@ -76,6 +76,10 @@
@Inject private ThreadLocalRequestContext requestContext;
+ @Inject private AuthRequest.Factory authRequestFactory;
+
+ @Inject private ExternalIdFactory externalIdFactory;
+
private LifecycleManager lifecycle;
private Account.Id userId;
private IdentifiedUser user;
@@ -101,7 +105,7 @@
lifecycle.start();
schemaCreator.create();
- userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ userId = accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
// Note: does not match any key in TestKeys.
accountsUpdateProvider
.get()
@@ -121,7 +125,7 @@
}
private IdentifiedUser addUser(String name) throws Exception {
- AuthRequest req = AuthRequest.forUser(name);
+ AuthRequest req = authRequestFactory.createForUser(name);
Account.Id id = accountManager.authenticate(req).getAccountId();
return userFactory.create(id);
}
@@ -202,16 +206,18 @@
reloadUser();
TestKey key = validKeyWithSecondUserId();
- PublicKeyChecker checker = checkerFactory.create(user, store).disableTrust();
+ GerritPublicKeyChecker checker =
+ (GerritPublicKeyChecker) checkerFactory.create(user, store).disableTrust();
assertProblems(
checker.check(key.getPublicKey()),
Status.BAD,
"No identities found for user; check http://test/settings#Identities");
- checker = checkerFactory.create().setStore(store).disableTrust();
+ checker = (GerritPublicKeyChecker) checkerFactory.create().setStore(store).disableTrust();
assertProblems(
checker.check(key.getPublicKey()), Status.BAD, "Key is not associated with any users");
- insertExtId(ExternalId.create(toExtIdKey(key.getPublicKey()), user.getAccountId()));
+ insertExtId(
+ externalIdFactory.create(checker.toExtIdKey(key.getPublicKey()), user.getAccountId()));
assertProblems(checker.check(key.getPublicKey()), Status.BAD, "No identities found for user");
}
@@ -362,13 +368,15 @@
private void add(PGPPublicKeyRing kr, IdentifiedUser user) throws Exception {
Account.Id id = user.getAccountId();
List<ExternalId> newExtIds = new ArrayList<>(2);
- newExtIds.add(ExternalId.create(toExtIdKey(kr.getPublicKey()), id));
+ GerritPublicKeyChecker checker =
+ (GerritPublicKeyChecker) checkerFactory.create(user, store).disableTrust();
+ newExtIds.add(externalIdFactory.create(checker.toExtIdKey(kr.getPublicKey()), id));
String userId = Iterators.getOnlyElement(kr.getPublicKey().getUserIDs(), null);
if (userId != null) {
String email = PushCertificateIdent.parse(userId).getEmailAddress();
assertThat(email).contains("@");
- newExtIds.add(ExternalId.createEmail(id, email));
+ newExtIds.add(externalIdFactory.createEmail(id, email));
}
store.add(kr);
@@ -401,7 +409,7 @@
}
private void addExternalId(String scheme, String id, String email) throws Exception {
- insertExtId(ExternalId.createWithEmail(scheme, id, user.getAccountId(), email));
+ insertExtId(externalIdFactory.createWithEmail(scheme, id, user.getAccountId(), email));
}
private void insertExtId(ExternalId extId) throws Exception {
diff --git a/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java b/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java
index 2f0fafa..162a171 100644
--- a/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java
+++ b/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java
@@ -32,8 +32,12 @@
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
+import com.google.gerrit.server.account.externalids.PasswordVerifier;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
@@ -62,12 +66,6 @@
private static final String AUTH_PASSWORD = "jd123";
private static final String GERRIT_COOKIE_KEY = "GerritAccount";
private static final String AUTH_COOKIE_VALUE = "gerritcookie";
- private static final ExternalId AUTH_USER_PASSWORD_EXTERNAL_ID =
- ExternalId.createWithPassword(
- ExternalId.Key.create(ExternalId.SCHEME_USERNAME, AUTH_USER),
- AUTH_ACCOUNT_ID,
- null,
- AUTH_PASSWORD);
@Mock private DynamicItem<WebSession> webSessionItem;
@@ -93,14 +91,23 @@
private FakeHttpServletRequest req;
private HttpServletResponse res;
private AuthResult authSuccessful;
+ private ExternalIdFactory extIdFactory;
+ private ExternalIdKeyFactory extIdKeyFactory;
+ private PasswordVerifier pwdVerifier;
+ private AuthRequest.Factory authRequestFactory;
@Before
public void setUp() throws Exception {
req = new FakeHttpServletRequest("gerrit.example.com", 80, "", "");
res = new FakeHttpServletResponse();
+ extIdKeyFactory = new ExternalIdKeyFactory(authConfig);
+ extIdFactory = new ExternalIdFactory(extIdKeyFactory);
+ authRequestFactory = new AuthRequest.Factory(extIdKeyFactory);
+ pwdVerifier = new PasswordVerifier(extIdKeyFactory);
+
authSuccessful =
- new AuthResult(AUTH_ACCOUNT_ID, ExternalId.Key.create("username", AUTH_USER), false);
+ new AuthResult(AUTH_ACCOUNT_ID, extIdKeyFactory.create("username", AUTH_USER), false);
doReturn(Optional.of(accountState)).when(accountCache).getByUsername(AUTH_USER);
doReturn(Optional.of(accountState)).when(accountCache).get(AUTH_ACCOUNT_ID);
doReturn(account).when(accountState).account();
@@ -121,7 +128,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -136,7 +149,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -155,7 +174,13 @@
doReturn(GitBasicAuthPolicy.LDAP).when(authConfig).getGitBasicAuthPolicy();
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -175,7 +200,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -216,7 +247,13 @@
doReturn(GitBasicAuthPolicy.LDAP).when(authConfig).getGitBasicAuthPolicy();
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -235,7 +272,13 @@
doReturn(GitBasicAuthPolicy.LDAP).when(authConfig).getGitBasicAuthPolicy();
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -255,7 +298,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
}
@@ -278,9 +327,13 @@
}
private void initMockedUsernamePasswordExternalId() {
- doReturn(ImmutableSet.builder().add(AUTH_USER_PASSWORD_EXTERNAL_ID).build())
- .when(accountState)
- .externalIds();
+ ExternalId extId =
+ extIdFactory.createWithPassword(
+ extIdKeyFactory.create(ExternalId.SCHEME_USERNAME, AUTH_USER),
+ AUTH_ACCOUNT_ID,
+ null,
+ AUTH_PASSWORD);
+ doReturn(ImmutableSet.builder().add(extId).build()).when(accountState).externalIds();
}
private void requestBasicAuth(FakeHttpServletRequest fakeReq) {
diff --git a/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java b/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java
index 814df03..058384e 100644
--- a/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java
+++ b/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java
@@ -25,12 +25,26 @@
import com.google.gerrit.server.account.externalids.AllExternalIds.Serializer;
import com.google.gerrit.server.cache.proto.Cache.AllExternalIdsProto;
import com.google.gerrit.server.cache.proto.Cache.AllExternalIdsProto.ExternalIdProto;
+import com.google.gerrit.server.config.AuthConfig;
import com.google.inject.TypeLiteral;
+import java.lang.reflect.Type;
import java.util.Arrays;
import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
public class AllExternalIdsTest {
+ private AuthConfig authConfig;
+ private ExternalIdFactory externalIdFactory;
+
+ @Before
+ public void setUp() throws Exception {
+ authConfig = Mockito.mock(AuthConfig.class);
+ Mockito.when(authConfig.isUserNameCaseInsensitive()).thenReturn(false);
+ externalIdFactory = new ExternalIdFactory(new ExternalIdKeyFactory(authConfig));
+ }
+
@Test
public void serializeEmptyExternalIds() throws Exception {
assertRoundTrip(allExternalIds(), AllExternalIdsProto.getDefaultInstance());
@@ -42,10 +56,10 @@
Account.Id accountId2 = Account.id(1002);
assertRoundTrip(
allExternalIds(
- ExternalId.create("scheme1", "id1", accountId1),
- ExternalId.create("scheme2", "id2", accountId1),
- ExternalId.create("scheme2", "id3", accountId2),
- ExternalId.create("scheme3", "id4", accountId2)),
+ externalIdFactory.create("scheme1", "id1", accountId1),
+ externalIdFactory.create("scheme2", "id2", accountId1),
+ externalIdFactory.create("scheme2", "id3", accountId2),
+ externalIdFactory.create("scheme3", "id4", accountId2)),
AllExternalIdsProto.newBuilder()
.addExternalId(
ExternalIdProto.newBuilder().setKey("scheme1:id1").setAccountId(1001).build())
@@ -61,7 +75,7 @@
@Test
public void serializeExternalIdWithEmail() throws Exception {
assertRoundTrip(
- allExternalIds(ExternalId.createEmail(Account.id(1001), "foo@example.com")),
+ allExternalIds(externalIdFactory.createEmail(Account.id(1001), "foo@example.com")),
AllExternalIdsProto.newBuilder()
.addExternalId(
ExternalIdProto.newBuilder()
@@ -75,7 +89,7 @@
public void serializeExternalIdWithPassword() throws Exception {
assertRoundTrip(
allExternalIds(
- ExternalId.create("scheme", "id", Account.id(1001), null, "hashed password")),
+ externalIdFactory.create("scheme", "id", Account.id(1001), null, "hashed password")),
AllExternalIdsProto.newBuilder()
.addExternalId(
ExternalIdProto.newBuilder()
@@ -89,8 +103,8 @@
public void serializeExternalIdWithBlobId() throws Exception {
assertRoundTrip(
allExternalIds(
- ExternalId.create(
- ExternalId.create("scheme", "id", Account.id(1001)),
+ externalIdFactory.create(
+ externalIdFactory.create("scheme", "id", Account.id(1001)),
ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))),
AllExternalIdsProto.newBuilder()
.addExternalId(
@@ -121,12 +135,14 @@
public void externalIdMethods() {
assertThatSerializedClass(ExternalId.class)
.hasAutoValueMethods(
- ImmutableMap.of(
- "key", ExternalId.Key.class,
- "accountId", Account.Id.class,
- "email", String.class,
- "password", String.class,
- "blobId", ObjectId.class));
+ ImmutableMap.<String, Type>builder()
+ .put("key", ExternalId.Key.class)
+ .put("accountId", Account.Id.class)
+ .put("isCaseInsensitive", boolean.class)
+ .put("email", String.class)
+ .put("password", String.class)
+ .put("blobId", ObjectId.class)
+ .build());
}
private static AllExternalIds allExternalIds(ExternalId... externalIds) {
diff --git a/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java b/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
index 5717e78..fab90d4 100644
--- a/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
+++ b/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
@@ -28,6 +28,7 @@
import com.google.gerrit.server.account.externalids.testing.ExternalIdTestUtil;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.AllUsersNameProvider;
+import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -56,12 +57,18 @@
private GitRepositoryManager repoManager = new InMemoryRepositoryManager();
private ExternalIdReader externalIdReader;
private ExternalIdReader externalIdReaderSpy;
+ private AuthConfig authConfig;
+ private ExternalIdFactory externalIdFactory;
@Before
public void setUp() throws Exception {
+ authConfig = Mockito.mock(AuthConfig.class);
+ Mockito.when(authConfig.isUserNameCaseInsensitive()).thenReturn(false);
+ externalIdFactory = new ExternalIdFactory(new ExternalIdKeyFactory(authConfig));
externalIdCache = CacheBuilder.newBuilder().build();
repoManager.createRepository(ALL_USERS).close();
- externalIdReader = new ExternalIdReader(repoManager, ALL_USERS, new DisabledMetricMaker());
+ externalIdReader =
+ new ExternalIdReader(repoManager, ALL_USERS, new DisabledMetricMaker(), externalIdFactory);
externalIdReaderSpy = Mockito.spy(externalIdReader);
loader = createLoader(true);
}
@@ -151,7 +158,8 @@
ObjectId head =
modifyExternalId(
externalId(1, 1),
- ExternalId.create("fooschema", "bar1", Account.id(1), "foo@bar.com", "password"));
+ externalIdFactory.create(
+ "fooschema", "bar1", Account.id(1), "foo@bar.com", "password"));
assertThat(allFromGit(head).byAccount().size()).isEqualTo(1);
externalIdCache.put(firstState, allFromGit(firstState));
@@ -212,7 +220,8 @@
externalIdReaderSpy,
Providers.of(externalIdCache),
new DisabledMetricMaker(),
- cfg);
+ cfg,
+ externalIdFactory);
}
private AllExternalIds allFromGit(ObjectId revision) throws Exception {
@@ -256,13 +265,14 @@
}
private ExternalId externalId(int key, int accountId) {
- return ExternalId.create("fooschema", "bar" + key, Account.id(accountId));
+ return externalIdFactory.create("fooschema", "bar" + key, Account.id(accountId));
}
private ObjectId performExternalIdUpdate(Consumer<ExternalIdNotes> update) throws Exception {
try (Repository repo = repoManager.openRepository(ALL_USERS)) {
PersonIdent updater = new PersonIdent("Foo bar", "foo@bar.com");
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(ALL_USERS, repo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(ALL_USERS, repo, externalIdFactory);
update.accept(extIdNotes);
try (MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, null, repo)) {
diff --git a/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java b/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java
index cd28ac4..5e3be9a 100644
--- a/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java
+++ b/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java
@@ -71,6 +71,7 @@
@Inject private ProjectConfig.Factory projectConfigFactory;
@Inject private GerritApi gApi;
@Inject private ProjectOperations projectOperations;
+ @Inject private AuthRequest.Factory authRequestFactory;
private LifecycleManager lifecycle;
private Account.Id userId;
@@ -87,7 +88,7 @@
lifecycle.start();
schemaCreator.create();
- userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ userId = accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
user = userFactory.create(userId);
requestContext.setContext(() -> user);
diff --git a/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java b/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java
index 92a5fbe..d16efc3 100644
--- a/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java
+++ b/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java
@@ -56,25 +56,33 @@
.build();
ExternalId extId1 =
ExternalId.create(
- ExternalId.Key.create(ExternalId.SCHEME_MAILTO, "foo.bar@example.com"),
+ ExternalId.Key.create(ExternalId.SCHEME_MAILTO, "foo.bar@example.com", false),
id,
"foo.bar@example.com",
null,
ObjectId.fromString("1b9a0cf038ea38a0ab08617c39aa8e28413a27ca"));
ExternalId extId2 =
ExternalId.create(
- ExternalId.Key.create(ExternalId.SCHEME_USERNAME, "foo"),
+ ExternalId.Key.create(ExternalId.SCHEME_USERNAME, "foo", false),
id,
null,
"secret",
ObjectId.fromString("5b3a73dc9a668a5b89b5f049225261e3e3291d1a"));
+ ExternalId extId3 =
+ ExternalId.create(
+ ExternalId.Key.create(ExternalId.SCHEME_USERNAME, "Bar", true),
+ id,
+ null,
+ "secret",
+ ObjectId.fromString("483ea804e84282e15ddcdd1d15a797eb4796a760"));
List<String> values =
toStrings(
AccountField.EXTERNAL_ID_STATE.get(
- AccountState.forAccount(account, ImmutableSet.of(extId1, extId2))));
+ AccountState.forAccount(account, ImmutableSet.of(extId1, extId2, extId3))));
String expectedValue1 = extId1.key().sha1().name() + ":" + extId1.blobId().name();
String expectedValue2 = extId2.key().sha1().name() + ":" + extId2.blobId().name();
- assertThat(values).containsExactly(expectedValue1, expectedValue2);
+ String expectedValue3 = extId3.key().sha1().name() + ":" + extId3.blobId().name();
+ assertThat(values).containsExactly(expectedValue1, expectedValue2, expectedValue3);
}
private List<String> toStrings(Iterable<byte[]> values) {
diff --git a/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java b/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
index 1035fe7..5daf68e 100644
--- a/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
+++ b/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
@@ -64,6 +64,7 @@
@Inject protected AllProjectsName allProjects;
@Inject private CommitsCollection commits;
@Inject private ProjectOperations projectOperations;
+ @Inject private AuthRequest.Factory authRequestFactory;
private TestRepository<InMemoryRepository> repo;
private Project.NameKey project;
@@ -72,7 +73,8 @@
public void setUp() throws Exception {
setUpPermissions();
- Account.Id user = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ Account.Id user =
+ accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
testEnvironment.setApiUser(user);
project = projectOperations.newProject().create();
repo = new TestRepository<>(repoManager.openRepository(project));
diff --git a/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java b/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
index 7e1e821..2212fe7 100644
--- a/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
+++ b/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.LabelValue;
@@ -72,7 +73,7 @@
}
@Test
- public void defaultSubmitRule_WithLabelsAllPass() {
+ public void defaultSubmitRule_withLabelsAllPass() {
SubmitRecord submitRecord =
createSubmitRecord(
"gerrit~DefaultSubmitRule",
@@ -100,7 +101,7 @@
}
@Test
- public void defaultSubmitRule_WithLabelsAllNeed() {
+ public void defaultSubmitRule_withLabelsAllNeed() {
SubmitRecord submitRecord =
createSubmitRecord(
"gerrit~DefaultSubmitRule",
@@ -128,7 +129,7 @@
}
@Test
- public void customSubmitRule_NoLabels_WithStatusOk() {
+ public void customSubmitRule_noLabels_withStatusOk() {
SubmitRecord submitRecord =
createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.OK, Arrays.asList());
@@ -145,7 +146,24 @@
}
@Test
- public void customSubmitRule_NoLabels_WithStatusNotReady() {
+ public void customSubmitRule_nullLabels_withStatusOk() {
+ SubmitRecord submitRecord =
+ createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.OK, /* labels= */ null);
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(1);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "gerrit~IgnoreSelfApprovalRule",
+ /* submitExpression= */ "rule:gerrit~IgnoreSelfApprovalRule",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ }
+
+ @Test
+ public void customSubmitRule_noLabels_withStatusNotReady() {
SubmitRecord submitRecord =
createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.NOT_READY, Arrays.asList());
@@ -162,7 +180,7 @@
}
@Test
- public void customSubmitRule_WithLabels() {
+ public void customSubmitRule_withLabels() {
SubmitRecord submitRecord =
createSubmitRecord(
"gerrit~PrologRule",
@@ -203,7 +221,7 @@
}
private SubmitRecord createSubmitRecord(
- String ruleName, SubmitRecord.Status status, List<Label> labels) {
+ String ruleName, SubmitRecord.Status status, @Nullable List<Label> labels) {
SubmitRecord record = new SubmitRecord();
record.ruleName = ruleName;
record.status = status;
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index b7be40b..16f7199 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -65,6 +65,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
@@ -139,6 +140,10 @@
@Inject protected ExternalIds externalIds;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject protected AuthRequest.Factory authRequestFactory;
+
protected LifecycleManager lifecycle;
protected Injector injector;
protected AccountInfo currentUserInfo;
@@ -659,7 +664,7 @@
List<AccountExternalIdInfo> externalIdInfos = gApi.accounts().self().getExternalIds();
List<ByteArrayWrapper> blobs = new ArrayList<>();
for (AccountExternalIdInfo info : externalIdInfos) {
- Optional<ExternalId> extId = externalIds.get(ExternalId.Key.parse(info.identity));
+ Optional<ExternalId> extId = externalIds.get(externalIdKeyFactory.parse(info.identity));
assertThat(extId).isPresent();
blobs.add(new ByteArrayWrapper(extId.get().toByteArray()));
}
@@ -772,9 +777,10 @@
private Account.Id createAccount(String username, String fullName, String email, boolean active)
throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
@@ -791,7 +797,7 @@
private void addEmails(AccountInfo account, String... emails) throws Exception {
Account.Id id = Account.id(account._accountId);
for (String email : emails) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountIndexer.index(id);
}
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 5358d01..92cbc41 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -105,7 +105,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.VersionedAccountQueries;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeTriplet;
import com.google.gerrit.server.change.NotifyResolver;
@@ -192,6 +192,8 @@
@Inject protected ProjectCache projectCache;
@Inject protected MetaDataUpdate.Server metaDataUpdateFactory;
@Inject protected IdentifiedUser.GenericFactory identifiedUserFactory;
+ @Inject protected AuthRequest.Factory authRequestFactory;
+ @Inject protected ExternalIdFactory externalIdFactory;
@Inject private ProjectConfig.Factory projectConfigFactory;
@Inject private ProjectOperations projectOperations;
@@ -226,14 +228,16 @@
protected void setUpDatabase() throws Exception {
schemaCreator.create();
- userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ userId = accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
String email = "user@example.com";
accountsUpdate
.get()
.update(
"Add Email",
userId,
- u -> u.addExternalId(ExternalId.createEmail(userId, email)).setPreferredEmail(email));
+ u ->
+ u.addExternalId(externalIdFactory.createEmail(userId, email))
+ .setPreferredEmail(email));
resetUser();
}
@@ -417,7 +421,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
// No private changes.
@@ -585,7 +589,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
assertQuery("is:owner", change1);
@@ -699,7 +703,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
Change change3 = insert(repo, newChange(repo), user2);
gApi.changes().id(change3.getId().get()).current().review(ReviewInput.approve());
@@ -989,7 +993,7 @@
@Test
public void byLabel() throws Exception {
- accountManager.authenticate(AuthRequest.forUser("anotheruser"));
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser"));
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo);
ChangeInserter ins2 = newChange(repo);
@@ -1203,7 +1207,7 @@
}
private Account.Id createAccount(String name) throws Exception {
- return accountManager.authenticate(AuthRequest.forUser(name)).getAccountId();
+ return accountManager.authenticate(authRequestFactory.createForUser(name)).getAccountId();
}
@Test
@@ -1363,7 +1367,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
for (int i = 0; i < 5; i++) {
insert(repo, newChange(repo), user2);
}
@@ -1376,7 +1380,7 @@
public void filterOutAllResults() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
for (int i = 0; i < 5; i++) {
insert(repo, newChange(repo), user2);
}
@@ -2162,11 +2166,11 @@
Account.Id user3 = createAccount("user3");
// Explicitly authenticate user2 and user3 so that display name gets set
- AuthRequest authRequest = AuthRequest.forUser("user2");
+ AuthRequest authRequest = authRequestFactory.createForUser("user2");
authRequest.setDisplayName("Another User");
authRequest.setEmailAddress("user2@example.com");
accountManager.authenticate(authRequest);
- authRequest = AuthRequest.forUser("user3");
+ authRequest = authRequestFactory.createForUser("user3");
authRequest.setDisplayName("Another User");
authRequest.setEmailAddress("user3@example.com");
accountManager.authenticate(authRequest);
@@ -2237,7 +2241,10 @@
Change change2 = insert(repo, newChange(repo));
int user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId().get();
+ accountManager
+ .authenticate(authRequestFactory.createForUser("anotheruser"))
+ .getAccountId()
+ .get();
ReviewInput input = new ReviewInput();
input.message = "toplevel";
@@ -2281,7 +2288,7 @@
}
@Test
- public void byNonExistingSubmitRule_ReturnsEmpty() throws Exception {
+ public void byNonExistingSubmitRule_returnsEmpty() throws Exception {
// Some submit rules could be removed from the gerrit.config but there can be records for
// merged changes in NoteDb for these rules. We allow querying for non-existent rules to handle
// this case.
@@ -2318,7 +2325,7 @@
gApi.changes().id(change2.getId().get()).current().createDraft(in);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
assertQuery("has:draft", change2, change1);
@@ -2375,7 +2382,7 @@
gApi.accounts().self().starChange(change2.getId().toString());
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
assertQuery("has:star", change2, change1);
assertQuery("star:star", change2, change1);
@@ -2393,7 +2400,7 @@
Change change3 = insert(repo, newChange(repo));
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
requestContext.setContext(newRequestContext(user2));
gApi.accounts().self().starChange(change1.getId().toString());
@@ -2415,7 +2422,7 @@
public void byIgnore() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change1 = insert(repo, newChange(repo), user2);
Change change2 = insert(repo, newChange(repo), user2);
@@ -2438,7 +2445,7 @@
Change change1 = insert(repo, newChange(repo));
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
ReviewInput input = new ReviewInput();
@@ -2556,7 +2563,7 @@
gApi.changes().id(change1.getId().get()).current().review(new ReviewInput().message("comment"));
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
requestContext.setContext(newRequestContext(user2));
gApi.changes().id(change2.getId().get()).current().review(new ReviewInput().message("comment"));
@@ -2622,7 +2629,7 @@
public void byReviewed() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Account.Id otherUser =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change1 = insert(repo, newChange(repo));
Change change2 = insert(repo, newChange(repo));
@@ -2642,9 +2649,12 @@
@Test
public void reviewerin() throws Exception {
- Account.Id user1 = accountManager.authenticate(AuthRequest.forUser("user1")).getAccountId();
- Account.Id user2 = accountManager.authenticate(AuthRequest.forUser("user2")).getAccountId();
- Account.Id user3 = accountManager.authenticate(AuthRequest.forUser("user3")).getAccountId();
+ Account.Id user1 =
+ accountManager.authenticate(authRequestFactory.createForUser("user1")).getAccountId();
+ Account.Id user2 =
+ accountManager.authenticate(authRequestFactory.createForUser("user2")).getAccountId();
+ Account.Id user3 =
+ accountManager.authenticate(authRequestFactory.createForUser("user3")).getAccountId();
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo));
@@ -3442,7 +3452,7 @@
AttentionSetInput input = new AttentionSetInput(userId.toString(), "reason 1");
gApi.changes().id(change.getChangeId()).addToAttentionSet(input);
Account.Id user2Id =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
// Add the second user as cc to ensure that user took part of the change and can be added to the
// attention set.
@@ -3494,7 +3504,7 @@
.isEqualTo("Unknown named destination: foo");
Account.Id anotherUserId =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
String destination1 = "refs/heads/master\trepo1";
String destination2 = "refs/heads/master\trepo2";
String destination3 = "refs/heads/master\trepo1\nrefs/heads/master\trepo2";
@@ -3571,7 +3581,7 @@
Change change2 = insert(repo, newChangeForBranch(repo, "stable"));
Account.Id anotherUserId =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
String queryListText =
"query1\tproject:repo\n"
+ "query2\tproject:repo status:open\n"
@@ -3673,7 +3683,7 @@
@Test
public void selfSucceedsForInactiveAccount() throws Exception {
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
TestRepository<Repo> repo = createProject("repo");
Change change = insert(repo, newChange(repo));
@@ -4053,9 +4063,10 @@
private Account.Id createAccount(String username, String fullName, String email, boolean active)
throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
diff --git a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
index f392747..568b5a0 100644
--- a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
@@ -106,6 +106,8 @@
@Inject protected GroupIndexCollection indexes;
+ @Inject protected AuthRequest.Factory authRequestFactory;
+
@Inject private GroupIndexCollection groupIndexes;
protected LifecycleManager lifecycle;
@@ -397,9 +399,10 @@
private Account.Id createAccountOutsideRequestContext(
String username, String fullName, String email, boolean active) throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
diff --git a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
index 2317c7e..60d1655 100644
--- a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
@@ -104,6 +104,8 @@
@Inject protected AllUsersName allUsers;
+ @Inject protected AuthRequest.Factory authRequestFactory;
+
protected LifecycleManager lifecycle;
protected Injector injector;
protected AccountInfo currentUserInfo;
@@ -309,9 +311,10 @@
private Account.Id createAccount(String username, String fullName, String email, boolean active)
throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
diff --git a/polygerrit-ui/app/api/styles.ts b/polygerrit-ui/app/api/styles.ts
index e393667..ded3beb 100644
--- a/polygerrit-ui/app/api/styles.ts
+++ b/polygerrit-ui/app/api/styles.ts
@@ -34,6 +34,7 @@
}
export interface Styles {
+ font: Style;
form: Style;
menuPage: Style;
subPage: Style;
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
index c41fe57..6efaf0c 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/iron-input/iron-input';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
index 46968eb..1438825 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
index 70242d8..c38f8be 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/gr-table-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
index 0c856bc..518abac 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-form-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 18862b5..596fe5b 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
index 98d21f9..6bc5d2a 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 9c98545..56e981a 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-menu-page-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
index f5ef86b..65f0564 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
index 3cef13f..de43dc6 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
index f572ac3..9948f8f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
@@ -36,11 +39,11 @@
<div id="loadedContent" class$="[[_computeLoadingClass(_loading)]]">
<h2 id="options" class="heading-2">Command</h2>
<div id="form">
- <h3>Create change</h3>
+ <h3 class="heading-3">Create change</h3>
<gr-button loading="[[_creatingChange]]" on-click="_createNewChange">
Create change
</gr-button>
- <h3>Edit repo config</h3>
+ <h3 class="heading-3">Edit repo config</h3>
<gr-button
id="editRepoConfig"
loading="[[_editingConfig]]"
@@ -48,7 +51,7 @@
>
Edit repo config
</gr-button>
- <h3 hidden="[[!_repoConfig.actions.gc.enabled]]">
+ <h3 class="heading-3" hidden="[[!_repoConfig.actions.gc.enabled]]">
[[_repoConfig.actions.gc.label]]
</h3>
<gr-button
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
index d132267..cd5b095 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -20,6 +20,7 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../shared/gr-download-commands/gr-download-commands';
import '../../shared/gr-select/gr-select';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
index ef0e6b4..71abec0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
index 37d969e..c31da77 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
@@ -63,7 +63,7 @@
class="cell"
colspan$="[[_computeColspan(changeSection, visibleChangeTableColumns, labelNames)]]"
>
- <h2>
+ <h2 class="heading-3">
<a
href$="[[_sectionHref(changeSection.query)]]"
class="section-title"
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
index 4564bd1..fd2a5d7 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
@@ -21,6 +21,7 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, css, html} from 'lit';
import {customElement} from 'lit/decorators';
+import {fontStyles} from '../../../styles/gr-font-styles';
declare global {
interface HTMLElementTagNameMap {
@@ -33,6 +34,7 @@
static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
index ee64cfe..beadea3 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
@@ -21,6 +21,7 @@
import {WebLinkInfo} from '../../../types/diff';
import {appContext} from '../../../services/app-context';
import {sharedStyles} from '../../../styles/shared-styles';
+import {fontStyles} from '../../../styles/gr-font-styles';
import {dashboardHeaderStyles} from '../../../styles/dashboard-header-styles';
import {LitElement, css, html, PropertyValues} from 'lit';
import {customElement, property} from 'lit/decorators';
@@ -42,6 +43,7 @@
return [
sharedStyles,
dashboardHeaderStyles,
+ fontStyles,
css`
.browse {
display: inline-block;
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
index 2ba72c5..bc21dc0 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
@@ -25,6 +25,7 @@
import {appContext} from '../../../services/app-context';
import {dashboardHeaderStyles} from '../../../styles/dashboard-header-styles';
import {sharedStyles} from '../../../styles/shared-styles';
+import {fontStyles} from '../../../styles/gr-font-styles';
import {LitElement, css, html, PropertyValues} from 'lit';
import {customElement, property} from 'lit/decorators';
@@ -51,6 +52,7 @@
return [
sharedStyles,
dashboardHeaderStyles,
+ fontStyles,
css`
.status.hide,
.name.hide,
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
index e4e5122..90b9a2d 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
@@ -63,6 +63,7 @@
import {spinnerStyles} from '../../../styles/gr-spinner-styles';
import {modifierPressed} from '../../../utils/dom-util';
import {DropdownLink} from '../../shared/gr-dropdown/gr-dropdown';
+import {fontStyles} from '../../../styles/gr-font-styles';
export enum SummaryChipStyles {
INFO = 'info',
@@ -96,6 +97,7 @@
static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
.summaryChip {
color: var(--chip-color);
@@ -180,6 +182,7 @@
static override get styles() {
return [
+ fontStyles,
sharedStyles,
css`
:host {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
index 350cc1a..c705319 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
@@ -27,6 +27,7 @@
import {sharedStyles} from '../../../styles/shared-styles';
import {LitElement, css, html} from 'lit';
import {customElement, property, query} from 'lit/decorators';
+import {fontStyles} from '../../../styles/gr-font-styles';
@customElement('gr-confirm-submit-dialog')
export class GrConfirmSubmitDialog extends LitElement {
@@ -60,6 +61,7 @@
static get styles() {
return [
sharedStyles,
+ fontStyles,
css`
#dialog {
min-width: 40em;
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
index c946aa2..d0865c9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-font-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-download-commands/gr-download-commands';
import {PolymerElement} from '@polymer/polymer/polymer-element';
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts
index 6e40f84..097fb0e 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
index c11e484..d50e00f 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-input/iron-input';
import '../../../styles/shared-styles';
+import '../../../styles/gr-font-styles';
import '../../shared/gr-button/gr-button';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-included-in-dialog_html';
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
index 2029209..674b7e7 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
background-color: var(--dialog-background-color);
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts
index 5704ff9..7ca7226 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+import '../../../styles/gr-font-styles';
import '../../shared/gr-hovercard/gr-hovercard-shared-style';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {customElement, property} from '@polymer/decorators';
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts
index da7b780..6adb29e 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-hovercard-shared-style">
#container {
min-width: 356px;
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index 233ed93..de334be 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -73,6 +73,7 @@
import {GerritNav} from '../core/gr-navigation/gr-navigation';
import {DropdownLink} from '../shared/gr-dropdown/gr-dropdown';
import {subscribe} from '../lit/subscription-controller';
+import {fontStyles} from '../../styles/gr-font-styles';
@customElement('gr-result-row')
class GrResultRow extends LitElement {
@@ -756,6 +757,7 @@
return [
sharedStyles,
spinnerStyles,
+ fontStyles,
css`
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 5264452..d296a46 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -58,6 +58,7 @@
import {appContext} from '../../services/app-context';
import {KnownExperimentId} from '../../services/flags/flags';
import {subscribe} from '../lit/subscription-controller';
+import {fontStyles} from '../../styles/gr-font-styles';
@customElement('gr-checks-run')
export class GrChecksRun extends LitElement {
@@ -403,6 +404,7 @@
static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
index 8b4b851..d26856c 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import './gr-checks-styles';
+import '../../styles/gr-font-styles';
import {HovercardBehaviorMixin} from '../shared/gr-hovercard/gr-hovercard-behavior';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-hovercard-run_html';
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
index 47979a5..49a1416 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-checks-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
index ed3ac8d..0b191f1 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -17,6 +17,7 @@
import '../../shared/gr-button/gr-button';
import '../gr-key-binding-display/gr-key-binding-display';
import '../../../styles/shared-styles';
+import '../../../styles/gr-font-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-keyboard-shortcuts-dialog_html';
import {
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts
index 3576dfe..4992daa 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts
index 787fe30..85edc12 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts
@@ -49,12 +49,12 @@
</style>
<gr-overlay id="diffPrefsOverlay" with-backdrop="">
<div role="dialog" aria-labelledby="diffPreferencesTitle">
- <h1
- class$="diffHeader [[_computeHeaderClass(_diffPrefsChanged)]]"
+ <h3
+ class$="heading-3 diffHeader [[_computeHeaderClass(_diffPrefsChanged)]]"
id="diffPreferencesTitle"
>
Diff Preferences
- </h1>
+ </h3>
<gr-diff-preferences
id="diffPreferences"
diff-prefs="{{_editableDiffPrefs}}"
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
index 76047f4..5b757e6 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-input/iron-input';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
index 4800e5b..ce95ccb 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
h1 {
margin-bottom: var(--spacing-m);
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
index 0e61f98..64409d5 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
@@ -16,6 +16,7 @@
*/
import {LitElement, css, html} from 'lit';
import {customElement, property} from 'lit/decorators';
+import {formStyles} from '../../../styles/gr-form-styles';
declare global {
interface HTMLElementTagNameMap {
@@ -33,6 +34,7 @@
static override get styles() {
return [
+ formStyles,
css`
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 98ad66f..453bc3f 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-input/iron-input';
import '@polymer/paper-toggle-button/paper-toggle-button';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-menu-page-styles';
import '../../../styles/gr-page-nav-styles';
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
index 167417d..1ed0d57 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
color: var(--primary-text-color);
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index f39e5b8..27c6341 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '../gr-button/gr-button';
+import '../../../styles/gr-font-styles';
import '../../../styles/shared-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dialog_html';
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
index f8ddcfd..a5cf8f1 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
color: var(--primary-text-color);
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
index 73da0a2..a329736 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-icon/iron-icon';
+import '../../../styles/gr-font-styles';
import '../../../styles/shared-styles';
import '../gr-avatar/gr-avatar';
import '../gr-button/gr-button';
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
index dac5962..f1f6bf8 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
@@ -18,6 +18,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-hovercard-shared-style">
.top,
.attention,
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
index 3ee393c..85491ef 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
@@ -31,6 +31,7 @@
} from '../../../services/gr-event-interface/gr-event-interface';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {Gerrit} from '../../../api/gerrit';
+import {fontStyles} from '../../../styles/gr-font-styles';
import {formStyles} from '../../../styles/gr-form-styles';
import {menuPageStyles} from '../../../styles/gr-menu-page-styles';
import {subpageStyles} from '../../../styles/gr-subpage-styles';
@@ -121,6 +122,7 @@
public readonly Auth = appContext.authService;
public readonly styles = {
+ font: fontStyles,
form: formStyles,
menuPage: menuPageStyles,
subPage: subpageStyles,
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
index f7475bf..b039a7e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
@@ -104,7 +104,7 @@
* which endpoints to dynamically add to the page.
*/
registerModule(plugin: PluginApi, opts: Options) {
- const endpoint = opts.endpoint!;
+ const endpoint = opts.endpoint;
const dynamicEndpoint = opts.dynamicEndpoint;
if (dynamicEndpoint) {
if (!this._dynamicPlugins.has(dynamicEndpoint)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
deleted file mode 100644
index e3475ad..0000000
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * 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.
- */
-
-import '../../../test/common-test-setup-karma.js';
-import {resetPlugins} from '../../../test/test-utils.js';
-import './gr-js-api-interface.js';
-import {GrPluginEndpoints} from './gr-plugin-endpoints.js';
-import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-plugin-endpoints tests', () => {
- let instance;
- let pluginFoo;
- let pluginBar;
- let domHook;
-
- setup(() => {
- domHook = {};
- instance = new GrPluginEndpoints();
- pluginApi.install(p => { pluginFoo = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/foo.js');
- instance.registerModule(
- pluginFoo,
- {
- endpoint: 'a-place',
- type: 'decorate',
- moduleName: 'foo-module',
- domHook,
- }
- );
- pluginApi.install(p => { pluginBar = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/bar.js');
- instance.registerModule(
- pluginBar,
- {
- endpoint: 'a-place',
- type: 'style',
- moduleName: 'bar-module',
- domHook,
- }
- );
- });
-
- teardown(() => {
- resetPlugins();
- });
-
- test('getDetails all', () => {
- assert.deepEqual(instance.getDetails('a-place'), [
- {
- moduleName: 'foo-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'decorate',
- domHook,
- slot: undefined,
- },
- {
- moduleName: 'bar-module',
- plugin: pluginBar,
- pluginUrl: pluginBar._url,
- type: 'style',
- domHook,
- slot: undefined,
- },
- ]);
- });
-
- test('getDetails by type', () => {
- assert.deepEqual(instance.getDetails('a-place', {type: 'style'}), [
- {
- moduleName: 'bar-module',
- plugin: pluginBar,
- pluginUrl: pluginBar._url,
- type: 'style',
- domHook,
- slot: undefined,
- },
- ]);
- });
-
- test('getDetails by module', () => {
- assert.deepEqual(
- instance.getDetails('a-place', {moduleName: 'foo-module'}),
- [
- {
- moduleName: 'foo-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'decorate',
- domHook,
- slot: undefined,
- },
- ]);
- });
-
- test('getModules', () => {
- assert.deepEqual(
- instance.getModules('a-place'), ['foo-module', 'bar-module']);
- });
-
- test('getPlugins', () => {
- assert.deepEqual(
- instance.getPlugins('a-place'), [pluginFoo._url]);
- });
-
- test('onNewEndpoint', () => {
- const newModuleStub = sinon.stub();
- instance.setPluginsReady();
- instance.onNewEndpoint('a-place', newModuleStub);
- instance.registerModule(
- pluginFoo,
- {
- endpoint: 'a-place',
- type: 'replace',
- moduleName: 'zaz-module',
- domHook,
- });
- assert.deepEqual(newModuleStub.lastCall.args[0], {
- moduleName: 'zaz-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'replace',
- domHook,
- slot: undefined,
- });
- });
-
- test('reuse dom hooks', () => {
- instance.registerModule(
- pluginFoo, 'a-place', 'decorate', 'foo-module', domHook);
- assert.deepEqual(instance.getDetails('a-place'), [
- {
- moduleName: 'foo-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'decorate',
- domHook,
- slot: undefined,
- },
- {
- moduleName: 'bar-module',
- plugin: pluginBar,
- pluginUrl: pluginBar._url,
- type: 'style',
- domHook,
- slot: undefined,
- },
- ]);
- });
-});
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.ts
new file mode 100644
index 0000000..c7bdfb4
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.ts
@@ -0,0 +1,177 @@
+/**
+ * @license
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * 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.
+ */
+import '../../../test/common-test-setup-karma';
+import {resetPlugins} from '../../../test/test-utils';
+import './gr-js-api-interface';
+import {GrPluginEndpoints} from './gr-plugin-endpoints';
+import {_testOnly_initGerritPluginApi} from './gr-gerrit';
+import {PluginApi} from '../../../api/plugin';
+import {HookApi, HookCallback, PluginElement} from '../../../api/hook';
+
+const pluginApi = _testOnly_initGerritPluginApi();
+
+export class MockHook<T extends PluginElement> implements HookApi<T> {
+ handleInstanceDetached(_: T) {}
+
+ handleInstanceAttached(_: T) {}
+
+ getLastAttached(): Promise<HTMLElement> {
+ throw new Error('unimplemented in mock');
+ }
+
+ getAllAttached() {
+ return [];
+ }
+
+ onAttached(_: HookCallback<T>) {
+ return this;
+ }
+
+ onDetached(_: HookCallback<T>) {
+ return this;
+ }
+
+ getModuleName() {
+ return 'MockHookApi-ModuleName';
+ }
+}
+
+suite('gr-plugin-endpoints tests', () => {
+ let instance: GrPluginEndpoints;
+ let decoratePlugin: PluginApi;
+ let stylePlugin: PluginApi;
+ let domHook: HookApi<PluginElement>;
+
+ setup(() => {
+ domHook = new MockHook<PluginElement>();
+ instance = new GrPluginEndpoints();
+ pluginApi.install(
+ plugin => (decoratePlugin = plugin),
+ '0.1',
+ 'http://test.com/plugins/testplugin/static/decorate.js'
+ );
+ instance.registerModule(decoratePlugin, {
+ endpoint: 'my-endpoint',
+ type: 'decorate',
+ moduleName: 'decorate-module',
+ domHook,
+ });
+ pluginApi.install(
+ plugin => (stylePlugin = plugin),
+ '0.1',
+ 'http://test.com/plugins/testplugin/static/style.js'
+ );
+ instance.registerModule(stylePlugin, {
+ endpoint: 'my-endpoint',
+ type: 'style',
+ moduleName: 'style-module',
+ domHook,
+ });
+ });
+
+ teardown(() => {
+ resetPlugins();
+ });
+
+ test('getDetails all', () => {
+ assert.deepEqual(instance.getDetails('my-endpoint'), [
+ {
+ moduleName: 'decorate-module',
+ plugin: decoratePlugin,
+ pluginUrl: decoratePlugin._url,
+ type: 'decorate',
+ domHook,
+ slot: undefined,
+ },
+ {
+ moduleName: 'style-module',
+ plugin: stylePlugin,
+ pluginUrl: stylePlugin._url,
+ type: 'style',
+ domHook,
+ slot: undefined,
+ },
+ ]);
+ });
+
+ test('getDetails by type', () => {
+ assert.deepEqual(
+ instance.getDetails('my-endpoint', {endpoint: 'a-place', type: 'style'}),
+ [
+ {
+ moduleName: 'style-module',
+ plugin: stylePlugin,
+ pluginUrl: stylePlugin._url,
+ type: 'style',
+ domHook,
+ slot: undefined,
+ },
+ ]
+ );
+ });
+
+ test('getDetails by module', () => {
+ assert.deepEqual(
+ instance.getDetails('my-endpoint', {
+ endpoint: 'my-endpoint',
+ moduleName: 'decorate-module',
+ }),
+ [
+ {
+ moduleName: 'decorate-module',
+ plugin: decoratePlugin,
+ pluginUrl: decoratePlugin._url,
+ type: 'decorate',
+ domHook,
+ slot: undefined,
+ },
+ ]
+ );
+ });
+
+ test('getModules', () => {
+ assert.deepEqual(instance.getModules('my-endpoint'), [
+ 'decorate-module',
+ 'style-module',
+ ]);
+ });
+
+ test('getPlugins URLs are unique', () => {
+ assert.equal(decoratePlugin._url, stylePlugin._url);
+ assert.deepEqual(instance.getPlugins('my-endpoint'), [decoratePlugin._url]);
+ });
+
+ test('onNewEndpoint', () => {
+ const newModuleStub = sinon.stub();
+ instance.setPluginsReady();
+ instance.onNewEndpoint('my-endpoint', newModuleStub);
+ instance.registerModule(decoratePlugin, {
+ endpoint: 'my-endpoint',
+ type: 'replace',
+ moduleName: 'replace-module',
+ domHook,
+ });
+ assert.deepEqual(newModuleStub.lastCall.args[0], {
+ moduleName: 'replace-module',
+ plugin: decoratePlugin,
+ pluginUrl: decoratePlugin._url,
+ type: 'replace',
+ domHook,
+ slot: undefined,
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
index 31a709a..026ca4c 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-voting-styles';
import '../../../styles/shared-styles';
import '../gr-account-label/gr-account-label';
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
index 1588020..f31b57f 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-voting-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/samples/repo-command.js b/polygerrit-ui/app/samples/repo-command.js
index acecd7d..6abb120 100644
--- a/polygerrit-ui/app/samples/repo-command.js
+++ b/polygerrit-ui/app/samples/repo-command.js
@@ -32,7 +32,7 @@
margin-bottom: var(--spacing-xxl);
}
</style>
- <h3>Plugin Bork</h3>
+ <h3 class="heading-3">Plugin Bork</h3>
<gr-button on-click="_handleCommandTap">Bork</gr-button>
`;
}
diff --git a/polygerrit-ui/app/styles/gr-font-styles.ts b/polygerrit-ui/app/styles/gr-font-styles.ts
new file mode 100644
index 0000000..422a7c5
--- /dev/null
+++ b/polygerrit-ui/app/styles/gr-font-styles.ts
@@ -0,0 +1,61 @@
+/**
+ * @license
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+import {css} from 'lit';
+
+export const fontStyles = css`
+ .font-normal {
+ font-size: var(--font-size-normal);
+ font-weight: var(--font-weight-normal);
+ line-height: var(--line-height-normal);
+ }
+ .font-small {
+ font-size: var(--font-size-small);
+ font-weight: var(--font-weight-normal);
+ line-height: var(--line-height-small);
+ }
+ .heading-1 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h1);
+ font-weight: var(--font-weight-h1);
+ line-height: var(--line-height-h1);
+ }
+ .heading-2 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h2);
+ font-weight: var(--font-weight-h2);
+ line-height: var(--line-height-h2);
+ }
+ .heading-3 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h3);
+ font-weight: var(--font-weight-h3);
+ line-height: var(--line-height-h3);
+ }
+ strong {
+ font-weight: var(--font-weight-bold);
+ }
+`;
+
+const $_documentContainer = document.createElement('template');
+$_documentContainer.innerHTML = `<dom-module id="gr-font-styles">
+ <template>
+ <style>
+ ${fontStyles.cssText}
+ </style>
+ </template>
+</dom-module>`;
+document.head.appendChild($_documentContainer.content);
diff --git a/polygerrit-ui/app/styles/shared-styles.ts b/polygerrit-ui/app/styles/shared-styles.ts
index 2edef49..b58d5b9 100644
--- a/polygerrit-ui/app/styles/shared-styles.ts
+++ b/polygerrit-ui/app/styles/shared-styles.ts
@@ -14,16 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import {css} from 'lit';
-// Mark the file as a module. Otherwise typescript assumes this is a script
-// and $_documentContainer is a global variable.
-// See: https://www.typescriptlang.org/docs/handbook/modules.html
-export {};
-
-const $_documentContainer = document.createElement('template');
-
export const sharedStyles = css`
/* CSS reset */
@@ -176,36 +168,6 @@
border-spacing: 0;
}
- /* Fonts */
-
- .font-normal {
- font-size: var(--font-size-normal);
- font-weight: var(--font-weight-normal);
- line-height: var(--line-height-normal);
- }
- .font-small {
- font-size: var(--font-size-small);
- font-weight: var(--font-weight-normal);
- line-height: var(--line-height-small);
- }
- .heading-1 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h1);
- font-weight: var(--font-weight-h1);
- line-height: var(--line-height-h1);
- }
- .heading-2 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h2);
- font-weight: var(--font-weight-h2);
- line-height: var(--line-height-h2);
- }
- .heading-3 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h3);
- font-weight: var(--font-weight-h3);
- line-height: var(--line-height-h3);
- }
iron-icon {
color: var(--deemphasized-text-color);
vertical-align: top;
@@ -261,9 +223,6 @@
/** This is needed for firefox */
--iron-autogrow-textarea_-_white-space: pre-wrap;
}
- strong {
- font-weight: var(--font-weight-bold);
- }
.assistive-tech-only {
user-select: none;
@@ -303,6 +262,7 @@
/** END: loading spiner */
`;
+const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="shared-styles">
<template>
<style>
@@ -310,5 +270,4 @@
</style>
</template>
</dom-module>`;
-
document.head.appendChild($_documentContainer.content);
diff --git a/proto/cache.proto b/proto/cache.proto
index 4f4c838..16e5e95 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -268,13 +268,14 @@
// com.google.gerrit.server.account.externalids.AllExternalIds.
// Next ID: 2
message AllExternalIdsProto {
- // Next ID: 6
+ // Next ID: 7
message ExternalIdProto {
string key = 1;
int32 accountId = 2;
string email = 3;
string password = 4;
bytes blobId = 5;
+ bool isCaseInsensitive = 6;
}
repeated ExternalIdProto external_id = 1;
}