protected void sendLogoutResponse(Status status, SAMLMessageContext context)
      throws MetadataProviderException, SAMLException, MessageEncodingException {

    SAMLObjectBuilder<LogoutResponse> responseBuilder =
        (SAMLObjectBuilder<LogoutResponse>)
            builderFactory.getBuilder(LogoutResponse.DEFAULT_ELEMENT_NAME);
    LogoutResponse logoutResponse = responseBuilder.buildObject();

    IDPSSODescriptor idpDescriptor = SAMLUtil.getIDPDescriptor(metadata, context.getPeerEntityId());
    SPSSODescriptor spDescriptor = (SPSSODescriptor) context.getLocalEntityRoleMetadata();
    String binding = SAMLUtil.getLogoutBinding(idpDescriptor, spDescriptor);
    SingleLogoutService logoutService = SAMLUtil.getLogoutServiceForBinding(idpDescriptor, binding);

    logoutResponse.setID(generateID());
    logoutResponse.setIssuer(getIssuer(context.getLocalEntityId()));
    logoutResponse.setVersion(SAMLVersion.VERSION_20);
    logoutResponse.setIssueInstant(new DateTime());
    logoutResponse.setInResponseTo(context.getInboundSAMLMessageId());
    logoutResponse.setDestination(logoutService.getLocation());
    logoutResponse.setStatus(status);

    context.setCommunicationProfileId(getProfileIdentifier());
    context.setOutboundMessage(logoutResponse);
    context.setOutboundSAMLMessage(logoutResponse);
    context.setPeerEntityEndpoint(logoutService);

    context.setPeerEntityId(idpDescriptor.getID());
    context.setPeerEntityRoleMetadata(idpDescriptor);

    boolean signMessage = context.getPeerExtendedMetadata().isRequireLogoutResponseSigned();
    sendMessage(context, signMessage);
  }
  public void processLogoutResponse(SAMLMessageContext context)
      throws SAMLException, org.opensaml.xml.security.SecurityException, ValidationException {

    SAMLObject message = context.getInboundSAMLMessage();

    // Verify type
    if (!(message instanceof LogoutResponse)) {
      log.debug("Received response is not of a Response object type");
      throw new SAMLException("Error validating SAML response");
    }
    LogoutResponse response = (LogoutResponse) message;

    // Make sure request was authenticated if required, authentication is done as part of the
    // binding processing
    if (!context.isInboundSAMLMessageAuthenticated()
        && context.getLocalExtendedMetadata().isRequireLogoutResponseSigned()) {
      log.debug(
          "Logout Response object is required to be signed by the entity policy: "
              + context.getInboundSAMLMessageId());
      throw new SAMLException("Logout Response object is required to be signed");
    }

    // Verify issue time
    DateTime time = response.getIssueInstant();
    if (!isDateTimeSkewValid(getResponseSkew(), time)) {
      log.debug("Response issue time is either too old or with date in the future");
      throw new SAMLException("Error validating SAML response");
    }

    // Verify response to field if present, set request if correct
    // The inResponseTo field is optional, SAML 2.0 Core, 1542
    SAMLMessageStorage messageStorage = context.getMessageStorage();
    if (messageStorage != null && response.getInResponseTo() != null) {
      XMLObject xmlObject = messageStorage.retrieveMessage(response.getInResponseTo());
      if (xmlObject == null) {
        log.debug(
            "InResponseToField doesn't correspond to sent message", response.getInResponseTo());
        throw new SAMLException("Error validating SAML response");
      } else if (xmlObject instanceof LogoutRequest) {
        // Expected
      } else {
        log.debug(
            "Sent request was of different type then received response",
            response.getInResponseTo());
        throw new SAMLException("Error validating SAML response");
      }
    }

    // Verify destination
    if (response.getDestination() != null) {
      SPSSODescriptor localDescriptor = (SPSSODescriptor) context.getLocalEntityRoleMetadata();

      // Check if destination is correct on this SP
      List<SingleLogoutService> services = localDescriptor.getSingleLogoutServices();
      boolean found = false;
      for (SingleLogoutService service : services) {
        if (response.getDestination().equals(service.getLocation())
            && context.getInboundSAMLBinding().equals(service.getBinding())) {
          found = true;
          break;
        }
      }
      if (!found) {
        log.debug(
            "Destination of the response was not the expected value", response.getDestination());
        throw new SAMLException("Error validating SAML response");
      }
    }

    // Verify issuer
    if (response.getIssuer() != null) {
      Issuer issuer = response.getIssuer();
      verifyIssuer(issuer, context);
    }

    // Verify status
    String statusCode = response.getStatus().getStatusCode().getValue();
    if (StatusCode.SUCCESS_URI.equals(statusCode)) {
      log.trace("Single Logout was successful");
    } else if (StatusCode.PARTIAL_LOGOUT_URI.equals(statusCode)) {
      log.trace("Single Logout was partially successful");
    } else {
      String[] logMessage = new String[2];
      logMessage[0] = response.getStatus().getStatusCode().getValue();
      StatusMessage message1 = response.getStatus().getStatusMessage();
      if (message1 != null) {
        logMessage[1] = message1.getMessage();
      }
      log.warn("Received LogoutResponse has invalid status code", logMessage);
    }
  }