package net.sxip.openidcards.icdemo.web; import org.springframework.web.servlet.mvc.AbstractController; import org.springframework.web.servlet.ModelAndView; import org.apache.log4j.Logger; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.Map; import java.util.List; import java.util.HashMap; import java.util.LinkedHashMap; import org.openid4java.discovery.DiscoveryInformation; import org.openid4java.discovery.Identifier; import org.openid4java.discovery.DiscoveryException; import org.openid4java.message.ax.FetchRequest; import org.openid4java.message.ax.FetchResponse; import org.openid4java.message.ax.AxMessage; import org.openid4java.message.*; import org.openid4java.consumer.ConsumerManager; import org.openid4java.consumer.VerificationResult; import org.openid4java.infocard.InfocardException; import org.openid4java.OpenIDException; import org.openid4java.infocard.OpenIDToken; /** * @author Marius Scurtescu */ public class IndexController extends AbstractController { private static Logger _logger = Logger.getLogger(IndexController.class); private static final String LOGGEDIN ="loggedin"; // attribute typeUri -> "nice label / alias" private static HashMap _attributes = new HashMap(); static { _attributes.put("http://axschema.org/contact/email", "Email"); _attributes.put("http://axschema.org/namePerson/first", "FirstName"); _attributes.put("http://axschema.org/namePerson/last", "LastName"); _attributes.put("http://axschema.org/contact/phone/default", "Phone"); _attributes.put("http://axschema.org/contact/postalAddress/home", "Address"); _attributes.put("http://axschema.org/contact/city/home", "City"); _attributes.put("http://axschema.org/contact/postalCode/home", "ZipCode"); _attributes.put("http://axschema.org/contact/country/home", "Country"); _attributes.put("http://axschema.org/contact/web/blog", "Blog"); } private String _loginView; private String _homeView; private String _postView; private String _errorView; private String _stsUrl; private String _axUrl; private ConsumerManager _consumerManager; private String _baseUrl; public void setConsumerManager(ConsumerManager consumerManager) { this._consumerManager = consumerManager; } public void setLoginView(String loginView) { _loginView = loginView; } public void setHomeView(String homeView) { _homeView = homeView; } public void setPostView(String postView) { _postView = postView; } public void setErrorView(String _errorView) { this._errorView = _errorView; } public void setStsUrl(String stsUrl) { this._stsUrl = stsUrl; } public void setAxUrl(String axUrl) { this._axUrl = axUrl; } public void setBaseUrl(String baseUrl) { _baseUrl = baseUrl; } protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); String return_to = _baseUrl + request.getContextPath() + "/"; String mode = request.getParameter("openid.mode"); String xmlToken = request.getParameter("xmlToken"); String openIdIdentifier = request.getParameter("openid_identifier"); try { if (mode != null) { // received a standard OpenID response ParameterList openidResp = extractFromOpenIDPost(request); return processOpenIDResp(request, session, openidResp); } else if (xmlToken != null) { // received an xmlToken from an identity selector ParameterList openidResp = extractFromInfocardPost(request); return processOpenIDResp(request, session, openidResp); } else if (openIdIdentifier != null) { return buildFetchReq(openIdIdentifier, session, return_to); } else { if (request.getParameter("logout") != null) { _logger.info("Logging out..."); session.removeAttribute(LOGGEDIN); session.removeAttribute("message"); } if (session.getAttribute(LOGGEDIN) == null) { _logger.info("Showing login page..."); return showLoginPage(); } else { _logger.info("(Re)Showing home / data view..."); return new ModelAndView(_homeView); } } } catch (Exception e) { _logger.error("Error encountered: ", e); return new ModelAndView(_errorView); } } private ModelAndView showLoginPage() { Map model = new HashMap(); model.put("title", "OpenID Infocards Demo"); String loginMessage1 = "This is a demonstration of using OpenID Information Cards" + "* to log into an OpenID Relying Party.

\n" + "Besides OpenID Authentication, the Relying Party " + "also requests profile data using Information Card conventions, " + "and the values are returned in the OpenID assertion, " + "using the OpenID Attribute Exchange** extension.\n"; String loginMessage2 = "* You can get an OpenID Information Card " + "here." + "The OpenID Information Cards spec can be found " + "here." + "
** The OpenID Attribute Exchange spec " + "can be found here\""; model.put("contents", loginMessage1); model.put("contents2", loginMessage2); return new ModelAndView(_loginView, model); } private ModelAndView buildFetchReq(String identifier, HttpSession session, String return_to) throws OpenIDException { _logger.info("Building auth + fetch request for: " + identifier); Map model = new HashMap(); List discoveries; String errorMsg = ""; try { discoveries = _consumerManager.discover(identifier); } catch (DiscoveryException e) { _logger.error("Error while performing HTML discovery on " + identifier, e); discoveries = null; errorMsg = "

" + e.getMessage() + ""; } if (discoveries == null || discoveries.size() == 0) { _logger.error("Discovery failed on: " + identifier); model.put("message", "The " + identifier + " identifier could not be resolved." + errorMsg); return new ModelAndView(_loginView, model); } DiscoveryInformation discovered = _consumerManager.associate(discoveries); // store the discovery information in the session for later use session.setAttribute("discovered", discovered); FetchRequest fetch = FetchRequest.createFetchRequest(); for (String typeUri : _attributes.keySet()) { fetch.addAttribute(_attributes.get(typeUri), typeUri, false); } AuthRequest req = _consumerManager.authenticate(discovered, return_to); req.addExtension(fetch); model.put("message", req); _logger.info("Sending fetch request / auto-post view..."); return new ModelAndView(_postView, model); } private ParameterList extractFromInfocardPost(HttpServletRequest request) throws InfocardException { _logger.info("Extracting OpenID AuthResponse / Fetch Response from Infocard POST..." ); String xmlToken = request.getParameter("xmlToken"); request.getSession().setAttribute("openidAssertion", xmlToken); OpenIDToken token = OpenIDToken.createFromXmlToken(xmlToken); return token.getOpenIDParams(); } private ParameterList extractFromOpenIDPost(HttpServletRequest request) throws MessageException { _logger.info("Extracting OpenID AuthResponse / Fetch Response from OpenID POST..." ); ParameterList openidAssertion = new ParameterList(request.getParameterMap()); request.getSession().setAttribute("openidAssertion", openidAssertion.toString()); return openidAssertion; } private ModelAndView processOpenIDResp(HttpServletRequest request, HttpSession session, ParameterList openidResp) throws OpenIDException { _logger.info("Processing OpenID auth / fetch response..." ); Map model = new HashMap(); model.put("title", "OpenID 2.0 OpenID InfoCards Demo"); // retrieve the previously stored discovery information DiscoveryInformation discovered = (DiscoveryInformation) session.getAttribute("discovered"); StringBuffer receivingURL = request.getRequestURL(); String queryString = request.getQueryString(); if (queryString != null && queryString.length() > 0) receivingURL.append("?").append(request.getQueryString()); // verify the response VerificationResult verification = _consumerManager.verify( receivingURL.toString(), openidResp, discovered); verification.getVerifiedId(); Message authResponse = verification.getAuthResponse(); if (!(authResponse instanceof AuthSuccess)) { _logger.error("Negative auth response received; showing login view..."); model.put("message", "Negative authentication response received from the OpenID Provider."); return new ModelAndView(_loginView, model); } Identifier verified = verification.getVerifiedId(); String identifier; if (verified == null) { _logger.error("OpenID verification failed; showing login view..."); model.put("message", verification.getStatusMsg()); return new ModelAndView(_loginView, model); } else { identifier = verified.getIdentifier(); } AuthSuccess authSuccess = (AuthSuccess) authResponse; FetchResponse fetchResp = null; Map attributes = new LinkedHashMap(); MessageExtension ext; if ( authSuccess.hasExtension(AxMessage.OPENID_NS_AX) && (ext = authSuccess.getExtension(AxMessage.OPENID_NS_AX)) instanceof FetchResponse) { fetchResp = (FetchResponse) ext; // extract the rest of the optional attributes List aliases = fetchResp.getAttributeAliases(); Map types = fetchResp.getAttributeTypes(); String alias; List values; for (Object a : aliases) { alias = (String) a; values = fetchResp.getAttributeValues(alias); attributes.put(_attributes.get(types.get(alias)), values.size() > 0 ? (String) values.get(0) : null); } } session.setAttribute(LOGGEDIN, ""); session.setAttribute("attributes", attributes); session.setAttribute("identifier", identifier); session.setAttribute("message", fetchResp); _logger.info("AX success; showing home / data view..."); return new ModelAndView(_homeView, model); } }