Merge branch 'stable-2.10' into stable-2.11
* stable-2.10: Update version to 2.10.2 Release notes for Gerrit 2.10.2 Do not return 403 when clicking on Gitweb breadcrumb Add log messages to troubleshoot OAuth/OpenID linking Remove unused OAuthToken in authorisation URL OnlineReindexer: log the success/failure numbers on exit Update replication plugin OAuth: Allow to link claimed identity to existing accounts OAuth: Allow to change username Change-Id: Ia9fc371b9f957c8e0fc3e215084baa3d31dadd41
This commit is contained in:
31
ReleaseNotes/ReleaseNotes-2.10.2.txt
Normal file
31
ReleaseNotes/ReleaseNotes-2.10.2.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
Release notes for Gerrit 2.10.2
|
||||
===============================
|
||||
|
||||
There are no schema changes from link:ReleaseNotes-2.10.1.html[2.10.1].
|
||||
|
||||
Download:
|
||||
link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.2.war[
|
||||
https://gerrit-releases.storage.googleapis.com/gerrit-2.10.2.war]
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
* Work around MyersDiff infinite loop in PatchListLoader. If the MyersDiff diff
|
||||
doesn't finish within 5 seconds, interrupt it and fall back to a different diff
|
||||
algorithm. From the user perspective, the only difference when the infinite
|
||||
loop is detected is that the files in the commit will not be compared in-depth,
|
||||
which will result in bigger edit regions.
|
||||
|
||||
Secondary Index
|
||||
---------------
|
||||
|
||||
* Online reindexing: log the number of done/failed changes in the error_log.
|
||||
Administrators can use the logged information to decide whether to activate the
|
||||
new index version or not.
|
||||
|
||||
Gitweb
|
||||
------
|
||||
|
||||
* Do not return `Forbidden` when clicking on Gitweb breadcrumb. Now when the
|
||||
user clicks on the parent folder, redirect to Gerrit projects list screen with
|
||||
the parent folder path as the filter.
|
||||
@@ -9,6 +9,7 @@ Version 2.11.x
|
||||
[[2_10]]
|
||||
Version 2.10.x
|
||||
--------------
|
||||
* link:ReleaseNotes-2.10.2.html[2.10.2]
|
||||
* link:ReleaseNotes-2.10.1.html[2.10.1]
|
||||
* link:ReleaseNotes-2.10.html[2.10]
|
||||
|
||||
|
||||
@@ -22,30 +22,21 @@ import java.io.IOException;
|
||||
@ExtensionPoint
|
||||
public interface OAuthServiceProvider {
|
||||
|
||||
/**
|
||||
* Retrieve the request token.
|
||||
*
|
||||
* @return request token
|
||||
*/
|
||||
OAuthToken getRequestToken();
|
||||
|
||||
/**
|
||||
* Returns the URL where you should redirect your users to authenticate
|
||||
* your application.
|
||||
*
|
||||
* @param requestToken the request token you need to authorize
|
||||
* @return the URL where you should redirect your users
|
||||
* @return the OAuth service URL to redirect your users for authentication
|
||||
*/
|
||||
String getAuthorizationUrl(OAuthToken requestToken);
|
||||
String getAuthorizationUrl();
|
||||
|
||||
/**
|
||||
* Retrieve the access token
|
||||
*
|
||||
* @param requestToken request token (obtained previously)
|
||||
* @param verifier verifier code
|
||||
* @return access token
|
||||
*/
|
||||
OAuthToken getAccessToken(OAuthToken requestToken, OAuthVerifier verifier);
|
||||
OAuthToken getAccessToken(OAuthVerifier verifier);
|
||||
|
||||
/**
|
||||
* After establishing of secure communication channel, this method supossed to
|
||||
|
||||
@@ -20,15 +20,18 @@ public class OAuthUserInfo {
|
||||
private final String userName;
|
||||
private final String emailAddress;
|
||||
private final String displayName;
|
||||
private final String claimedIdentity;
|
||||
|
||||
public OAuthUserInfo(String externalId,
|
||||
String userName,
|
||||
String emailAddress,
|
||||
String displayName) {
|
||||
String displayName,
|
||||
String claimedIdentity) {
|
||||
this.externalId = externalId;
|
||||
this.userName = userName;
|
||||
this.emailAddress = emailAddress;
|
||||
this.displayName = displayName;
|
||||
this.claimedIdentity = claimedIdentity;
|
||||
}
|
||||
|
||||
public String getExternalId() {
|
||||
@@ -46,4 +49,8 @@ public class OAuthUserInfo {
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getClaimedIdentity() {
|
||||
return claimedIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,9 @@ public class OnlineReindexer {
|
||||
SiteIndexer.Result result =
|
||||
batchIndexer.indexAll(index, projectCache.all());
|
||||
if (!result.success()) {
|
||||
log.error("Online reindex of schema version {} failed", version(index));
|
||||
log.error("Online reindex of schema version {} failed. Successfully"
|
||||
+ " indexed {} changes, failed to index {} changes",
|
||||
version(index), result.doneCount(), result.failedCount());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@ java_library(
|
||||
'//gerrit-common:annotations',
|
||||
'//gerrit-extension-api:api',
|
||||
'//gerrit-httpd:httpd',
|
||||
'//gerrit-reviewdb:server',
|
||||
'//gerrit-server:server',
|
||||
'//lib:gson',
|
||||
'//lib:guava',
|
||||
'//lib:gwtorm',
|
||||
'//lib/commons:codec',
|
||||
'//lib/guice:guice',
|
||||
'//lib/guice:guice-servlet',
|
||||
|
||||
@@ -23,9 +23,11 @@ import com.google.gerrit.extensions.auth.oauth.OAuthUserInfo;
|
||||
import com.google.gerrit.extensions.auth.oauth.OAuthVerifier;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.httpd.WebSession;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.server.account.AccountException;
|
||||
import com.google.gerrit.server.account.AccountManager;
|
||||
import com.google.gerrit.server.account.AuthResult;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.servlet.SessionScoped;
|
||||
|
||||
@@ -87,8 +89,7 @@ class OAuthSession {
|
||||
}
|
||||
|
||||
log.debug("Login-Retrieve-User " + this);
|
||||
token = oauth.getAccessToken(null,
|
||||
new OAuthVerifier(request.getParameter("code")));
|
||||
token = oauth.getAccessToken(new OAuthVerifier(request.getParameter("code")));
|
||||
|
||||
user = oauth.getUserInfo(token);
|
||||
|
||||
@@ -103,7 +104,7 @@ class OAuthSession {
|
||||
} else {
|
||||
log.debug("Login-PHASE1 " + this);
|
||||
redirectUrl = request.getRequestURI();
|
||||
response.sendRedirect(oauth.getAuthorizationUrl(null) +
|
||||
response.sendRedirect(oauth.getAuthorizationUrl() +
|
||||
"&state=" + state);
|
||||
return false;
|
||||
}
|
||||
@@ -113,11 +114,48 @@ class OAuthSession {
|
||||
throws IOException {
|
||||
com.google.gerrit.server.account.AuthRequest areq =
|
||||
new com.google.gerrit.server.account.AuthRequest(user.getExternalId());
|
||||
AuthResult arsp;
|
||||
try {
|
||||
String claimedIdentifier = user.getClaimedIdentity();
|
||||
Account.Id actualId = accountManager.lookup(user.getExternalId());
|
||||
if (!Strings.isNullOrEmpty(claimedIdentifier)) {
|
||||
Account.Id claimedId = accountManager.lookup(claimedIdentifier);
|
||||
if (claimedId != null && actualId != null) {
|
||||
if (claimedId.equals(actualId)) {
|
||||
// Both link to the same account, that's what we expected.
|
||||
log.debug("OAuth2: claimed identity equals current id");
|
||||
} else {
|
||||
// This is (for now) a fatal error. There are two records
|
||||
// for what might be the same user.
|
||||
//
|
||||
log.error("OAuth accounts disagree over user identity:\n"
|
||||
+ " Claimed ID: " + claimedId + " is " + claimedIdentifier
|
||||
+ "\n" + " Delgate ID: " + actualId + " is "
|
||||
+ user.getExternalId());
|
||||
rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
} else if (claimedId != null && actualId == null) {
|
||||
// Claimed account already exists: link to it.
|
||||
//
|
||||
log.info("OAuth2: linking claimed identity to {}",
|
||||
claimedId.toString());
|
||||
try {
|
||||
accountManager.link(claimedId, areq);
|
||||
} catch (OrmException e) {
|
||||
log.error("Cannot link: " + user.getExternalId()
|
||||
+ " to user identity:\n"
|
||||
+ " Claimed ID: " + claimedId + " is " + claimedIdentifier);
|
||||
rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.debug("OAuth2: claimed identity is empty");
|
||||
}
|
||||
areq.setUserName(user.getUserName());
|
||||
areq.setEmailAddress(user.getEmailAddress());
|
||||
areq.setDisplayName(user.getDisplayName());
|
||||
AuthResult arsp;
|
||||
try {
|
||||
arsp = accountManager.authenticate(areq);
|
||||
} catch (AccountException e) {
|
||||
log.error("Unable to authenticate user \"" + user + "\"", e);
|
||||
|
||||
@@ -144,6 +144,7 @@ class OpenIdServiceImpl {
|
||||
final AuthRequest aReq;
|
||||
try {
|
||||
aReq = manager.authenticate(state.discovered, state.retTo.toString());
|
||||
log.debug("OpenID: openid-realm={}", state.contextUrl);
|
||||
aReq.setRealm(state.contextUrl);
|
||||
|
||||
if (requestRegistration(aReq)) {
|
||||
|
||||
@@ -40,8 +40,7 @@ public class DefaultRealm extends AbstractRealm {
|
||||
|
||||
@Override
|
||||
public boolean allowsEdit(final Account.FieldName field) {
|
||||
if (authConfig.getAuthType() == AuthType.HTTP
|
||||
|| authConfig.getAuthType() == AuthType.OAUTH) {
|
||||
if (authConfig.getAuthType() == AuthType.HTTP) {
|
||||
switch (field) {
|
||||
case USER_NAME:
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user