/* * Atricore IDBus * * Copyright (c) 2009, Atricore Inc. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.atricore.idbus.capabilities.openid.main.binding; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.atricore.idbus.capabilities.openid.main.messaging.OpenIDAuthnResponse; import org.atricore.idbus.capabilities.openid.main.messaging.OpenIDMessage; import org.atricore.idbus.capabilities.openid.main.messaging.SubmitOpenIDV1AuthnRequest; import org.atricore.idbus.capabilities.openid.main.messaging.SubmitOpenIDV2AuthnRequest; import org.atricore.idbus.capabilities.sso.support.core.util.XmlUtils; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptor; import org.atricore.idbus.kernel.main.mediation.Channel; import org.atricore.idbus.kernel.main.mediation.MediationMessage; import org.atricore.idbus.kernel.main.mediation.MediationMessageImpl; import org.atricore.idbus.kernel.main.mediation.MediationState; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.AbstractMediationHttpBinding; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.CamelMediationMessage; import org.w3._1999.xhtml.*; import java.io.ByteArrayInputStream; import java.lang.Object; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @author <a href="mailto:gbrigandi@atricore.org">Gianluca Brigandi</a> */ public class OpenIDHttpPostBinding extends AbstractMediationHttpBinding { private static final Log logger = LogFactory.getLog(OpenIDHttpPostBinding.class); protected OpenIDHttpPostBinding(Channel channel) { super(OpenIDBinding.OPENID_HTTP_POST.getValue(), channel); } public MediationMessage createMessage(CamelMediationMessage message) { OpenIDAuthnResponse sm = new OpenIDAuthnResponse(); Exchange exchange = message.getExchange().getExchange(); logger.debug("Create Message Body from exchange " + exchange.getClass().getName()); Message httpMsg = exchange.getIn(); if (httpMsg.getHeader("http.requestMethod") == null) { if (logger.isDebugEnabled()) { Map<String, Object> h = httpMsg.getHeaders(); for (String key : h.keySet()) { logger.debug("CAMEL Header:" + key + ":" + h.get(key)); } } throw new IllegalArgumentException("Unknown message, no valid HTTP Method header found!"); } MediationState state = createMediationState(exchange); // extract the receiving URL from the HTTP request StringBuffer receivingURL = new StringBuffer((String) httpMsg.getHeader("org.atricore.idbus.http.RequestURL")); String queryString = (String) httpMsg.getHeader("org.atricore.idbus.http.QueryString"); if (queryString != null && queryString.length() > 0) receivingURL.append("?").append(queryString); // set relaying request's http parameters from transient variables HashMap<String, String> parametersMap = new HashMap<String, String>(); for (String tvarName : state.getTransientVarNames()) { String tvarValue = state.getTransientVariable(tvarName); parametersMap.put(tvarName, tvarValue); } sm.setParameterMap(parametersMap); sm.setReceivingUrl(receivingURL.toString()); return new MediationMessageImpl(message.getMessageId(), sm, null, null, null, state); } public void copyMessageToExchange(CamelMediationMessage openIdOut, Exchange exchange) { MediationMessage<OpenIDMessage> out = openIdOut.getMessage(); EndpointDescriptor ed = out.getDestination(); Message httpOut = exchange.getOut(); Message httpIn = exchange.getIn(); OpenIDMessage sm = out.getContent(); copyBackState(out.getState(), exchange); try { Html post = null; if (sm instanceof SubmitOpenIDV2AuthnRequest) { SubmitOpenIDV2AuthnRequest soar = (SubmitOpenIDV2AuthnRequest) sm; logger.debug("Submitting Authentication Request to OpenID 2.0 Identity Provider at " + soar.getOpEndpoint()); post = createHtmlPostMessage(soar.getOpEndpoint(), soar.getParameterMap()); String marshalledHttpResponseBody = XmlUtils.marshal(post, "http://www.w3.org/1999/xhtml", "html", new String[]{"org.w3._1999.xhtml"}); // ------------------------------------------------------------ // Prepare HTTP Response // ------------------------------------------------------------ copyBackState(out.getState(), exchange); httpOut.getHeaders().put("Cache-Control", "no-cache, no-store"); httpOut.getHeaders().put("Pragma", "no-cache"); httpOut.getHeaders().put("http.responseCode", 200); httpOut.getHeaders().put("Content-Type", "text/html"); handleCrossOriginResourceSharing(exchange); ByteArrayInputStream baos = new ByteArrayInputStream(marshalledHttpResponseBody.getBytes()); httpOut.setBody(baos); } else { // assume openid v1 SubmitOpenIDV1AuthnRequest soar = (SubmitOpenIDV1AuthnRequest) sm; logger.debug("Submitting Authentication Request to OpenID 2.0 Identity Provider at " + soar.getDestinationUrl()); httpOut.getHeaders().put("Cache-Control", "no-cache, no-store"); httpOut.getHeaders().put("Pragma", "no-cache"); httpOut.getHeaders().put("http.responseCode", 302); httpOut.getHeaders().put("Content-Type", "text/html"); httpOut.getHeaders().put("Location", soar.getDestinationUrl()); handleCrossOriginResourceSharing(exchange); } } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } protected Html createHtmlPostMessage(String url, Map parametersMap) throws Exception { Html html = createHtmlBaseMessage(); Body body = html.getBody(); Div pageDiv = (Div) body.getPOrH1OrH2().iterator().next(); Form form = new Form(); form.setMethod("post"); form.setAction(url); form.setId("postbinding"); form.setEnctype("application/x-www-form-urlencoded"); { // Noscript paragraph P paragraph = new P(); paragraph.setTitle("Note: Since your browser does not support JavaScript, you must press the Continue button once to proceed."); // TODO : i18n Noscript noscript = new Noscript(); noscript.getPOrH1OrH2().add(paragraph); body.getPOrH1OrH2().add(noscript); } { // Div with form fields Div divFields = new Div(); Iterator keyit = parametersMap.keySet().iterator(); String key; String value; while (keyit.hasNext()) { key = (String) keyit.next(); value = (String) parametersMap.get(key); Input input = new Input(); input.setType(InputType.HIDDEN); input.setName(key); input.setValue(value); divFields.getContent().add(input); } // Add first filds to form form.getPOrH1OrH2().add(divFields); } { // Create noscript submit button Noscript noscript = new Noscript(); Div divNoScript = new Div(); noscript.getPOrH1OrH2().add(divNoScript); Input submit = new Input(); submit.setType(InputType.SUBMIT); submit.setValue("Continue"); divNoScript.getContent().add(submit); form.getPOrH1OrH2().add(noscript); } // Part of post binding body.setOnload("document.forms.postbinding.submit();"); pageDiv.getContent().add(form); return html; } }