/****************************************************************************** * WebJavin - Java Web Framework. * * * * Copyright (c) 2011 - Sergey "Frosman" Lukjanov, me@frostman.ru * * * * 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 ru.frostman.web.indigo.openid; import org.openid4java.OpenIDException; import org.openid4java.consumer.ConsumerManager; import org.openid4java.consumer.VerificationResult; import org.openid4java.discovery.DiscoveryInformation; import org.openid4java.discovery.Identifier; import org.openid4java.message.AuthRequest; import org.openid4java.message.AuthSuccess; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.frostman.web.annotation.Action; import ru.frostman.web.annotation.Controller; import ru.frostman.web.annotation.Param; import ru.frostman.web.controller.Controllers; import ru.frostman.web.controller.View; import ru.frostman.web.session.JavinSession; import javax.servlet.http.HttpServletRequest; import java.util.List; import static ru.frostman.web.controller.Controllers.redirect; import static ru.frostman.web.controller.Controllers.redirectAbs; /** * @author slukjanov aka Frostman */ @Controller public class OpenIdController { private static final Logger log = LoggerFactory.getLogger(OpenIdController.class); private final static String YAHOO_ENDPOINT = "https://me.yahoo.com"; public final static String GOOGLE_ENDPOINT = "https://www.google.com/accounts/o8/id"; public static final String PARAM_PROVIDER = "provider"; public static final String PARAM_TARGET = "targetUrl"; public static final String ATTR_OPENID_DISCOVERY = "javin.openid.discovery"; public static final String ATTR_JAVIN_AUTH_EMAIL = "javin.auth.email"; public static final String ATTR_JAVIN_AUTH_SOURCE = "javin.auth.source"; public static final String AUTH_REDIRECT_URL = "/javin/indigo/openid/sendAuth"; public static final String CALLBACK_URL = "/javin/indigo/openid/callback"; //todo think about thread safety private static final ConsumerManager manager = new ConsumerManager(); //todo remove test url // http://localhost:8080/test/javin/indigo/openid/sendAuth?identifier=https://www.google.com/accounts/o8/id&targetUrl=/test @Action(AUTH_REDIRECT_URL) public View sendAuthRequest(@Param(PARAM_PROVIDER) String userSuppliedString, JavinSession session, @Param(PARAM_TARGET) String targetUrl) throws OpenIDException { // perform discovery on the user-supplied identifier List discoveries = manager.discover(userSuppliedString); // attempt to associate with the OpenID provider // and retrieve one service endpoint for authentication DiscoveryInformation discovered = manager.associate(discoveries); // store the discovery information in the user's session session.setAttribute(ATTR_OPENID_DISCOVERY, discovered); // obtain a AuthRequest message to be sent to the OpenID provider String callbackUrl = Controllers.urlFull(CALLBACK_URL) + "?targetUrl=" + targetUrl; AuthRequest authReq = manager.authenticate(discovered, callbackUrl); FetchRequest fetch = FetchRequest.createFetchRequest(); if (userSuppliedString.startsWith(GOOGLE_ENDPOINT)) { fetch.addAttribute("email", "http://axschema.org/contact/email", true); // fetch.addAttribute("firstName", "http://axschema.org/namePerson/first", true); // fetch.addAttribute("lastName", "http://axschema.org/namePerson/last", true); } else if (userSuppliedString.startsWith(YAHOO_ENDPOINT)) { fetch.addAttribute("email", "http://axschema.org/contact/email", true); // fetch.addAttribute("fullname", "http://axschema.org/namePerson", true); } else { // works for myOpenID fetch.addAttribute("email", "http://schema.openid.net/contact/email", true); // fetch.addAttribute("fullname", "http://schema.openid.net/namePerson", true); } // attach the extension to the authentication request authReq.addExtension(fetch); return redirectAbs(authReq.getDestinationUrl(true)); } @Action(CALLBACK_URL) public View callbackVerify(HttpServletRequest request, JavinSession session, @Param("targetUrl") String targetUrl) throws OpenIDException { // extract the parameters from the authentication response // (which comes in as a HTTP request from the OpenID provider) ParameterList response = new ParameterList(request.getParameterMap()); // retrieve the previously stored discovery information DiscoveryInformation discovered = (DiscoveryInformation) session.getAttribute(ATTR_OPENID_DISCOVERY); // extract the receiving URL from the HTTP request StringBuffer receivingURL = request.getRequestURL(); String queryString = request.getQueryString(); if (queryString != null && queryString.length() > 0) receivingURL.append("?").append(request.getQueryString()); // verify the response; ConsumerManager needs to be the same // (static) instance used to place the authentication request VerificationResult verification = manager.verify(receivingURL.toString(), response, discovered); // examine the verification result and extract the verified // identifier Identifier verified = verification.getVerifiedId(); if (verified != null) { AuthSuccess authSuccess = (AuthSuccess) verification.getAuthResponse(); if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) { FetchResponse fetchResp = (FetchResponse) authSuccess.getExtension(AxMessage.OPENID_NS_AX); List emails = fetchResp.getAttributeValues("email"); String email = (String) emails.get(0); //todo store credentials in session session.setAttribute(ATTR_JAVIN_AUTH_EMAIL, email); session.setAttribute(ATTR_JAVIN_AUTH_SOURCE, "openid"); log.info("OpenId login done with email: " + email); } } return redirect(targetUrl + "?verified=" + (verified != null)); } }