summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ostrovsky <david@ostrovsky.org>2015-04-18 22:11:31 +0200
committerDavid Ostrovsky <david@ostrovsky.org>2015-04-28 08:27:29 +0200
commit3ae7ec043f00515ee0f900b740487794311b74a1 (patch)
treea58dc0f025df7caa762ba5dd866da8aaa36f2d08
parente6782847f87166c650ad0ec172c6e64b5be3c432 (diff)
Hybrid OpenID/OAuth: Allow to link identity accross protocols
This change support all linking directions: * From OpenID to OAuth * From OAuth to OpenID * From OAuth to OAuth TEST PLAN: 1. Set up vanilla Gerrit site 2. Assign auth scheme to OpenID 3. Install gerrit-oauth-provider plugin 4. Configure GitHub or Google provider (or both) 5. Sign in with source identity 6. Click User => Settings => Identities => Link Another Identity 7. Select target identity from the login form 8. Confirm that the target identity is linked to the source identity GitHub-Bug: https://github.com/davido/gerrit-oauth-provider/issues/12 Change-Id: I06e5cfc2ad1dde81050b951c0b7f602461af7992
-rw-r--r--gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java14
-rw-r--r--gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java28
-rw-r--r--gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java5
3 files changed, 40 insertions, 7 deletions
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
index 93031fef62..e6bb25b382 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
@@ -178,6 +178,7 @@ class LoginForm extends HttpServlet {
|| oauthSession.isOAuthFinal(req))
&& !oauthSession.isLoggedIn()) {
oauthSession.setServiceProvider(oauthProvider);
+ oauthSession.setLinkMode(link);
oauthSession.login(req, res, oauthProvider);
}
}
@@ -303,7 +304,7 @@ class LoginForm extends HttpServlet {
oauthServiceProviders.byPlugin(pluginName);
for (Map.Entry<String, Provider<OAuthServiceProvider>> e
: m.entrySet()) {
- addProvider(providers, pluginName, e.getKey(),
+ addProvider(providers, link, pluginName, e.getKey(),
e.getValue().get().getName());
}
}
@@ -326,13 +327,18 @@ class LoginForm extends HttpServlet {
}
}
- private static void addProvider(Element form, String pluginName,
- String id, String serviceName) {
+ private static void addProvider(Element form, boolean link,
+ String pluginName, String id, String serviceName) {
Element div = form.getOwnerDocument().createElement("div");
div.setAttribute("id", id);
Element hyperlink = form.getOwnerDocument().createElement("a");
- hyperlink.setAttribute("href", String.format("?id=%s_%s",
+ StringBuilder u = new StringBuilder(String.format("?id=%s_%s",
pluginName, id));
+ if (link) {
+ u.append("&link");
+ }
+ hyperlink.setAttribute("href", u.toString());
+
hyperlink.setTextContent(serviceName +
" (" + pluginName + " plugin)");
div.appendChild(hyperlink);
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
index a02f52d5d0..fb3d135edb 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
@@ -27,11 +27,13 @@ import com.google.gerrit.httpd.CanonicalWebUrl;
import com.google.gerrit.httpd.LoginUrlToken;
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.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;
@@ -55,19 +57,23 @@ class OAuthSessionOverOpenID {
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
OAuthSessionOverOpenID(DynamicItem<WebSession> webSession,
+ Provider<IdentifiedUser> identifiedUser,
AccountManager accountManager,
CanonicalWebUrl urlProvider) {
this.state = generateRandomState();
this.webSession = webSession;
+ this.identifiedUser = identifiedUser;
this.accountManager = accountManager;
this.urlProvider = urlProvider;
}
@@ -96,7 +102,6 @@ class OAuthSessionOverOpenID {
log.debug("Login-Retrieve-User " + this);
token = oauth.getAccessToken(new OAuthVerifier(request.getParameter("code")));
-
user = oauth.getUserInfo(token);
if (isLoggedIn()) {
@@ -124,6 +129,7 @@ class OAuthSessionOverOpenID {
try {
String claimedIdentifier = user.getClaimedIdentity();
Account.Id actualId = accountManager.lookup(user.getExternalId());
+ // Use case 1: claimed identity was provided during handshake phase
if (!Strings.isNullOrEmpty(claimedIdentifier)) {
Account.Id claimedId = accountManager.lookup(claimedIdentifier);
if (claimedId != null && actualId != null) {
@@ -153,6 +159,18 @@ class OAuthSessionOverOpenID {
return;
}
}
+ } else if (linkMode) {
+ // Use case 2: link mode activated from the UI
+ 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;
+ } finally {
+ linkMode = false;
+ }
}
areq.setUserName(user.getUserName());
areq.setEmailAddress(user.getEmailAddress());
@@ -213,4 +231,12 @@ class OAuthSessionOverOpenID {
public OAuthServiceProvider getServiceProvider() {
return serviceProvider;
}
+
+ public void setLinkMode(boolean linkMode) {
+ this.linkMode = linkMode;
+ }
+
+ public boolean isLinkMode() {
+ return linkMode;
+ }
}
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java
index 53fc889305..dff456f2f7 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java
@@ -70,7 +70,9 @@ class OAuthWebFilterOverOpenID implements Filter {
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpSession httpSession = ((HttpServletRequest) request).getSession(false);
- if (currentUserProvider.get().isIdentifiedUser()) {
+ OAuthSessionOverOpenID oauthSession = oauthSessionProvider.get();
+ if (!oauthSession.isLinkMode()
+ && currentUserProvider.get().isIdentifiedUser()) {
if (httpSession != null) {
httpSession.invalidate();
}
@@ -80,7 +82,6 @@ class OAuthWebFilterOverOpenID implements Filter {
HttpServletResponse httpResponse = (HttpServletResponse) response;
- OAuthSessionOverOpenID oauthSession = oauthSessionProvider.get();
OAuthServiceProvider service = ssoProvider == null
? oauthSession.getServiceProvider()
: ssoProvider;