/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.openid; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.logging.Logger; 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.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.restlet.Context; import org.restlet.Request; import org.restlet.Response; import org.restlet.data.Form; import org.restlet.data.MediaType; import org.restlet.data.Reference; import org.restlet.engine.Engine; import org.restlet.representation.Representation; import org.restlet.representation.StringRepresentation; /** * Describes a relaying party, also known as a RP. * * @author Martin Svensson */ public class RelayingParty { private static Representation getForm(AuthRequest authReq) { StringBuilder sb = new StringBuilder(); sb.append("<html>"); sb.append("<head>"); sb.append("<title>OpenID HTML FORM Redirection</title>"); sb.append("</head>"); sb.append("<body onload=\"document.forms['openid-form-redirection'].submit();\">"); sb.append("<form name=\"openid-form-redirection\" action=\""); sb.append(authReq.getOPEndpoint()); sb.append("\" method=\"post\" accept-charset=\"utf-8\">"); for (Object key : authReq.getParameterMap().keySet()) { sb.append(" <input type=\"hidden\" name=\""); sb.append(key.toString()); // ${parameter.key} sb.append("\" value=\""); sb.append(authReq.getParameterMap().get(key)); sb.append("\"/>"); } sb.append("</form>"); sb.append("</body>"); sb.append("</html>"); return new StringRepresentation(sb.toString(), MediaType.TEXT_HTML); } private final ConsumerManager cm; private final Map<String, DiscoveryInformation> sessions; public RelayingParty() { this(new ConsumerManager()); } public RelayingParty(ConsumerManager cm) { this.cm = cm; this.sessions = new HashMap<String, DiscoveryInformation>(); } public String authRequest(String identifier, boolean sessionAware, boolean addReturnTo, String returnTo, Set<AttributeExchange> optionalAttrs, Set<AttributeExchange> requiredAttrs, Request req, Response res) throws Exception { List<?> discoveries = cm.discover(identifier); DiscoveryInformation di = cm.associate(discoveries); // return String sessionId = null; if (sessionAware && di != null) { getLogger().info("save discovery information to session"); sessionId = UUID.randomUUID().toString(); this.sessions.put(sessionId, di); Reference ref = new Reference(returnTo); ref.addQueryParameter("sessionId", sessionId); returnTo = ref.toString(); } if (addReturnTo) { Reference ref = new Reference(returnTo); ref.addQueryParameter("returnTo", "true"); returnTo = ref.toString(); } AuthRequest authReq = cm.authenticate(di, returnTo); FetchRequest fetch = null; // add attributes if (optionalAttrs != null) { fetch = FetchRequest.createFetchRequest(); for (AttributeExchange o : optionalAttrs) { fetch.addAttribute(o.getName(), o.getSchema(), false); } } if (requiredAttrs != null) { if (fetch == null) fetch = FetchRequest.createFetchRequest(); for (AttributeExchange r : requiredAttrs) { fetch.addAttribute(r.getName(), r.getSchema(), true); } } if (fetch != null) authReq.addExtension(fetch); if (di.isVersion2()) { getLogger().info("sending auth request using OpenId 2 form"); res.setEntity(getForm(authReq)); } else { getLogger().info( "sending auth request using OpenId 1 query parameters"); res.redirectTemporary(authReq.getDestinationUrl(true)); } return sessionId; } public Logger getLogger() { Logger result = null; Context context = Context.getCurrent(); if (context != null) { result = context.getLogger(); } if (result == null) { result = Engine.getLogger(this, "org.restlet.ext.openid.RP"); } return result; } public boolean hasReturnTo(Request request) { String val = request.getResourceRef().getQueryAsForm() .getFirstValue("returnTo"); return "true".equals(val) == true ? true : false; } public Identifier verify(Map<AttributeExchange, String> axResp, Request req, boolean sessionAware) throws Exception { // TODO: Make sure it can handle form based returns as well! Form params = req.getResourceRef().getQueryAsForm(); ParameterList response = new ParameterList(params.getValuesMap()); String sessionId = sessionAware ? params.getFirstValue("sessionId") : null; // retrieve the previously stored discovery information DiscoveryInformation discovered = sessionId != null ? sessions .get(sessionId) : null; getLogger().info( "retrieved discovery information from session: (" + sessionId + ") " + discovered); String received = req.getResourceRef().getHostIdentifier() + req.getResourceRef().getPath(); if (req.getResourceRef().hasQuery()) { received += "?" + req.getResourceRef().getQuery(); } VerificationResult verification = cm.verify(received, response, discovered); 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); MessageExtension ext = authSuccess .getExtension(AxMessage.OPENID_NS_AX); if (ext instanceof FetchResponse) { @SuppressWarnings("unchecked") List<String> aliases = (List<String>) fetchResp .getAttributeAliases(); for (String alias : aliases) { String value = fetchResp.getAttributeValue(alias); axResp.put(AttributeExchange.valueOf(alias), value); } } } } return verified; } }