protected AuthnRequest buildAuthnRequest(HttpServletRequest request) throws SSOAgentException { IssuerBuilder issuerBuilder = new IssuerBuilder(); Issuer issuer = issuerBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:assertion", "Issuer", "samlp"); issuer.setValue(ssoAgentConfig.getSAML2().getSPEntityId()); /* NameIDPolicy */ NameIDPolicyBuilder nameIdPolicyBuilder = new NameIDPolicyBuilder(); NameIDPolicy nameIdPolicy = nameIdPolicyBuilder.buildObject(); nameIdPolicy.setFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"); nameIdPolicy.setSPNameQualifier("Issuer"); nameIdPolicy.setAllowCreate(true); /* AuthnContextClass */ AuthnContextClassRefBuilder authnContextClassRefBuilder = new AuthnContextClassRefBuilder(); AuthnContextClassRef authnContextClassRef = authnContextClassRefBuilder.buildObject( "urn:oasis:names:tc:SAML:2.0:assertion", "AuthnContextClassRef", "saml"); authnContextClassRef.setAuthnContextClassRef( "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"); /* AuthnContex */ RequestedAuthnContextBuilder requestedAuthnContextBuilder = new RequestedAuthnContextBuilder(); RequestedAuthnContext requestedAuthnContext = requestedAuthnContextBuilder.buildObject(); requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT); requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef); DateTime issueInstant = new DateTime(); /* Creation of AuthRequestObject */ AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder(); AuthnRequest authRequest = authRequestBuilder.buildObject( "urn:oasis:names:tc:SAML:2.0:protocol", "AuthnRequest", "samlp"); authRequest.setForceAuthn(ssoAgentConfig.getSAML2().isForceAuthn()); authRequest.setIsPassive(ssoAgentConfig.getSAML2().isPassiveAuthn()); authRequest.setIssueInstant(issueInstant); authRequest.setProtocolBinding(ssoAgentConfig.getSAML2().getHttpBinding()); authRequest.setAssertionConsumerServiceURL(ssoAgentConfig.getSAML2().getACSURL()); authRequest.setIssuer(issuer); authRequest.setNameIDPolicy(nameIdPolicy); authRequest.setRequestedAuthnContext(requestedAuthnContext); authRequest.setID(SSOAgentUtils.createID()); authRequest.setVersion(SAMLVersion.VERSION_20); authRequest.setDestination(ssoAgentConfig.getSAML2().getIdPURL()); if (request.getAttribute(Extensions.LOCAL_NAME) != null) { authRequest.setExtensions((Extensions) request.getAttribute(Extensions.LOCAL_NAME)); } /* Requesting Attributes. This Index value is registered in the IDP */ if (ssoAgentConfig.getSAML2().getAttributeConsumingServiceIndex() != null && ssoAgentConfig.getSAML2().getAttributeConsumingServiceIndex().trim().length() > 0) { authRequest.setAttributeConsumingServiceIndex( Integer.parseInt(ssoAgentConfig.getSAML2().getAttributeConsumingServiceIndex())); } return authRequest; }
/** * Fills the request with required AuthNContext according to selected options. * * @param request request to fill * @param options options driving generation of the element */ protected void builNameIDPolicy(AuthnRequest request, WebSSOProfileOptions options) { if (options.getNameID() != null) { SAMLObjectBuilder<NameIDPolicy> builder = (SAMLObjectBuilder<NameIDPolicy>) builderFactory.getBuilder(NameIDPolicy.DEFAULT_ELEMENT_NAME); NameIDPolicy nameIDPolicy = builder.buildObject(); nameIDPolicy.setFormat(options.getNameID()); nameIDPolicy.setAllowCreate(options.isAllowCreate()); nameIDPolicy.setSPNameQualifier(getSPNameQualifier()); request.setNameIDPolicy(nameIDPolicy); } }
/** {@inheritDoc} */ protected void marshallAttributes(XMLObject samlObject, Element domElement) throws MarshallingException { NameIDPolicy policy = (NameIDPolicy) samlObject; if (policy.getFormat() != null) { domElement.setAttributeNS(null, NameIDPolicy.FORMAT_ATTRIB_NAME, policy.getFormat()); } if (policy.getSPNameQualifier() != null) { domElement.setAttributeNS( null, NameIDPolicy.SP_NAME_QUALIFIER_ATTRIB_NAME, policy.getSPNameQualifier()); } if (policy.getAllowCreateXSBoolean() != null) { domElement.setAttributeNS( null, NameIDPolicy.ALLOW_CREATE_ATTRIB_NAME, policy.getAllowCreateXSBoolean().toString()); } }
private AuthnRequest buildAuthnRequest( HttpServletRequest request, boolean isPassive, String idpUrl, AuthenticationContext context) throws SAMLSSOException { IssuerBuilder issuerBuilder = new IssuerBuilder(); Issuer issuer = issuerBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:assertion", "Issuer", "samlp"); String spEntityId = properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SP_ENTITY_ID); if (spEntityId != null && !spEntityId.isEmpty()) { issuer.setValue(spEntityId); } else { issuer.setValue("carbonServer"); } DateTime issueInstant = new DateTime(); /* Creation of AuthRequestObject */ AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder(); AuthnRequest authRequest = authRequestBuilder.buildObject( "urn:oasis:names:tc:SAML:2.0:protocol", "AuthnRequest", "samlp"); authRequest.setForceAuthn(isForceAuthenticate(context)); authRequest.setIsPassive(isPassive); authRequest.setIssueInstant(issueInstant); String includeProtocolBindingProp = properties.get( IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_PROTOCOL_BINDING); if (StringUtils.isEmpty(includeProtocolBindingProp) || Boolean.parseBoolean(includeProtocolBindingProp)) { authRequest.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); } String acsUrl = IdentityUtil.getServerURL(FrameworkConstants.COMMONAUTH); authRequest.setAssertionConsumerServiceURL(acsUrl); authRequest.setIssuer(issuer); authRequest.setID(SSOUtils.createID()); authRequest.setVersion(SAMLVersion.VERSION_20); authRequest.setDestination(idpUrl); String attributeConsumingServiceIndexProp = properties.get( IdentityApplicationConstants.Authenticator.SAML2SSO.ATTRIBUTE_CONSUMING_SERVICE_INDEX); if (StringUtils.isNotEmpty(attributeConsumingServiceIndexProp)) { try { authRequest.setAttributeConsumingServiceIndex( Integer.valueOf(attributeConsumingServiceIndexProp)); } catch (NumberFormatException e) { log.error( "Error while populating SAMLRequest with AttributeConsumingServiceIndex: " + attributeConsumingServiceIndexProp, e); } } String includeNameIDPolicyProp = properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_NAME_ID_POLICY); if (StringUtils.isEmpty(includeNameIDPolicyProp) || Boolean.parseBoolean(includeNameIDPolicyProp)) { NameIDPolicyBuilder nameIdPolicyBuilder = new NameIDPolicyBuilder(); NameIDPolicy nameIdPolicy = nameIdPolicyBuilder.buildObject(); nameIdPolicy.setFormat(NameIDType.UNSPECIFIED); // nameIdPolicy.setSPNameQualifier("Issuer"); nameIdPolicy.setAllowCreate(true); authRequest.setNameIDPolicy(nameIdPolicy); } // Get the inbound SAMLRequest AuthnRequest inboundAuthnRequest = getAuthnRequest(context); RequestedAuthnContext requestedAuthnContext = buildRequestedAuthnContext(inboundAuthnRequest); if (requestedAuthnContext != null) { authRequest.setRequestedAuthnContext(requestedAuthnContext); } Extensions extensions = getSAMLExtensions(request); if (extensions != null) { authRequest.setExtensions(extensions); } return authRequest; }
/* (non-Javadoc) * @see com.vmware.identity.samlservice.SamlValidator#validate(java.lang.Object) */ @Override public ValidationResult validate(AuthnRequestState t) { log.debug("Validating request {}", t); ValidationResult vr = null; try { Validate.notNull(t); HttpServletRequest httpRequest = t.getRequest(); Validate.notNull(httpRequest); AuthnRequest request = t.getAuthnRequest(); Validate.notNull(request); Validate.notNull(request.getIssuer()); IdmAccessor accessor = t.getIdmAccessor(); Validate.notNull(accessor); Validate.notNull(accessor.getTenant()); // Validate assertion consumer service first, if that is valid, we can send SAML replies try { boolean validateACSWithMetadata = !this.isRequestSigned(t); String acsUrl = accessor.getAcsForRelyingParty( request.getIssuer().getValue(), request.getAssertionConsumerServiceIndex(), request.getAssertionConsumerServiceURL(), request.getProtocolBinding(), validateACSWithMetadata); t.setAcsUrl(acsUrl); } catch (IllegalStateException e) { // set validation result to 400 log.debug("Caught illegal state exception while Validating {} returning 400", e.toString()); vr = new ValidationResult(HttpServletResponse.SC_BAD_REQUEST, e.getMessage(), null); } // Validate ID if (vr == null && request.getID() == null) { vr = new ValidationResult(OasisNames.REQUESTER); log.debug("Validation FAILED - Request ID is missing"); } // Validate version if (vr == null) { SAMLVersion version = request.getVersion(); if ((version.getMajorVersion() > Shared.REQUIRED_SAML_VERSION.getMajorVersion()) || version.getMajorVersion() == Shared.REQUIRED_SAML_VERSION.getMajorVersion() && version.getMinorVersion() > Shared.REQUIRED_SAML_VERSION.getMinorVersion()) { // version too high vr = new ValidationResult( OasisNames.VERSION_MISMATCH, OasisNames.REQUEST_VERSION_TOO_HIGH); log.debug("Validation FAILED - Version is too high"); } else if ((version.getMajorVersion() < Shared.REQUIRED_SAML_VERSION.getMajorVersion()) || version.getMajorVersion() == Shared.REQUIRED_SAML_VERSION.getMajorVersion() && version.getMinorVersion() < Shared.REQUIRED_SAML_VERSION.getMinorVersion()) { // version too low vr = new ValidationResult(OasisNames.VERSION_MISMATCH, OasisNames.REQUEST_VERSION_TOO_LOW); log.debug("Validation FAILED - Version is too low"); } } // Validate IssueInstant only if this is a new request (i.e. it had not pass been validated) if (vr == null && !t.isExistingRequest()) { DateTime dtPlus = request.getIssueInstant(); DateTime dtMinus = request.getIssueInstant(); DateTime instant = new DateTime(); long clockTolerance = accessor.getClockTolerance(); if (dtPlus == null) { vr = new ValidationResult(OasisNames.REQUESTER); log.debug("Validation FAILED - Issue Instant is missing"); } else { dtPlus = dtPlus.plus(clockTolerance); dtMinus = dtMinus.minus(clockTolerance); // dtPlus must be after now and dtMinus must be before now // in order to satisfy clock tolerance if (dtPlus.isBefore(instant) || dtMinus.isAfter(instant)) { vr = new ValidationResult(OasisNames.REQUESTER); log.debug("Validation FAILED - Issue Instant outside of clock tolerance"); log.debug("clockTolerance {}", clockTolerance); log.debug("now {}", instant); log.debug("dtPlus {}", dtPlus.toString()); log.debug("dtMinus {}", dtMinus.toString()); } } } // Destination URL skipped, this is already done by OpenSAML when parsing // validate scoping if presenet if (vr == null) { vr = validateScoping(t); } // signature must NOT be included if (vr == null) { if (request.getSignature() != null) { log.debug("Validation FAILED - Signature MUST NOT be present"); vr = new ValidationResult(OasisNames.REQUESTER, OasisNames.REQUEST_UNSUPPORTED); } } // ensure that we don't accept unsigned requests if configuration requires signing if (vr == null) { try { boolean mustBeSigned = accessor.getAuthnRequestsSignedForRelyingParty(request.getIssuer().getValue()); this.validateSigning(mustBeSigned, t); } catch (IllegalStateException e) { // set validation result to request denied log.error("Validation FAILED - unsigned request detected, signing required"); vr = new ValidationResult(OasisNames.RESPONDER, OasisNames.REQUEST_DENIED); } } // validate NameIDPolicy if present if (vr == null) { NameIDPolicy policy = request.getNameIDPolicy(); if (policy != null) { String format = policy.getFormat(); if (format != null && !format.equals(OasisNames.PERSISTENT) && !format.equals(OasisNames.EMAIL_ADDRESS) && !format.equals(SAMLNames.IDFORMAT_VAL_UPN.toString())) { log.error("Validation FAILED - unknown NameIDPolicy Format"); vr = new ValidationResult(OasisNames.REQUESTER, OasisNames.INVALID_NAMEID_POLICY); } } } // validate conditions if (vr == null) { Conditions conditions = request.getConditions(); if (conditions != null) { // notBefore processing DateTime notBefore = conditions.getNotBefore(); if (notBefore != null) { // no additional validation, we'll use whatever client wants t.setStartTime(notBefore.toDate()); } // delegable and renewable conditions for (Condition c : conditions.getConditions()) { if (c == null) { continue; } if (c instanceof RenewableType) { t.setRenewable(true); } if (c instanceof DelegableType) { t.setDelegable(true); } } } } if (vr == null) { computeSupportedAuthnTypes(t, request); } // validation done if (vr == null) { log.info("Authentication request validation succeeded"); vr = new ValidationResult(); // success // check if we need to convert a principal into emailAddress if (request.getNameIDPolicy() != null && request.getNameIDPolicy().getFormat() != null && request.getNameIDPolicy().getFormat().equals(OasisNames.EMAIL_ADDRESS)) { t.setIdentityFormat(OasisNames.IDENTITY_FORMAT_EMAIL_ADDRESS); } else { t.setIdentityFormat(OasisNames.IDENTITY_FORMAT_UPN); } } } catch (Exception e) { vr = new ValidationResult(HttpServletResponse.SC_BAD_REQUEST, "BadRequest", null); log.debug("Caught exception while Validating " + e.toString() + ", returning 400"); } return vr; }
/** * Returns AuthnRequest SAML message to be used to demand authentication from an IDP described * using idpEntityDescriptor, with an expected response to the assertionConsumer address. * * @param context message context * @param options preferences of message creation * @param assertionConsumer assertion consumer where the IDP should respond * @param bindingService service used to deliver the request * @return authnRequest ready to be sent to IDP * @throws SAMLException error creating the message * @throws MetadataProviderException error retreiving metadata */ protected AuthnRequest getAuthnRequest( SAMLMessageContext context, WebSSOProfileOptions options, AssertionConsumerService assertionConsumer, SingleSignOnService bindingService) throws SAMLException, MetadataProviderException { SAMLObjectBuilder<AuthnRequest> builder = (SAMLObjectBuilder<AuthnRequest>) builderFactory.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME); AuthnRequest request = builder.buildObject(); request.setIsPassive(options.getPassive()); request.setForceAuthn(options.getForceAuthN()); request.setProviderName(options.getProviderName()); request.setVersion(SAMLVersion.VERSION_20); if (options.getIncludeEidas()) { // ne sert à rien // request.setAssertionConsumerServiceURL(options.getIssuer()); // IssuerBuilder issuerBuilder = new IssuerBuilder(); // Issuer issuer = issuerBuilder.buildObject(); // issuer.setFormat(NAME_ISSUER_FORMAT_EIDAS); // log.debug("issuer="+options.getIssuer()); // issuer.setValue(options.getIssuer()); // request.setIssuer(issuer); NameIDPolicy nameIDPolicy = new NameIDPolicyBuilder().buildObject(); nameIDPolicy.setFormat(NAME_POLICY_FORMAT_EIDAS); nameIDPolicy.setAllowCreate(true); request.setNameIDPolicy(nameIDPolicy); QName eidas = new QName("xmlns:eidas", "http://eidas.europa.eu/saml-extensions"); request.getNamespaceManager().registerAttributeName(eidas); Extensions extEidas = new ExtensionsBuilder() .buildObject("urn:oasis:names:tc:SAML:2.0:protocol", "Extensions", "saml2p"); // Extensions extEidas = new EidasExtensions(); Collection<String> colAttr = options.getEidasAttributes(); // XSAnyBuilder raBuild = new XSAnyBuilder(); // <eidas:SPType>public</eidas:SPType> SPType pub = new SPTypeBuilder() .buildObject("http://eidas.europa.eu/saml-extensions", "SPType", "eidas"); // pub.setTextContent(EIDAS_PUBLIC); pub.setSPType(EIDAS_PUBLIC); // XSAny attrs = new XSAnyBuilder().buildObject("http://eidas.europa.eu/saml-extensions", // "RequestedAttributes", "eidas"); extEidas.getUnknownXMLObjects().add(pub); // XSAnyBuilder anyBuilder = (XSAnyBuilder) // Configuration.getBuilderFactory().getBuilder(XSAny.TYPE_NAME); String resAttrs = "<eidas:RequestedAttributes xmlns:eidas=\"http://eidas.europa.eu/saml-extensions\">"; for (String attr : colAttr) { resAttrs += oneAttribute(attr); } resAttrs += "</eidas:RequestedAttributes>"; log.debug("resAttrs=" + resAttrs); EidasExtensionConfiguration eidasExt = new EidasExtensionConfiguration(); eidasExt.configureExtension(); SAMLSchemaBuilder.addExtensionSchema("/schema/saml_eidas_extension.xsd"); BasicParserPool ppMgr = new BasicParserPool(); ppMgr.setNamespaceAware(true); try { ppMgr.setSchema(SAMLSchemaBuilder.getSAML11Schema()); } catch (SAXException ex) { log.error("Erreur schema=" + ex); return null; } InputStream is = new ByteArrayInputStream(resAttrs.getBytes()); Document domAttrsRaq = null; try { domAttrsRaq = ppMgr.parse(is); } catch (XMLParserException e) { log.error("Erreur dom=" + e); return null; } if (domAttrsRaq == null) { log.error("Erreur dom vide"); return null; } RequestedAttributesUnmarshaller unMars = new RequestedAttributesUnmarshaller(); XMLObject attrs = null; try { attrs = unMars.unmarshall(domAttrsRaq.getDocumentElement()); } catch (UnmarshallingException e) { System.err.println("Erreur unMarsh error=" + e); } extEidas.getUnknownXMLObjects().add(attrs); request.setExtensions(extEidas); } buildCommonAttributes(context.getLocalEntityId(), request, bindingService); buildScoping(request, bindingService, options); builNameIDPolicy(request, options); buildAuthnContext(request, options); buildReturnAddress(request, assertionConsumer); return request; }