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;
  }