Back to index

nordugrid-arc-nox  1.1.0~rc6
Public Member Functions | Static Public Member Functions | Static Protected Attributes | Private Types | Private Attributes
ArcSec::SAMLTokenSH Class Reference

Adds WS-Security SAML Token into SOAP Header. More...

#include <SAMLTokenSH.h>

Inheritance diagram for ArcSec::SAMLTokenSH:
Inheritance graph
Collaboration diagram for ArcSec::SAMLTokenSH:
Collaboration graph

List of all members.

Public Member Functions

 SAMLTokenSH (Arc::Config *cfg, Arc::ChainContext *ctx)
virtual ~SAMLTokenSH (void)
virtual bool Handle (Arc::Message *msg) const

Static Public Member Functions

static Arc::Pluginget_sechandler (Arc::PluginArgument *arg)

Static Protected Attributes

static Arc::Logger logger

Private Types

enum  { process_none, process_extract, process_generate }
enum  { signature, encryption }

Private Attributes

enum ArcSec::SAMLTokenSH:: { ... }  process_type_
enum ArcSec::SAMLTokenSH:: { ... }  usage_type_
std::string cert_file_
std::string key_file_
std::string ca_file_
std::string ca_dir_
std::string local_dn_
std::string aa_service_
Arc::XMLNode saml_assertion_

Detailed Description

Adds WS-Security SAML Token into SOAP Header.

Definition at line 14 of file SAMLTokenSH.h.

Member Enumeration Documentation

anonymous enum [private]

Definition at line 16 of file SAMLTokenSH.h.

anonymous enum [private]

Definition at line 21 of file SAMLTokenSH.h.

Constructor & Destructor Documentation

