diff options
author | David Ostrovsky <david@ostrovsky.org> | 2015-04-18 22:10:16 +0200 |
---|---|---|
committer | David Ostrovsky <david@ostrovsky.org> | 2015-05-05 21:39:50 +0200 |
commit | 6269edfc68cff5019faaed0b57c9a5992d87b5a3 (patch) | |
tree | 727183ca4c2260b0521ddba688ab7fe20d722c4a | |
parent | 8ca666bdcc0431a4f41e854ebf49a4044ffa474c (diff) |
Allow to link user identity to another OAuth provider
GitHub-Bug: https://github.com/davido/gerrit-oauth-provider/issues/12
Change-Id: I9507d15983cd021ba883afbdf4e526091d55c517
3 files changed, 84 insertions, 37 deletions
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java index e0a6d8f9b8..1f4d7ed20f 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java @@ -59,7 +59,8 @@ public class MyIdentitiesScreen extends SettingsScreen { }); add(deleteIdentity); - if (Gerrit.getConfig().getAuthType() == AuthType.OPENID) { + if (Gerrit.getConfig().getAuthType() == AuthType.OPENID + || Gerrit.getConfig().getAuthType() == AuthType.OAUTH) { Button linkIdentity = new Button(Util.C.buttonLinkIdentity()); linkIdentity.addClickHandler(new ClickHandler() { @Override diff --git a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java index 739dffe52a..54e81de5f0 100644 --- a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java +++ b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java @@ -26,11 +26,14 @@ import com.google.gerrit.extensions.restapi.Url; import com.google.gerrit.httpd.CanonicalWebUrl; import com.google.gerrit.httpd.WebSession; import com.google.gerrit.reviewdb.client.Account; +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.gwtorm.server.OrmException; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.servlet.SessionScoped; import org.apache.commons.codec.binary.Base64; @@ -52,18 +55,22 @@ class OAuthSession { private static final SecureRandom randomState = newRandomGenerator(); private final String state; private final DynamicItem<WebSession> webSession; + private final Provider<IdentifiedUser> identifiedUser; private final AccountManager accountManager; private final CanonicalWebUrl urlProvider; private OAuthServiceProvider serviceProvider; private OAuthToken token; private OAuthUserInfo user; private String redirectToken; + private boolean linkMode; @Inject OAuthSession(DynamicItem<WebSession> webSession, + Provider<IdentifiedUser> identifiedUser, AccountManager accountManager, CanonicalWebUrl urlProvider) { this.state = generateRandomState(); + this.identifiedUser = identifiedUser; this.webSession = webSession; this.accountManager = accountManager; this.urlProvider = urlProvider; @@ -122,46 +129,19 @@ class OAuthSession { private void authenticateAndRedirect(HttpServletRequest req, HttpServletResponse rsp) throws IOException { - com.google.gerrit.server.account.AuthRequest areq = - new com.google.gerrit.server.account.AuthRequest(user.getExternalId()); + AuthRequest areq = new 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; - } + if (!authenticateWithIdentityClaimedDuringHandshake(areq, rsp, + claimedIdentifier)) { + return; + } + } else if (linkMode) { + if (!authenticateWithLinkedIdentity(areq, rsp)) { + return; } - } else { - log.debug("OAuth2: claimed identity is empty"); } areq.setUserName(user.getUserName()); areq.setEmailAddress(user.getEmailAddress()); @@ -181,6 +161,59 @@ class OAuthSession { rsp.sendRedirect(rdr.toString()); } + private boolean authenticateWithIdentityClaimedDuringHandshake( + AuthRequest req, HttpServletResponse rsp, String claimedIdentifier) + throws AccountException, IOException { + Account.Id claimedId = accountManager.lookup(claimedIdentifier); + Account.Id actualId = accountManager.lookup(user.getExternalId()); + 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 false; + } + } 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, req); + } catch (OrmException e) { + log.error("Cannot link: " + user.getExternalId() + + " to user identity:\n" + + " Claimed ID: " + claimedId + " is " + claimedIdentifier); + rsp.sendError(HttpServletResponse.SC_FORBIDDEN); + return false; + } + } + return true; + } + + private boolean authenticateWithLinkedIdentity(AuthRequest areq, + HttpServletResponse rsp) throws AccountException, IOException { + try { + accountManager.link(identifiedUser.get().getAccountId(), areq); + } catch (OrmException e) { + log.error("Cannot link: " + user.getExternalId() + + " to user identity: " + identifiedUser.get().getAccountId()); + rsp.sendError(HttpServletResponse.SC_FORBIDDEN); + return false; + } finally { + linkMode = false; + } + return true; + } + void logout() { token = null; user = null; @@ -224,4 +257,12 @@ class OAuthSession { public OAuthServiceProvider getServiceProvider() { return serviceProvider; } + + public void setLinkMode(boolean linkMode) { + this.linkMode = linkMode; + } + + public boolean isLinkMode() { + return linkMode; + } } diff --git a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java index 48963a6e51..5b9e4f1102 100644 --- a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java +++ b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java @@ -90,7 +90,12 @@ class OAuthWebFilter implements Filter { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpSession httpSession = ((HttpServletRequest) request).getSession(false); OAuthSession oauthSession = oauthSessionProvider.get(); - if (currentUserProvider.get().isIdentifiedUser()) { + boolean link = request.getParameter("link") != null; + if (link) { + oauthSession.setLinkMode(link); + } + if (!oauthSession.isLinkMode() + && currentUserProvider.get().isIdentifiedUser()) { if (httpSession != null) { httpSession.invalidate(); } |