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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user