Java tutorial
/* * * Copyright (c) Anoigo. All rights reserved. * * A-Select is a trademark registered by SURFnet bv. * * This program is distributed under the EUPL 1.0 (http://osor.eu/eupl) * See the included LICENSE file for details. * * If you did not receive a copy of the LICENSE * please contact Anoigo. (http://www.anoigo.nl) */ package org.aselect.server.request.handler.xsaml20.sp; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.security.PrivateKey; import java.util.logging.Level; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.aselect.server.application.ApplicationManager; import org.aselect.server.config.ASelectConfigManager; import org.aselect.server.config.Version; import org.aselect.server.request.HandlerTools; import org.aselect.server.request.RequestState; import org.aselect.server.request.handler.xsaml20.PartnerData; import org.aselect.server.request.handler.xsaml20.Saml20_BaseHandler; import org.aselect.server.request.handler.xsaml20.Saml20_Metadata; import org.aselect.server.request.handler.xsaml20.Saml20_RedirectEncoder; import org.aselect.server.request.handler.xsaml20.SamlTools; import org.aselect.server.request.handler.xsaml20.SecurityLevel; import org.aselect.server.sam.ASelectSAMAgent; import org.aselect.system.error.Errors; import org.aselect.system.exception.ASelectCommunicationException; import org.aselect.system.exception.ASelectConfigException; import org.aselect.system.exception.ASelectException; import org.aselect.system.exception.ASelectSAMException; import org.aselect.system.sam.agent.SAMResource; import org.aselect.system.utils.BASE64Encoder; import org.aselect.system.utils.Base64Codec; import org.aselect.system.utils.Tools; import org.aselect.system.utils.Utils; import org.joda.time.DateTime; import org.opensaml.common.SAMLObjectBuilder; import org.opensaml.common.SAMLVersion; import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder; import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.RequestedAuthnContext; import org.opensaml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml2.metadata.Endpoint; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.ws.transport.http.HttpServletResponseAdapter; import org.opensaml.xml.Configuration; import org.opensaml.xml.XMLObjectBuilderFactory; import org.opensaml.xml.io.Marshaller; import org.opensaml.xml.io.MarshallerFactory; import org.opensaml.xml.security.x509.BasicX509Credential; import org.opensaml.xml.util.XMLHelper; import org.w3c.dom.Node; public class Xsaml20_ISTS extends Saml20_BaseHandler { private final static String MODULE = "Xsaml20_ISTS"; protected final String singleSignOnServiceBindingConstantREDIRECT = SAMLConstants.SAML2_REDIRECT_BINDING_URI; protected final String singleSignOnServiceBindingConstantHTTPPOST = SAMLConstants.SAML2_POST_BINDING_URI; private String _sServerId = null; // <server_id> in <aselect> private String _sAssertionConsumerUrl = null; private String _sPostTemplate = null; private String _sHttpMethod = "GET"; private String _sIdpResourceGroup = null; private String _sFallbackUrl = null; private String _sRedirectSyncTime = null; private boolean bIdpSelectForm = false; // Example configuration // // <handler id="saml20_ists" target="/saml20_ists.*" // class="org.aselect.server.request.handler.xsaml20.Xsaml20_ISTS"> // /* (non-Javadoc) * @see org.aselect.server.request.handler.xsaml20.Saml20_BaseHandler#init(javax.servlet.ServletConfig, java.lang.Object) */ @Override public void init(ServletConfig oServletConfig, Object oConfig) throws ASelectException { String sMethod = "init"; Object sam = null; Object agent = null; Object idpSection = null; try { super.init(oServletConfig, oConfig); } catch (ASelectException e) { // pass to caller throw e; } catch (Exception e) { _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Could not initialize", e); throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e); } _sServerId = ASelectConfigManager.getParamFromSection(null, "aselect", "server_id", true); _sHttpMethod = ASelectConfigManager.getSimpleParam(oConfig, "http_method", false); if (_sHttpMethod != null && _sHttpMethod.equalsIgnoreCase("POST")) _sHttpMethod = "POST"; else _sHttpMethod = "GET"; if (_sHttpMethod.equals("POST")) _sPostTemplate = readTemplateFromConfig(oConfig, "post_template"); String sUseIdpSelectForm = ASelectConfigManager.getSimpleParam(oConfig, "use_idp_select", false); if (sUseIdpSelectForm != null && sUseIdpSelectForm.equals("true")) bIdpSelectForm = true; _sIdpResourceGroup = ASelectConfigManager.getSimpleParam(oConfig, "resourcegroup", false); if (_sIdpResourceGroup == null) _sIdpResourceGroup = "federation-idp"; // backward compatibility _systemLogger.log(Level.INFO, MODULE, sMethod, "IDP resourcegroup=" + _sIdpResourceGroup); _sFallbackUrl = ASelectConfigManager.getSimpleParam(oConfig, "fallback_url", false); _systemLogger.log(Level.INFO, MODULE, sMethod, "fallback_url=" + _sFallbackUrl); // Find the resourcegroup sam = _configManager.getSection(null, "sam"); agent = _configManager.getSection(sam, "agent"); try { Object metaResourcegroup = _configManager.getSection(agent, "resourcegroup", "id=" + _sIdpResourceGroup); idpSection = _configManager.getSection(metaResourcegroup, "resource"); } catch (ASelectConfigException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No resourcegroup: " + _sIdpResourceGroup + " configured"); } // And pass it's resources to the metadata manager MetaDataManagerSp metadataMgr = MetaDataManagerSp.getHandle(); // will create the MetaDataManager object while (idpSection != null) { metadataMgr.processResourceSection(idpSection); idpSection = _configManager.getNextSection(idpSection); } metadataMgr.logIdPs(); // Get Assertion Consumer data from config try { Object oRequest = _configManager.getSection(null, "requests"); Object oHandlers = _configManager.getSection(oRequest, "handlers"); Object oHandler = _configManager.getSection(oHandlers, "handler"); Object oASelect = _configManager.getSection(null, "aselect"); String sRedirectUrl = _configManager.getParam(oASelect, "redirect_url"); for (; oHandler != null; oHandler = _configManager.getNextSection(oHandler)) { String sId = _configManager.getParam(oHandler, "id"); if (sId != null && !sId.equals("saml20_assertionconsumer")) continue; // The Assertion Consumer String sTarget = _configManager.getParam(oHandler, "target"); if (sTarget != null) { _systemLogger.log(Level.INFO, MODULE, sMethod, "id=" + sId + " target=" + sTarget); sTarget = sTarget.replace("\\", ""); sTarget = sTarget.replace(".*", ""); _sAssertionConsumerUrl = sRedirectUrl + sTarget; } } } catch (ASelectConfigException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config next section 'handler' found", e); throw new ASelectException(Errors.ERROR_ASELECT_INIT_ERROR, e); } } /* (non-Javadoc) * @see org.aselect.server.request.handler.IRequestHandler#process(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @SuppressWarnings("unchecked") public RequestState process(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ASelectException { String sMethod = "process"; String sRid; String sFederationUrl = null; PrintWriter pwOut = null; String sMyUrl = _sServerUrl; // extractAselectServerUrl(request); _systemLogger.log(Level.INFO, MODULE, sMethod, "MyUrl=" + sMyUrl + " MyId=" + getID() + " path=" + servletRequest.getPathInfo()); try { pwOut = Utils.prepareForHtmlOutput(servletRequest, servletResponse); sRid = servletRequest.getParameter("rid"); if (sRid == null) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Missing RID parameter"); throw new ASelectCommunicationException(Errors.ERROR_ASELECT_SERVER_INVALID_REQUEST); } // Find the associated session context _htSessionContext = _oSessionManager.getSessionContext(sRid); if (_htSessionContext == null) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No session found for RID: " + sRid); throw new ASelectException(Errors.ERROR_ASELECT_SERVER_INVALID_REQUEST); } // Session present Tools.resumeSensorData(_configManager, _systemLogger, _htSessionContext); //20111102, can change the session // 20091028, Bauke, let the user choose which IdP to use // 20110308, Bauke: changed, user chooses when "use_idp_select" is "true" // otherwise this handler uses it's own resource group to get a resource and sets "federation_url" // to the id of that resource sFederationUrl = servletRequest.getParameter("federation_url"); //int cnt = MetaDataManagerSp.getHandle().getIdpCount(); //if (cnt == 1) { // sFederationUrl = MetaDataManagerSp.getHandle().getDefaultIdP(); // there can only be one //} if (bIdpSelectForm && (!Utils.hasValue(sFederationUrl))) { // No Federation URL choice made yet, allow the user to choose String sIdpSelectForm = Utils.loadTemplateFromFile(_systemLogger, _configManager.getWorkingdir(), null/*subdir*/, "idpselect", _sUserLanguage, _configManager.getOrgFriendlyName(), Version.getVersion()); sIdpSelectForm = Utils.replaceString(sIdpSelectForm, "[rid]", sRid); // Not backward compatible! [aselect_url] used to be server_url/handler_id, // they're separated now to allow use of [aselect_url] in the traditional way too! sIdpSelectForm = Utils.replaceString(sIdpSelectForm, "[handler_url]", sMyUrl + "/" + getID()); sIdpSelectForm = Utils.replaceString(sIdpSelectForm, "[aselect_url]", sMyUrl); // 20110310 + "/" + getID()); sIdpSelectForm = Utils.replaceString(sIdpSelectForm, "[handler_id]", getID()); sIdpSelectForm = Utils.replaceString(sIdpSelectForm, "[a-select-server]", _sServerId); // 20110310 //sSelectForm = Utils.replaceString(sSelectForm, "[language]", sLanguage); sIdpSelectForm = _configManager.updateTemplate(sIdpSelectForm, _htSessionContext, servletRequest); // 20130822, Bauke: added to show requestor_friendly_name _systemLogger.log(Level.FINER, MODULE, sMethod, "Template updated, [handler_url]=" + sMyUrl + "/" + getID()); _htSessionContext.put("user_state", "state_idpselect"); _oSessionManager.setUpdateSession(_htSessionContext, _systemLogger); // 20120403, Bauke: was updateSession Tools.pauseSensorData(_configManager, _systemLogger, _htSessionContext); //20111102 can update the session pwOut.println(sIdpSelectForm); return new RequestState(null); } // federation_url was set or bIdpSelectForm is false _systemLogger.log(Level.FINER, MODULE, sMethod, "federation_url=" + sFederationUrl); _htSessionContext.put("user_state", "state_toidp"); // at least remove state_select _oSessionManager.setUpdateSession(_htSessionContext, _systemLogger); // 20120403, Bauke: was updateSession // 20110308, Bauke: new mechanism to get to the IdP using the SAM agent (allows redundant resources) // User choice was made, or "federation_url" was set programmatically ASelectSAMAgent samAgent = ASelectSAMAgent.getHandle(); SAMResource samResource = null; try { samResource = samAgent.getActiveResource(_sIdpResourceGroup); } catch (ASelectSAMException ex) { // no active resource // if a fallback is present: REDIRECT to the authsp if (Utils.hasValue(_sFallbackUrl)) { // Don't come back here: _htSessionContext.remove("forced_authsp"); // 20110331, Bauke: We leave forced_uid in place! // If we do, control can easily be transferred to e.g. DigiD //htSessionContext.remove("forced_uid"); _oSessionManager.setUpdateSession(_htSessionContext, _systemLogger); // 20120403, Bauke: added String sRedirectUrl = _sFallbackUrl; //sRedirectUrl = "[aselect_url]?request=direct_login1&rid=[rid]&authsp=Ldap&a-select-server=[a-select-server]"; sRedirectUrl = Utils.replaceString(sRedirectUrl, "[aselect_url]", sMyUrl); sRedirectUrl = Utils.replaceString(sRedirectUrl, "[a-select-server]", _sServerId); sRedirectUrl = Utils.replaceString(sRedirectUrl, "[rid]", sRid); //sRedirectUrl = Utils.replaceString(sRedirectUrl, "[language]", sLanguage); _systemLogger.log(Level.FINER, MODULE, sMethod, "Fallback REDIRECT to: " + sRedirectUrl); Tools.pauseSensorData(_configManager, _systemLogger, _htSessionContext); //20111102 can change the session //_oSessionManager.updateSession(sRid, _htSessionContext); // 20120403, Bauke: removed servletResponse.sendRedirect(sRedirectUrl); return new RequestState(null); } else { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No active resource available"); throw new ASelectSAMException(Errors.ERROR_ASELECT_SAM_UNAVALABLE); } } // The result is a single resource from our own resourcegroup sFederationUrl = samResource.getId(); _systemLogger.log(Level.FINER, MODULE, sMethod, "IdP resource id=" + sFederationUrl); // 20090811, Bauke: save type of Authsp to store in the TGT later on // This is needed to prevent session sync when we're not saml20 _htSessionContext.put("authsp_type", "saml20"); _htSessionContext.put("federation_url", sFederationUrl); _oSessionManager.setUpdateSession(_htSessionContext, _systemLogger); // 20120403, Bauke: was updateSession _systemLogger.log(Level.FINER, MODULE, sMethod, "Get MetaData FederationUrl=" + sFederationUrl); MetaDataManagerSp metadataMgr = MetaDataManagerSp.getHandle(); // RM_57_01 // RM_57_02 // We now support the Redirect and POST Binding String sDestination = null; if ("POST".equalsIgnoreCase(_sHttpMethod)) { sDestination = metadataMgr.getLocation(sFederationUrl, SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME, singleSignOnServiceBindingConstantHTTPPOST); } else { sDestination = metadataMgr.getLocation(sFederationUrl, SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME, singleSignOnServiceBindingConstantREDIRECT); } _systemLogger.log(Level.FINER, MODULE, sMethod, "Location retrieved=" + sDestination); if ("".equals(sDestination)) throw new ASelectException(Errors.ERROR_ASELECT_SERVER_INVALID_REQUEST); String sApplicationId = (String) _htSessionContext.get("app_id"); String sApplicationLevel = getApplicationLevel(sApplicationId); String sAuthnContextClassRefURI = SecurityLevel.convertLevelToAuthnContextClassRefURI(sApplicationLevel, _systemLogger); // 20100428, Bauke: old: String sAuthnContextClassRefURI = levelMap.get(sApplicationLevel); if (sAuthnContextClassRefURI == null) { // this level was not configured. Log it and inform the user _systemLogger.log(Level.WARNING, MODULE, sMethod, "Application Level " + sApplicationLevel + " is not configured"); throw new ASelectException(Errors.ERROR_ASELECT_SERVER_INVALID_APP_LEVEL); } // Send SAML request to the IDP XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); SAMLObjectBuilder<AuthnContextClassRef> authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) builderFactory .getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME); AuthnContextClassRef authnContextClassRef = authnContextClassRefBuilder.buildObject(); authnContextClassRef.setAuthnContextClassRef(sAuthnContextClassRefURI); SAMLObjectBuilder<RequestedAuthnContext> requestedAuthnContextBuilder = (SAMLObjectBuilder<RequestedAuthnContext>) builderFactory .getBuilder(RequestedAuthnContext.DEFAULT_ELEMENT_NAME); RequestedAuthnContext requestedAuthnContext = requestedAuthnContextBuilder.buildObject(); requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef); // 20100311, Bauke: added for eHerkenning PartnerData partnerData = MetaDataManagerSp.getHandle().getPartnerDataEntry(sFederationUrl); _systemLogger.log(Level.FINER, MODULE, sMethod, "Partnerdata: " + partnerData); String specialSettings = (partnerData == null) ? null : partnerData.getSpecialSettings(); if (specialSettings != null && specialSettings.contains("minimum")) requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); else requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT); // 20120706, Bauke: save in session, must be transferred to TGT and used for Digid4 session_sync mechanism String sst = partnerData.getRedirectSyncTime(); if (Utils.hasValue(sst)) { _htSessionContext.put("redirect_sync_time", sst); _htSessionContext.put("redirect_ists_url", sMyUrl + "/" + getID()); _htSessionContext.put("redirect_post_form", partnerData.getRedirectPostForm()); _oSessionManager.setUpdateSession(_htSessionContext, _systemLogger); } SAMLObjectBuilder<Issuer> issuerBuilder = (SAMLObjectBuilder<Issuer>) builderFactory .getBuilder(Issuer.DEFAULT_ELEMENT_NAME); Issuer issuer = issuerBuilder.buildObject(); // 20100311, Bauke: Alternate Issuer, added for eHerkenning if (partnerData != null && partnerData.getLocalIssuer() != null) issuer.setValue(partnerData.getLocalIssuer()); else issuer.setValue(sMyUrl); // AuthnRequest SAMLObjectBuilder<AuthnRequest> authnRequestbuilder = (SAMLObjectBuilder<AuthnRequest>) builderFactory .getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME); AuthnRequest authnRequest = authnRequestbuilder.buildObject(); // We should be able to set AssertionConsumerServiceIndex. This is according to saml specs mutually exclusive with // ProtocolBinding and AssertionConsumerServiceURL if (partnerData != null) _systemLogger.log(Level.FINER, MODULE, sMethod, "acsi=" + partnerData.getAssertionConsumerServiceindex()); if (partnerData != null && partnerData.getAssertionConsumerServiceindex() != null) { authnRequest.setAssertionConsumerServiceIndex( Integer.parseInt(partnerData.getAssertionConsumerServiceindex())); } else { // mutually exclusive // 20100311, Bauke: added for eHerkenning // The assertion consumer url must be set to the value in the Metadata: // 20101112, RH, added support for POST binding if (specialSettings != null && specialSettings.toUpperCase().contains("POST")) authnRequest.setProtocolBinding(Saml20_Metadata.singleSignOnServiceBindingConstantPOST); else // backward compatibility, defaults to ARTIFACT authnRequest .setProtocolBinding(Saml20_Metadata.assertionConsumerServiceBindingConstantARTIFACT); // We should be able to not set setAssertionConsumerServiceURL and let IDP get it from metadata // But not sure if all idp's will handle that well if (partnerData != null && partnerData.getDestination() != null) { if (!"".equals(partnerData.getDestination().trim())) { // if empty, let the idp look for the AssertionConsumerServiceURL in metadata authnRequest.setAssertionConsumerServiceURL(partnerData.getDestination()); } } else { // backward compatibility, default to _sAssertionConsumerUrl authnRequest.setAssertionConsumerServiceURL(_sAssertionConsumerUrl); } } // RH, 20140505, sn String sForcedAttrConServInd = ApplicationManager.getHandle() .getForcedAttrConsServIndex(sApplicationId); if (sForcedAttrConServInd != null) { authnRequest.setAttributeConsumingServiceIndex(Integer.parseInt(sForcedAttrConServInd)); } else { // RH, 20140505, en if (partnerData != null && partnerData.getAttributeConsumerServiceindex() != null) { authnRequest.setAttributeConsumingServiceIndex( Integer.parseInt(partnerData.getAttributeConsumerServiceindex())); } else { // be backwards compatible authnRequest.setAttributeConsumingServiceIndex(2); } } // RH, 20140505, n authnRequest.setDestination(sDestination); DateTime tStamp = new DateTime(); // Set interval conditions authnRequest = (AuthnRequest) SamlTools.setValidityInterval(authnRequest, tStamp, getMaxNotBefore(), getMaxNotOnOrAfter()); // 20100531, Bauke, use Rid but add part of the timestamp to make the ID unique // The AssertionConsumer will strip it off to regain our Rid value String timePostFix = String.format("%02d%02d%02d%03d", tStamp.getHourOfDay(), tStamp.getMinuteOfHour(), tStamp.getSecondOfMinute(), tStamp.getMillisOfSecond()); authnRequest.setID(sRid + timePostFix); authnRequest.setProviderName(_sServerId); authnRequest.setVersion(SAMLVersion.VERSION_20); authnRequest.setIssuer(issuer); authnRequest.setIssueInstant(new DateTime()); // 20100712 authnRequest.setRequestedAuthnContext(requestedAuthnContext); // Check if we have to set the ForceAuthn attribute // 20090613, Bauke: use forced_authenticate (not forced_logon)! Boolean bForcedAuthn = (Boolean) _htSessionContext.get("forced_authenticate"); if (bForcedAuthn == null) bForcedAuthn = false; // 20100311, Bauke: "force" special_setting added for eHerkenning if (bForcedAuthn || (specialSettings != null && specialSettings.contains("force"))) { _systemLogger.log(Level.INFO, MODULE, sMethod, "Setting the ForceAuthn attribute"); authnRequest.setForceAuthn(true); } // 20140924, RH: "force_passive" special_setting (only for testing yet) // If needed in production must have its own element/attribuut in config Boolean bForcedPassive = (Boolean) _htSessionContext.get("forced_passive"); if (bForcedPassive || (specialSettings != null && specialSettings.contains("passive"))) { _systemLogger.log(Level.INFO, MODULE, sMethod, "Setting the IsPassive attribute"); authnRequest.setIsPassive(true); } // Handle testdata if (partnerData.getTestdata4partner() != null) { String timeOffset = partnerData.getTestdata4partner().getIssueInstant(); if (timeOffset != null) { // if (timeOffset.startsWith("-")) { // authnRequest.setIssueInstant(new DateTime().minus(1000*Long.parseLong(timeOffset))); // } else { authnRequest.setIssueInstant(new DateTime().plus(1000 * Long.parseLong(timeOffset))); // } // RM_57_03 } if (partnerData.getTestdata4partner().getIssuer() != null) { authnRequest.getIssuer().setValue(partnerData.getTestdata4partner().getIssuer()); } if (partnerData.getTestdata4partner().getAuthnContextClassRefURI() != null) { // There should be one so take first authnRequest.getRequestedAuthnContext().getAuthnContextClassRefs().get(0) .setAuthnContextClassRef( partnerData.getTestdata4partner().getAuthnContextClassRefURI()); } if (partnerData.getTestdata4partner().getAuthnContextComparisonTypeEnumeration() != null) { if ("minimum".equalsIgnoreCase( partnerData.getTestdata4partner().getAuthnContextComparisonTypeEnumeration())) requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); else if ("exact".equalsIgnoreCase( partnerData.getTestdata4partner().getAuthnContextComparisonTypeEnumeration())) requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT); else if ("better".equalsIgnoreCase( partnerData.getTestdata4partner().getAuthnContextComparisonTypeEnumeration())) requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.BETTER); else if ("maximum".equalsIgnoreCase( partnerData.getTestdata4partner().getAuthnContextComparisonTypeEnumeration())) requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.MAXIMUM); } if (partnerData.getTestdata4partner().getForceAuthn() != null) { authnRequest .setForceAuthn(Boolean.parseBoolean(partnerData.getTestdata4partner().getForceAuthn())); } if (partnerData.getTestdata4partner().getProviderName() != null) { authnRequest.setProviderName(partnerData.getTestdata4partner().getProviderName()); } if (partnerData.getTestdata4partner().getAssertionConsumerServiceIndex() != null) { // RM_57_04 authnRequest.setAssertionConsumerServiceIndex( Integer.parseInt(partnerData.getTestdata4partner().getAssertionConsumerServiceIndex())); } if (partnerData.getTestdata4partner().getAssertionConsumerServiceURL() != null) { authnRequest.setAssertionConsumerServiceURL( partnerData.getTestdata4partner().getAssertionConsumerServiceURL()); } if (partnerData.getTestdata4partner().getDestination() != null) { authnRequest.setDestination(partnerData.getTestdata4partner().getDestination()); } } // 20100908, Bauke: Look for aselect_specials! // In app_url or in the caller's RelayState (if we're an IdP) String sSpecials = null; if (specialSettings != null && specialSettings.contains("relay_specials")) { sSpecials = Utils.getAselectSpecials(_htSessionContext, false/*leave base64*/, _systemLogger); } _systemLogger.log(Level.FINER, MODULE, sMethod, "<special_settings>=" + specialSettings + " aselect_specials=" + sSpecials); // Create the new RelayState String sRelayState = "idp=" + sFederationUrl; if (specialSettings != null && specialSettings.contains("relay_specials")) { if (Utils.hasValue(sSpecials)) sRelayState += "&aselect_specials=" + sSpecials; sRelayState = Base64Codec.encode(sRelayState.getBytes()); _systemLogger.log(Level.FINER, MODULE, sMethod, "RelayState=" + sRelayState); } // // We have the AuthnRequest, now get it to the other side // boolean useSha256 = (specialSettings != null && specialSettings.contains("sha256")); if (_sHttpMethod.equals("GET")) { // No use signing the AuthnRequest, it's even forbidden according to the Saml specs // Brent Putman quote: The Redirect-DEFLATE binding encoder strips off the protocol message's ds:Signature element (if even present) // before the marshalling and signing operations. Per the spec, it's not allowed to carry the signature that way. SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory .getBuilder(AssertionConsumerService.DEFAULT_ELEMENT_NAME); Endpoint samlEndpoint = endpointBuilder.buildObject(); samlEndpoint.setLocation(sDestination); samlEndpoint.setResponseLocation(sMyUrl); _systemLogger.log(Level.FINER, MODULE, sMethod, "GET EndPoint=" + samlEndpoint + " Destination=" + sDestination); //HttpServletResponseAdapter outTransport = SamlTools.createHttpServletResponseAdapter(response, sDestination); HttpServletResponseAdapter outTransport = new HttpServletResponseAdapter(servletResponse, (sDestination == null) ? false : sDestination.toLowerCase().startsWith("https")); // RH, 20081113, set appropriate headers outTransport.setHeader("Pragma", "no-cache"); outTransport.setHeader("Cache-Control", "no-cache, no-store"); BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); messageContext.setOutboundMessageTransport(outTransport); messageContext.setOutboundSAMLMessage(authnRequest); messageContext.setPeerEntityEndpoint(samlEndpoint); BasicX509Credential credential = new BasicX509Credential(); PrivateKey key = _configManager.getDefaultPrivateKey(); credential.setPrivateKey(key); messageContext.setOutboundSAMLMessageSigningCredential(credential); // 20091028, Bauke: use RelayState to transport rid to my AssertionConsumer messageContext.setRelayState(sRelayState); MarshallerFactory marshallerFactory = Configuration.getMarshallerFactory(); Marshaller marshaller = marshallerFactory.getMarshaller(messageContext.getOutboundSAMLMessage()); Node nodeMessageContext = marshaller.marshall(messageContext.getOutboundSAMLMessage()); _systemLogger.log(Level.FINER, MODULE, sMethod, "RelayState=" + sRelayState + " OutboundSAMLMessage:\n" + XMLHelper.prettyPrintXML(nodeMessageContext)); if (useSha256) { Saml20_RedirectEncoder encoder = new Saml20_RedirectEncoder(); // is a HTTPRedirectDeflateEncoder encoder.encode(messageContext); // does a sendRedirect() } else { // HTTPRedirectDeflateEncoder: SAML 2.0 HTTP Redirect encoder using the DEFLATE encoding method. // This encoder only supports DEFLATE compression and DSA-SHA1 and RSA-SHA1 signatures. HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); encoder.encode(messageContext); // does a sendRedirect() } _systemLogger.log(Level.FINER, MODULE, sMethod, "Ready " + messageContext); } else { // POST // 20100331, Bauke: added support for HTTP POST _systemLogger.log(Level.FINER, MODULE, sMethod, "Sign the authnRequest >======" + authnRequest); authnRequest = (AuthnRequest) SamlTools.signSamlObject(authnRequest, useSha256 ? "sha256" : "sha1", "true".equalsIgnoreCase(partnerData.getAddkeyname()), "true".equalsIgnoreCase(partnerData.getAddcertificate())); _systemLogger.log(Level.FINER, MODULE, sMethod, "Signed the authnRequest ======<" + authnRequest); String sAssertion = XMLHelper.nodeToString(authnRequest.getDOM()); _systemLogger.log(Level.FINER, MODULE, sMethod, "Assertion=" + sAssertion); try { byte[] bBase64Assertion = sAssertion.getBytes("UTF-8"); BASE64Encoder b64enc = new BASE64Encoder(); sAssertion = b64enc.encode(bBase64Assertion); } catch (UnsupportedEncodingException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, e.getMessage(), e); throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR); } // Let's POST the token String sInputs = buildHtmlInput("RelayState", sRelayState); // sInputs += buildHtmlInput("SAMLResponse", sAssertion); //Tools.htmlEncode(nodeMessageContext.getTextContent())); // RH, 20101104, this should be a SAMLRequest, we were just lucky the other side didn't bother sInputs += buildHtmlInput("SAMLRequest", sAssertion); //Tools.htmlEncode(nodeMessageContext.getTextContent())); // 20100317, Bauke: pass language to IdP (does not work in the GET version) String sLang = (String) _htSessionContext.get("language"); if (sLang != null) sInputs += buildHtmlInput("language", sLang); _systemLogger.log(Level.FINER, MODULE, sMethod, "Inputs=" + Utils.firstPartOf(sInputs, 200)); handlePostForm(_sPostTemplate, sDestination, sInputs, servletRequest, servletResponse); } Tools.pauseSensorData(_configManager, _systemLogger, _htSessionContext); //20111102 can change the session } catch (ASelectException e) { // pass unchanged to the caller throw e; } catch (Exception e) { _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Could not process", e); throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e); } finally { if (pwOut != null) pwOut.close(); // 20130821, Bauke: save friendly name after session is gone if (_htSessionContext != null) { String sStatus = (String) _htSessionContext.get("status"); String sAppId = (String) _htSessionContext.get("app_id"); if ("del".equals(sStatus) && Utils.hasValue(sAppId)) { String sUF = ApplicationManager.getHandle().getFriendlyName(sAppId); HandlerTools.setEncryptedCookie(servletResponse, "requestor_friendly_name", sUF, _configManager.getCookieDomain(), -1/*age*/, _systemLogger); } } _oSessionManager.finalSessionProcessing(_htSessionContext, true/*update session*/); } return new RequestState(null); } /** * Gets the application level. * * @param sApplicationId * the s application id * @return the application level * @throws ASelectException * the a select exception */ private String getApplicationLevel(String sApplicationId) throws ASelectException { String sMethod = "getApplicationLevel"; _systemLogger.log(Level.INFO, MODULE, sMethod, "Id=" + sApplicationId); Object oApplications = null; try { oApplications = _configManager.getSection(null, "applications"); } catch (ASelectConfigException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config section 'applications' found", e); throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e); } Object oApplication = null; try { oApplication = _configManager.getSection(oApplications, "application"); } catch (ASelectConfigException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config section 'application' found", e); throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR, e); } String sApplicationLevel = null; while (oApplication != null) { if (_configManager.getParam(oApplication, "id").equals(sApplicationId)) { sApplicationLevel = _configManager.getParam(oApplication, "level"); if (sApplicationLevel == null) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No config attribute 'level' found"); throw new ASelectException(Errors.ERROR_ASELECT_INTERNAL_ERROR); } return sApplicationLevel; } oApplication = _configManager.getNextSection(oApplication); } return null; } }