Definition at line 136 of file SAMLTokenSH.cpp.

  if(!init_xmlsec()) return;
  std::string process_type = (std::string)((*cfg)["Process"]);
  if(process_type == "generate") { 
    if(cert_file_.empty()) {
      logger.msg(ERROR,"Missing or empty CertificatePath element");
    if(key_file_.empty()) {
      logger.msg(ERROR,"Missing or empty KeyPath element");
    if(ca_file_.empty() && ca_dir_.empty()) {
      logger.msg(WARNING,"Both of CACertificatePath and CACertificatesDir elements missing or empty");
    aa_service_ = (std::string)((*cfg)["AAService"]);
  } else if(process_type == "extract") {
    //If ca file does not exist, we can only verify the signature by
    //using the certificate in the incoming wssecurity; we can not authenticate
    //the the message because we can not check the certificate chain without 
    //trusted ca.
    if(ca_file_.empty() && ca_dir_.empty()) {
      logger.msg(INFO,"Missing or empty CertificatePath or CACertificatesDir element; will only check the signature, will not do message authentication");
  } else {
    logger.msg(ERROR,"Processing type not supported: %s",process_type);
  if(!cert_file_.empty()) {
    Arc::Credential cred(cert_file_, key_file_, ca_dir_, ca_file_);
    local_dn_ = convert_to_rdn(cred.GetDN());

Here is the call graph for this function:

Here is the caller graph for this function:

ArcSec::SAMLTokenSH::~SAMLTokenSH ( void  ) [virtual]

Definition at line 179 of file SAMLTokenSH.cpp.


Here is the call graph for this function:

Member Function Documentation

Definition at line 24 of file SAMLTokenSH.cpp.

    ArcSec::SecHandlerPluginArgument* shcarg =
    if(!shcarg) return NULL;
    return new ArcSec::SAMLTokenSH((Arc::Config*)(*shcarg),(Arc::ChainContext*)(*shcarg));

Here is the call graph for this function:

bool ArcSec::SAMLTokenSH::Handle ( Arc::Message msg) const [virtual]

Implements ArcSec::SecHandler.

Definition at line 183 of file SAMLTokenSH.cpp.

  if(process_type_ == process_extract) {
    try {
      PayloadSOAP* soap = dynamic_cast<PayloadSOAP*>(msg->Payload());
      SAMLToken st(*soap);
      if(!st) {
        logger.msg(ERROR,"Failed to parse SAML Token from incoming SOAP");
        return false;
      if(!st.Authenticate()) {
        logger.msg(ERROR, "Failed to verify SAML Token inside the incoming SOAP");
        return false;
      if((!ca_file_.empty() || !ca_dir_.empty()) && !st.Authenticate(ca_file_, ca_dir_)) {
        logger.msg(ERROR, "Failed to authenticate SAML Token inside the incoming SOAP");
        return false;
      logger.msg(INFO, "Succeeded to authenticate SAMLToken");

      //Store the saml assertion into message context
      Arc::XMLNode assertion_nd = st["Assertion"];
      SAMLAssertionSecAttr* sattr = new SAMLAssertionSecAttr(assertion_nd);
      msg->Auth()->set("SAMLAssertion", sattr);

    } catch(std::exception) {
      logger.msg(ERROR,"Incoming Message is not SOAP");
      return false;
  } else if(process_type_ == process_generate) {
    try {
      if(!saml_assertion_) {
        //Contact the AA service to get the saml assertion

        //Compose <samlp:AttributeQuery/>
        Arc::NS ns;
        ns["saml"] = "urn:oasis:names:tc:SAML:2.0:assertion";
        ns["samlp"] = "urn:oasis:names:tc:SAML:2.0:protocol";
        Arc::XMLNode attr_query(ns, "samlp:AttributeQuery");
        std::string query_id = Arc::UUID();
        attr_query.NewAttribute("ID") = query_id;
        Arc::Time t;
        std::string current_time = t.str(Arc::UTCTime);
        attr_query.NewAttribute("IssueInstant") = current_time;
        attr_query.NewAttribute("Version") = std::string("2.0");
        attr_query.NewChild("saml:Issuer") = local_dn_;

        Arc::XMLNode subject = attr_query.NewChild("saml:Subject");
        Arc::XMLNode name_id = subject.NewChild("saml:NameID");
        name_id = local_dn_;

        Arc::XMLNode attribute = attr_query.NewChild("saml:Attribute");

        Arc::XMLSecNode attr_query_secnd(attr_query);
        std::string attr_query_idname("ID");
        attr_query_secnd.AddSignatureTemplate(attr_query_idname, Arc::XMLSecNode::RSA_SHA1);
        if(attr_query_secnd.SignNode(key_file_, cert_file_)) {
          std::cout<<"Succeeded to sign the signature under <samlp:AttributeQuery/>"<<std::endl;

        Arc::NS soap_ns;
        Arc::SOAPEnvelope envelope(soap_ns);
        Arc::PayloadSOAP request(envelope);

        // Send request
        Arc::URL aa_service_url(aa_service_);
        Arc::MCCConfig cfg;
        if (!cert_file_.empty()) cfg.AddCertificate(cert_file_);
        if (!key_file_.empty()) cfg.AddPrivateKey(key_file_);
        if (!ca_file_.empty()) cfg.AddCAFile(ca_file_);
        if (!ca_dir_.empty()) cfg.AddCADir(ca_dir_);

        Arc::ClientSOAP client(cfg, aa_service_url);
        Arc::PayloadSOAP *response = NULL;
        Arc::MCC_Status status = client.process(&request,&response);
        if (!response) {
          logger.msg(Arc::ERROR, "No response from AA service %s failed", aa_service_.c_str());
          return false;
        if (!status) {
          logger.msg(Arc::ERROR, "SOAP Request to AA service %s failed", aa_service_.c_str());
          delete response; return false;

        //Consume the response from AA
        Arc::XMLNode attr_resp;
        attr_resp = (*response).Body().Child(0);
        if(!attr_resp) {
          logger.msg(Arc::ERROR, "Cannot find content under response soap message");
          return false;
        if((attr_resp.Name() != "Response") || (attr_resp.Prefix() != "samlp")) {
          logger.msg(Arc::ERROR, "Cannot find <samlp:Response/> under response soap message:");
          std::string tmp; attr_resp.GetXML(tmp);
          logger.msg(Arc::ERROR, "%s", tmp.c_str());
          return false;

        std::string resp_idname = "ID";
        Arc::XMLSecNode attr_resp_secnode(attr_resp);
        if(attr_resp_secnode.VerifyNode(resp_idname, ca_file_, ca_dir_)) {
          logger.msg(Arc::INFO, "Succeeded to verify the signature under <samlp:Response/>");
        else {
          logger.msg(Arc::ERROR, "Failed to verify the signature under <samlp:Response/>");
          delete response; return false;
        std::string responseto_id = (std::string)(attr_resp.Attribute("InResponseTo"));
        if(query_id != responseto_id) {
          logger.msg(Arc::INFO, "The Response is not going to this end");
          delete response; return false;

        std::string resp_time = attr_resp.Attribute("IssueInstant");
        std::string statuscode_value = attr_resp["samlp:Status"]["samlp:StatusCode"];
        if(statuscode_value == "urn:oasis:names:tc:SAML:2.0:status:Success")
          logger.msg(Arc::INFO, "The StatusCode is Success");

        Arc::XMLNode assertion = attr_resp["saml:Assertion"];
        std::string assertion_idname = "ID";
        Arc::XMLSecNode assertion_secnode(assertion);
        if(assertion_secnode.VerifyNode(assertion_idname, ca_file_, ca_dir_)) {
          logger.msg(Arc::INFO, "Succeeded to verify the signature under <saml:Assertion/>");
        else {
          logger.msg(Arc::ERROR, "Failed to verify the signature under <saml:Assertion/>");
          delete response;  return false;
        delete response;

      //Protect the SOAP message with SAML assertion
      PayloadSOAP* soap = dynamic_cast<PayloadSOAP*>(msg->Payload());
      SAMLToken st(*soap, cert_file_, key_file_, SAMLToken::SAML2, saml_assertion_);
      if(!st) {
        logger.msg(ERROR,"Failed to generate SAML Token for outgoing SOAP");
        return false;
      //Reset the soap message
      (*soap) = st;
    } catch(std::exception) {
      logger.msg(ERROR,"Outgoing Message is not SOAP");
      return false;
  } else {
    logger.msg(ERROR,"SAML Token handler is not configured");
    return false;
  return true;

Here is the call graph for this function:

Member Data Documentation

std::string ArcSec::SAMLTokenSH::aa_service_ [private]

Definition at line 30 of file SAMLTokenSH.h.

std::string ArcSec::SAMLTokenSH::ca_dir_ [private]

Definition at line 28 of file SAMLTokenSH.h.

std::string ArcSec::SAMLTokenSH::ca_file_ [private]

Definition at line 27 of file SAMLTokenSH.h.

std::string ArcSec::SAMLTokenSH::cert_file_ [private]

Definition at line 25 of file SAMLTokenSH.h.

std::string ArcSec::SAMLTokenSH::key_file_ [private]

Definition at line 26 of file SAMLTokenSH.h.

std::string ArcSec::SAMLTokenSH::local_dn_ [private]

Definition at line 29 of file SAMLTokenSH.h.

Arc::Logger ArcSec::SecHandler::logger [static, protected, inherited]

Reimplemented in ArcSec::DelegationSH.

Definition at line 31 of file SecHandler.h.

enum { ... } ArcSec::SAMLTokenSH::process_type_ [private]

Definition at line 31 of file SAMLTokenSH.h.

enum { ... } ArcSec::SAMLTokenSH::usage_type_ [private]

The documentation for this class was generated from the following files: