diff options
Diffstat (limited to 'src/main/java/com/google/gerrit/server/openid/OpenIdServiceImpl.java')
-rw-r--r-- | src/main/java/com/google/gerrit/server/openid/OpenIdServiceImpl.java | 468 |
1 files changed, 0 insertions, 468 deletions
diff --git a/src/main/java/com/google/gerrit/server/openid/OpenIdServiceImpl.java b/src/main/java/com/google/gerrit/server/openid/OpenIdServiceImpl.java deleted file mode 100644 index aa956df4d4..0000000000 --- a/src/main/java/com/google/gerrit/server/openid/OpenIdServiceImpl.java +++ /dev/null @@ -1,468 +0,0 @@ -// Copyright (C) 2009 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.openid; - -import com.google.gerrit.client.Link; -import com.google.gerrit.client.SignInDialog; -import com.google.gerrit.client.SignInDialog.Mode; -import com.google.gerrit.client.auth.openid.DiscoveryResult; -import com.google.gerrit.client.auth.openid.OpenIdService; -import com.google.gerrit.client.auth.openid.OpenIdUtil; -import com.google.gerrit.client.reviewdb.Account; -import com.google.gerrit.server.IdentifiedUser; -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.cache.Cache; -import com.google.gerrit.server.cache.SelfPopulatingCache; -import com.google.gerrit.server.config.CanonicalWebUrl; -import com.google.gerrit.server.config.Nullable; -import com.google.gerrit.server.http.WebSession; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwtorm.client.KeyUtil; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.Singleton; -import com.google.inject.name.Named; - -import org.openid4java.consumer.ConsumerException; -import org.openid4java.consumer.ConsumerManager; -import org.openid4java.consumer.VerificationResult; -import org.openid4java.discovery.DiscoveryException; -import org.openid4java.discovery.DiscoveryInformation; -import org.openid4java.message.AuthRequest; -import org.openid4java.message.Message; -import org.openid4java.message.MessageException; -import org.openid4java.message.MessageExtension; -import org.openid4java.message.ParameterList; -import org.openid4java.message.ax.AxMessage; -import org.openid4java.message.ax.FetchRequest; -import org.openid4java.message.ax.FetchResponse; -import org.openid4java.message.sreg.SRegMessage; -import org.openid4java.message.sreg.SRegRequest; -import org.openid4java.message.sreg.SRegResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.List; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@Singleton -class OpenIdServiceImpl implements OpenIdService { - private static final Logger log = - LoggerFactory.getLogger(OpenIdServiceImpl.class); - - static final String RETURN_URL = "OpenID"; - - private static final String P_MODE = "gerrit.mode"; - private static final String P_TOKEN = "gerrit.token"; - private static final String P_REMEMBER = "gerrit.remember"; - private static final String P_CLAIMED = "gerrit.claimed"; - private static final int LASTID_AGE = 365 * 24 * 60 * 60; // seconds - - private static final String OPENID_MODE = "openid.mode"; - private static final String OMODE_CANCEL = "cancel"; - - private static final String SCHEMA_EMAIL = - "http://schema.openid.net/contact/email"; - private static final String SCHEMA_FIRSTNAME = - "http://schema.openid.net/namePerson/first"; - private static final String SCHEMA_LASTNAME = - "http://schema.openid.net/namePerson/last"; - - private final Provider<WebSession> webSession; - private final Provider<IdentifiedUser> identifiedUser; - private final Provider<String> urlProvider; - private final AccountManager accountManager; - private final ConsumerManager manager; - private final SelfPopulatingCache<String, List> discoveryCache; - - @Inject - OpenIdServiceImpl(final Provider<WebSession> cf, - final Provider<IdentifiedUser> iu, - @CanonicalWebUrl @Nullable final Provider<String> up, - @Named("openid") final Cache<String, List> openidCache, - final AccountManager am) throws ConsumerException { - webSession = cf; - identifiedUser = iu; - urlProvider = up; - accountManager = am; - manager = new ConsumerManager(); - - discoveryCache = new SelfPopulatingCache<String, List>(openidCache) { - @Override - protected List createEntry(final String url) throws Exception { - try { - final List<?> list = manager.discover(url); - return list != null && !list.isEmpty() ? list : null; - } catch (DiscoveryException e) { - return null; - } - } - }; - } - - public void discover(final String openidIdentifier, - final SignInDialog.Mode mode, final boolean remember, - final String returnToken, final AsyncCallback<DiscoveryResult> callback) { - final State state; - state = init(openidIdentifier, mode, remember, returnToken); - if (state == null) { - callback.onSuccess(new DiscoveryResult(false)); - return; - } - - final AuthRequest aReq; - try { - aReq = manager.authenticate(state.discovered, state.retTo.toString()); - aReq.setRealm(state.contextUrl); - - if (requestRegistration(aReq)) { - final SRegRequest sregReq = SRegRequest.createFetchRequest(); - sregReq.addAttribute("fullname", true); - sregReq.addAttribute("email", true); - aReq.addExtension(sregReq); - - final FetchRequest fetch = FetchRequest.createFetchRequest(); - fetch.addAttribute("FirstName", SCHEMA_FIRSTNAME, true); - fetch.addAttribute("LastName", SCHEMA_LASTNAME, true); - fetch.addAttribute("Email", SCHEMA_EMAIL, true); - aReq.addExtension(fetch); - } - } catch (MessageException e) { - callback.onSuccess(new DiscoveryResult(false)); - return; - } catch (ConsumerException e) { - callback.onSuccess(new DiscoveryResult(false)); - return; - } - - callback.onSuccess(new DiscoveryResult(true, aReq.getDestinationUrl(false), - aReq.getParameterMap())); - } - - private boolean requestRegistration(final AuthRequest aReq) { - if (AuthRequest.SELECT_ID.equals(aReq.getIdentity())) { - // We don't know anything about the identity, as the provider - // will offer the user a way to indicate their identity. Skip - // any database query operation and assume we must ask for the - // registration information, in case the identity is new to us. - // - return true; - - } - - // We might already have this account on file. Look for it. - // - try { - return accountManager.lookup(aReq.getIdentity()) == null; - } catch (AccountException e) { - log.warn("Cannot determine if user account exists", e); - return true; - } - } - - /** Called by {@link OpenIdLoginServlet} doGet, doPost */ - void doAuth(final HttpServletRequest req, final HttpServletResponse rsp) - throws Exception { - if (OMODE_CANCEL.equals(req.getParameter(OPENID_MODE))) { - cancel(req, rsp); - return; - } - - // Process the authentication response. - // - final SignInDialog.Mode mode = signInMode(req); - final String openidIdentifier = req.getParameter("openid.identity"); - final String claimedIdentifier = req.getParameter(P_CLAIMED); - final String returnToken = req.getParameter(P_TOKEN); - final boolean remember = "1".equals(req.getParameter(P_REMEMBER)); - final String rediscoverIdentifier = - claimedIdentifier != null ? claimedIdentifier : openidIdentifier; - final State state; - - state = init(rediscoverIdentifier, mode, remember, returnToken); - if (state == null) { - // Re-discovery must have failed, we can't run a login. - // - cancel(req, rsp); - return; - } - - final String returnTo = req.getParameter("openid.return_to"); - if (returnTo != null && returnTo.contains("openid.rpnonce=")) { - // Some providers (claimid.com) seem to embed these request - // parameters into our return_to URL, and then give us them - // in the return_to request parameter. But not all. - // - state.retTo.put("openid.rpnonce", req.getParameter("openid.rpnonce")); - state.retTo.put("openid.rpsig", req.getParameter("openid.rpsig")); - } - - final VerificationResult result = - manager.verify(state.retTo.toString(), new ParameterList(req - .getParameterMap()), state.discovered); - if (result.getVerifiedId() == null /* authentication failure */) { - if ("Nonce verification failed.".equals(result.getStatusMsg())) { - // We might be suffering from clock skew on this system. - // - log.error("OpenID failure: " + result.getStatusMsg() - + " Likely caused by clock skew on this server," - + " install/configure NTP."); - cancelWithError(req, rsp, result.getStatusMsg()); - - } else if (result.getStatusMsg() != null) { - // Authentication failed. - // - log.error("OpenID failure: " + result.getStatusMsg()); - cancelWithError(req, rsp, result.getStatusMsg()); - - } else { - // Assume authentication was canceled. - // - cancel(req, rsp); - } - return; - } - - final Message authRsp = result.getAuthResponse(); - SRegResponse sregRsp = null; - FetchResponse fetchRsp = null; - - if (authRsp.hasExtension(SRegMessage.OPENID_NS_SREG)) { - final MessageExtension ext = - authRsp.getExtension(SRegMessage.OPENID_NS_SREG); - if (ext instanceof SRegResponse) { - sregRsp = (SRegResponse) ext; - } - } - - if (authRsp.hasExtension(AxMessage.OPENID_NS_AX)) { - final MessageExtension ext = authRsp.getExtension(AxMessage.OPENID_NS_AX); - if (ext instanceof FetchResponse) { - fetchRsp = (FetchResponse) ext; - } - } - - final com.google.gerrit.server.account.AuthRequest areq = - new com.google.gerrit.server.account.AuthRequest(openidIdentifier); - - if (sregRsp != null) { - areq.setDisplayName(sregRsp.getAttributeValue("fullname")); - areq.setEmailAddress(sregRsp.getAttributeValue("email")); - - } else if (fetchRsp != null) { - final String firstName = fetchRsp.getAttributeValue("FirstName"); - final String lastName = fetchRsp.getAttributeValue("LastName"); - final StringBuilder n = new StringBuilder(); - if (firstName != null && firstName.length() > 0) { - n.append(firstName); - } - if (lastName != null && lastName.length() > 0) { - if (n.length() > 0) { - n.append(' '); - } - n.append(lastName); - } - areq.setDisplayName(n.length() > 0 ? n.toString() : null); - areq.setEmailAddress(fetchRsp.getAttributeValue("Email")); - } - - if (claimedIdentifier != null) { - // The user used a claimed identity which has delegated to the verified - // identity we have in our AuthRequest above. We still should have a - // link between the two, so set one up if not present. - // - Account.Id claimedId = accountManager.lookup(claimedIdentifier); - Account.Id actualId = accountManager.lookup(areq.getExternalId()); - - if (claimedId != null && actualId != null) { - if (claimedId.equals(actualId)) { - // Both link to the same account, that's what we expected. - } else { - // This is (for now) a fatal error. There are two records - // for what might be the same user. - // - log.error("OpenID accounts disagree over user identity:\n" - + " Claimed ID: " + claimedId + " is " + claimedIdentifier - + "\n" + " Delgate ID: " + actualId + " is " - + areq.getExternalId()); - cancelWithError(req, rsp, "Contact site administrator"); - return; - } - - } else if (claimedId == null && actualId != null) { - // Older account, the actual was already created but the claimed - // 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(claimedIdentifier); - linkReq.setDisplayName(areq.getDisplayName()); - linkReq.setEmailAddress(areq.getEmailAddress()); - accountManager.link(actualId, linkReq); - - } else if (claimedId != null && actualId == null) { - // Claimed account already exists, but it smells like the user has - // changed their delegate to point to a different provider. Link - // the new provider. - // - accountManager.link(claimedId, areq); - - } else { - // Both are null, we are going to create a new account below. - } - } - - try { - switch (mode) { - case REGISTER: - case SIGN_IN: - final com.google.gerrit.server.account.AuthResult arsp; - arsp = accountManager.authenticate(areq); - - final Cookie lastId = new Cookie(OpenIdUtil.LASTID_COOKIE, ""); - lastId.setPath(req.getContextPath() + "/"); - if (remember) { - lastId.setValue(rediscoverIdentifier); - lastId.setMaxAge(LASTID_AGE); - } else { - lastId.setMaxAge(0); - } - rsp.addCookie(lastId); - webSession.get().login(arsp.getAccountId(), remember); - if (arsp.isNew() && claimedIdentifier != null) { - final com.google.gerrit.server.account.AuthRequest linkReq = - new com.google.gerrit.server.account.AuthRequest( - claimedIdentifier); - linkReq.setDisplayName(areq.getDisplayName()); - linkReq.setEmailAddress(areq.getEmailAddress()); - accountManager.link(arsp.getAccountId(), linkReq); - } - callback(arsp.isNew(), req, rsp); - break; - - case LINK_IDENTIY: - accountManager.link(identifiedUser.get().getAccountId(), areq); - callback(false, req, rsp); - break; - } - } catch (AccountException e) { - log.error("OpenID authentication failure", e); - cancelWithError(req, rsp, "Contact site administrator"); - } - } - - private boolean isSignIn(final SignInDialog.Mode mode) { - switch (mode) { - case SIGN_IN: - case REGISTER: - return true; - default: - return false; - } - } - - private static Mode signInMode(final HttpServletRequest req) { - try { - return SignInDialog.Mode.valueOf(req.getParameter(P_MODE)); - } catch (RuntimeException e) { - return SignInDialog.Mode.SIGN_IN; - } - } - - private void callback(final boolean isNew, final HttpServletRequest req, - final HttpServletResponse rsp) throws IOException { - String token = req.getParameter(P_TOKEN); - if (token == null || token.isEmpty() || token.startsWith("SignInFailure,")) { - token = Link.MINE; - } - - final StringBuilder rdr = new StringBuilder(); - rdr.append(urlProvider.get()); - rdr.append('#'); - if (isNew && !token.startsWith(Link.REGISTER + ",")) { - rdr.append(Link.REGISTER); - rdr.append(','); - } - rdr.append(token); - rsp.sendRedirect(rdr.toString()); - } - - private void cancel(final HttpServletRequest req, - final HttpServletResponse rsp) throws IOException { - if (isSignIn(signInMode(req))) { - webSession.get().logout(); - } - callback(false, req, rsp); - } - - private void cancelWithError(final HttpServletRequest req, - final HttpServletResponse rsp, final String errorDetail) - throws IOException { - final SignInDialog.Mode mode = signInMode(req); - if (isSignIn(mode)) { - webSession.get().logout(); - } - final StringBuilder rdr = new StringBuilder(); - rdr.append(urlProvider.get()); - rdr.append('#'); - rdr.append("SignInFailure"); - rdr.append(','); - rdr.append(mode.name()); - rdr.append(','); - rdr.append(errorDetail != null ? KeyUtil.encode(errorDetail) : ""); - rsp.sendRedirect(rdr.toString()); - } - - private State init(final String openidIdentifier, - final SignInDialog.Mode mode, final boolean remember, - final String returnToken) { - final List<?> list = discoveryCache.get(openidIdentifier); - if (list == null || list.isEmpty()) { - return null; - } - - final String contextUrl = urlProvider.get(); - final DiscoveryInformation discovered = manager.associate(list); - final UrlEncoded retTo = new UrlEncoded(contextUrl + RETURN_URL); - retTo.put(P_MODE, mode.name()); - if (returnToken != null && returnToken.length() > 0) { - retTo.put(P_TOKEN, returnToken); - } - if (remember) { - retTo.put(P_REMEMBER, "1"); - } - if (discovered.hasClaimedIdentifier()) { - retTo.put(P_CLAIMED, discovered.getClaimedIdentifier().getIdentifier()); - } - return new State(discovered, retTo, contextUrl); - } - - private static class State { - final DiscoveryInformation discovered; - final UrlEncoded retTo; - final String contextUrl; - - State(final DiscoveryInformation d, final UrlEncoded r, final String c) { - discovered = d; - retTo = r; - contextUrl = c; - } - } -} |