class Ciam::Saml::Response

Constants

ASSERTION
DSIG
PROTOCOL

Attributes

attr_name_format[RW]
decrypted_document[R]
document[RW]
options[RW]
response[RW]
settings[RW]

Public Class Methods

new(response, options = {}) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 22
def initialize(response, options = {})
  raise ArgumentError.new("Response cannot be nil") if response.nil?
  self.options  = options
  self.response = response
  if assertion_encrypted?
    @decrypted_document = generate_decrypted_document
  end
  begin
    self.document = Ciam::XMLSecurityNew::SignedDocument.new(Base64.decode64(response))
  rescue REXML::ParseException => e
    if response =~ /</
      self.document = Ciam::XMLSecurityNew::SignedDocument.new(response)
    else
      raise e
    end
  end
  
end

Public Instance Methods

assertion_conditions_not_before() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 227
def assertion_conditions_not_before
  node_cond_not_before = xpath_first_from_signed_assertion('/a:Conditions')
  return  node_cond_not_before.attributes["NotBefore"] unless node_cond_not_before.blank?
end
assertion_conditions_not_on_or_after() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 232
def assertion_conditions_not_on_or_after
  node_cond_not_on_or_after = xpath_first_from_signed_assertion('/a:Conditions')
  return  node_cond_not_on_or_after.attributes["NotOnOrAfter"] unless node_cond_not_on_or_after.blank?
end
assertion_encrypted?() click to toggle source

Checks if the SAML Response contains or not an EncryptedAssertion element @return [Boolean] True if the SAML Response contains an EncryptedAssertion element

# File lib/ciam/ruby-saml/response.rb, line 44
def assertion_encrypted?
  false
  #!REXML::XPath.first(self.document, "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)", { "p" => PROTOCOL, "a" => ASSERTION }).nil?
end
assertion_id() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 207
def assertion_id
  node = REXML::XPath.first(document, "/p:Response/a:Assertion/", { "p" => PROTOCOL, "a" => ASSERTION  })
  return  node.attributes["ID"] unless node.blank?
end
assertion_issue_instant() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 202
def assertion_issue_instant
  node = REXML::XPath.first(document, "/p:Response/a:Assertion/", { "p" => PROTOCOL, "a" => ASSERTION  })
  return  node.attributes["IssueInstant"] unless node.blank?
end
assertion_present?() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 197
def assertion_present?
  node = REXML::XPath.first(document, "/p:Response/a:Assertion/", { "p" => PROTOCOL, "a" => ASSERTION  })
  return  !node.blank?
end
assertion_subject() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 212
def assertion_subject
  node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION  })
  return  node.text
end
assertion_subject_confirmation_data_not_on_or_after() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 222
def assertion_subject_confirmation_data_not_on_or_after
  node_subj_conf_data = xpath_first_from_signed_assertion('/a:Subject/a:SubjectConfirmation/a:SubjectConfirmationData')
  return  node_subj_conf_data.attributes["NotOnOrAfter"] unless node_subj_conf_data.blank?
end
assertion_subject_name_qualifier() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 217
def assertion_subject_name_qualifier
  node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION  })
  return  node.attributes["NameQualifier"] unless node.blank?
end
attributes() click to toggle source

A hash of alle the attributes with the response. Assuming there is only one value for each key

# File lib/ciam/ruby-saml/response.rb, line 70
def attributes
  @attr_statements ||= begin
    result = {}
    stmt_element = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AttributeStatement", { "p" => PROTOCOL, "a" => ASSERTION })
    return {} if stmt_element.nil?
    
    @attr_name_format = []
    stmt_element.elements.each do |attr_element|
      name  = attr_element.attributes["Name"]
      #salvo i vari format per controllare poi che non ce ne siano di null
      @attr_name_format << attr_element.attributes["NameFormat"].blank? ? nil : attr_element.attributes["NameFormat"].text
      value = (attr_element.elements.blank? ? nil : attr_element.elements.first.text)

      result[name] = value
    end
    #mette il symbol
    result.keys.each do |key|
      result[key.intern] = result[key]
    end

    result
  end
end
conditions() click to toggle source

Conditions (if any) for the assertion to run

# File lib/ciam/ruby-saml/response.rb, line 124
def conditions
  @conditions ||= begin
    REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id}']/a:Conditions", { "p" => PROTOCOL, "a" => ASSERTION })
  end
end
get_status_message() click to toggle source

Ritorno il valore dello StatusMessage

# File lib/ciam/ruby-saml/response.rb, line 118
def get_status_message
    node = REXML::XPath.first(document, "/p:Response/p:Status/p:StatusMessage", { "p" => PROTOCOL, "a" => ASSERTION })
    node.text unless node.blank?
end
id() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 187
def id
  node = REXML::XPath.first(document, "/p:Response", { "p" => PROTOCOL })
  return  node.attributes["ID"] unless node.blank?
end
is_valid?() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 49
def is_valid?
  validate
end
issue_instant() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 192
def issue_instant
  node = REXML::XPath.first(document, "/p:Response", { "p" => PROTOCOL })
  return  node.attributes["IssueInstant"] unless node.blank?
end
issuer() click to toggle source

metodi per ricavare info per tracciatura agid

# File lib/ciam/ruby-saml/response.rb, line 135
def issuer
  @issuer ||= begin
    node = REXML::XPath.first(document, "/p:Response/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
    node ||= REXML::XPath.first(document, "/p:Response/a:Assertion/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
    node.nil? ? nil : node.text
  end
end
issuers(soft=true) click to toggle source

Gets the Issuers (from Response and Assertion). (returns the first node that matches the supplied xpath from the Response and from the Assertion) @return [Array] Array with the Issuers (REXML::Element)

# File lib/ciam/ruby-saml/response.rb, line 147
def issuers(soft=true)
  @issuers ||= begin
    issuer_response_nodes = REXML::XPath.match(
      document,
      "/p:Response/a:Issuer",
      { "p" => PROTOCOL, "a" => ASSERTION }
    )

    unless issuer_response_nodes.size == 1
      # error_msg = "Issuer of the Response not found or multiple."
      # raise ValidationError.new(error_msg)
      return (soft ? false : validation_error("Issuer of the Response not found or multiple."))
    end

    issuer_assertion_nodes = xpath_from_signed_assertion("/a:Issuer")
    unless issuer_assertion_nodes.size == 1
      # error_msg = "Issuer of the Assertion not found or multiple."
      # raise ValidationError.new(error_msg)
      return (soft ? false : validation_error("Issuer of the Assertion not found or multiple."))
    end

    issuer_response_nodes.each{ |iss|
      #controllo: L'attributo Format di Issuer deve essere presente con il valore urn:oasis:names:tc:SAML:2.0:nameid-format:entity
      return (soft ? false : validation_error("Elemento Issuer non ha formato corretto ")) if !iss.attributes['Format'].nil? && iss.attributes['Format'] != 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'

    }

    nodes = issuer_response_nodes + issuer_assertion_nodes

    nodes.map { |node| Utils.element_text(node) }.compact.uniq
  end
end
name_id() click to toggle source

The value of the user identifier as designated by the initialization request response

# File lib/ciam/ruby-saml/response.rb, line 58
def name_id
  @name_id ||= begin
    node = REXML::XPath.first(document, "/saml2p:Response/saml2:Assertion[@ID='#{document.signed_element_id}']/saml2:Subject/saml2:NameID")
    node ||=  REXML::XPath.first(document, "/saml2p:Response[@ID='#{document.signed_element_id}']/saml2:Assertion/saml2:Subject/saml2:NameID")
    node.nil? ? nil : node.text
  end
end
response_to_id() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 182
def response_to_id
  node = REXML::XPath.first(document, "/p:Response", { "p" => PROTOCOL })
  return  node.attributes["InResponseTo"] unless node.blank?
end
session_expires_at() click to toggle source

When this user session should expire at latest

# File lib/ciam/ruby-saml/response.rb, line 95
def session_expires_at
  @expires_at ||= begin
    node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AuthnStatement", { "p" => PROTOCOL, "a" => ASSERTION })
    parse_time(node, "SessionNotOnOrAfter")
  end
end
session_index() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 102
def session_index
  @session_index ||= begin
    node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AuthnStatement", { "p" => PROTOCOL, "a" => ASSERTION })
    node.attributes["SessionIndex"] unless node.blank?
  end
end
success?() click to toggle source

Checks the status of the response for a “Success” code

# File lib/ciam/ruby-saml/response.rb, line 110
def success?
  @status_code ||= begin
    node = REXML::XPath.first(document, "/p:Response/p:Status/p:StatusCode", { "p" => PROTOCOL, "a" => ASSERTION })
    node.attributes["Value"] == "urn:oasis:names:tc:SAML:2.0:status:Success" unless node.blank?
  end
end
validate!() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 53
def validate!
  validate(false)
end

Private Instance Methods

destination() click to toggle source

@return [String|nil] Destination attribute from the SAML Response.

# File lib/ciam/ruby-saml/response.rb, line 477
def destination
    @destination ||= begin
      node = REXML::XPath.first(
        document,
        "/p:Response",
        { "p" => PROTOCOL }
      )
      node.nil? ? nil : node.attributes['Destination']
    end
end
get_fingerprint() click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 597
def get_fingerprint
    idp_metadata = Ciam::Saml::Metadata.new(settings).get_idp_metadata
    
    if settings.idp_cert
      cert_text = Base64.decode64(settings.idp_cert)
      cert = OpenSSL::X509::Certificate.new(cert_text)
      Digest::SHA2.hexdigest(cert.to_der).upcase.scan(/../).join(":")
    else
      settings.idp_cert_fingerprint
    end
    
end
parse_time(node, attribute) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 629
def parse_time(node, attribute)
    if node && node.attributes[attribute]
      Time.parse(node.attributes[attribute])
    end
end
validate(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 243
def validate(soft = true)
    # prime the IdP metadata before the document validation.
    # The idp_cert needs to be populated before the validate_response_state method
    
    if settings
      idp_metadata = Ciam::Saml::Metadata.new(settings).get_idp_metadata
    end
    
    #carico nei setting l'idp_entity_id
    entity_descriptor_element = REXML::XPath.first(idp_metadata,"/EntityDescriptor")
    if !entity_descriptor_element.nil? 
      settings.idp_entity_id = entity_descriptor_element.attributes["entityID"]
    end

    return false if validate_structure(soft) == false
    return false if validate_response_state(soft) == false
    return false if validate_conditions(soft) == false
    #validazione assertion firmata
    return false if validate_signed_elements(soft) == false
    #validazione version che sia 2.0
    return false if validate_version(soft) == false
    #validazione version delle asserzioni che sia 2.0
    return false if validate_version_assertion(soft) == false
    #validazione destination
    return false if validate_destination(soft) == false
    #validazione status
    return false if validate_status(soft) == false
    #validazione inresponseto
    return false if validate_presence_inresponseto(soft) == false
    #validazione issuer
    return false if validate_issuer(soft) == false
    #validazioni varie su asserzioni
    return false if validate_assertion(soft) == false
    #validazione presenza format su attributes
    return false if validate_name_format_attributes(soft) == false


    # Just in case a user needs to toss out the signature validation,
    # I'm adding in an option for it.  (Sometimes canonicalization is a bitch!)
    return true if settings.skip_validation == true
    
    # document.validte populates the idp_cert
    return false if document.validate_document(get_fingerprint, soft) == false
    
    # validate response code
    return false if success? == false  

    return true
end
validate_assertion(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 509
def validate_assertion(soft = true)
    #posso avere n nodi asserzione..forse
    nodes_assertion = xpath_from_signed_assertion
    unless nodes_assertion.blank?
      #Elemento NameID non specificato
      node_name_id = xpath_first_from_signed_assertion('/a:Subject/a:NameID')
      unless node_name_id.blank?
        return soft ? false : validation_error("Errore su Asserzione: NameID vuoto") if node_name_id.text.blank?
        #controlli su attributo format
        attr_format = node_name_id.attribute("Format")
        return soft ? false : validation_error("Errore su Asserzione: Format su NameID vuoto") if attr_format.blank? || attr_format.to_s != "urn:oasis:names:tc:SAML:2.0:nameid-format:transient" #45
        #controlli su attributo NameQualifier
        attr_name_qual = node_name_id.attribute("NameQualifier")
        return soft ? false : validation_error("Errore su Asserzione: NameQualifier su NameID vuoto") if attr_name_qual.blank? || ( !attr_name_qual.blank? && attr_name_qual.value.blank?)#48 e 49
      else
        return soft ? false : validation_error("Errore su Asserzione: NameID non presente")
          
      end
      #Controlli su SubjectConfirmation
      node_subj_conf = xpath_first_from_signed_assertion('/a:Subject/a:SubjectConfirmation')
      unless node_subj_conf.blank?
        #controlli su attributo Method
        attr_method = node_subj_conf.attribute("Method")
        return soft ? false : validation_error("Errore su Asserzione: Method su SubjectConfirmation vuoto") if attr_method.blank? || attr_method.to_s != "urn:oasis:names:tc:SAML:2.0:cm:bearer" #53 54 e 55
        #Controlli su SubjectConfirmationData
        node_subj_conf_data = xpath_first_from_signed_assertion('/a:Subject/a:SubjectConfirmation/a:SubjectConfirmationData')
        unless node_subj_conf_data.blank?
          #controllo attr Recipient, vuoto o diverso da AssertionConsumerServiceURL
          attr_recipient = node_subj_conf_data.attribute("Recipient")
          return soft ? false : validation_error("Errore su Asserzione: Recipient su SubjectConfirmationData vuoto o diverso da AssertionConsumerServiceURL") if attr_recipient.blank? || attr_recipient.to_s != settings.assertion_consumer_service_url #57 58 e 59
          #controllo attr InResponseTo, vuoto o diverso da ID request
          node_response = REXML::XPath.first(document, "/p:Response", { "p" => PROTOCOL})
          id_request = node_response.attribute("InResponseTo")
          attr_in_resp_to = node_subj_conf_data.attribute("InResponseTo")
          return soft ? false : validation_error("Errore su Asserzione: InResponseTo su SubjectConfirmationData vuoto o diverso da ID request") if attr_in_resp_to.blank? || attr_in_resp_to.to_s != id_request.to_s #57 58 e 59
        
          #controllo attr NotOnOrAfter se vuoto o non presente  #63 64
          attr_not_on_or_after = node_subj_conf_data.attribute("NotOnOrAfter")
          return soft ? false : validation_error("Errore su Asserzione: NotOnOrAfter su SubjectConfirmationData mancante") if attr_not_on_or_after.blank?


        else
          return soft ? false : validation_error("Errore su Asserzione: SubjectConfirmationData non presente")
        end

      else
          return soft ? false : validation_error("Errore su Asserzione: SubjectConfirmation non presente")
      end

      #Controlli su Conditions
      node_conditions = xpath_first_from_signed_assertion('/a:Conditions')
      unless node_conditions.blank?
          attr_not_before = node_conditions.attribute("NotBefore")
          return soft ? false : validation_error("Errore su Asserzione: Recipient su SubjectConfirmationData vuoto") if attr_not_before.blank? #75 76
          #83 84. Assertion - Elemento AudienceRestriction di Condition mancante
          node_conditions_audience_restrictions = xpath_first_from_signed_assertion('/a:Conditions/a:AudienceRestriction')
          return soft ? false : validation_error("Errore su Asserzione: AudienceRestriction su Conditions vuoto") if node_conditions_audience_restrictions.blank? #83 84
          #85 86 87. Assertion - Elemento Audience di AudienceRestriction mancante
          node_conditions_audience_restrictions_audience = xpath_first_from_signed_assertion('/a:Conditions/a:AudienceRestriction/a:Audience')
          #Ciamer.logger.error "\n\n node_conditions_audience_restrictions_audience #{node_conditions_audience_restrictions_audience}"
          #Ciamer.logger.error "\n\n settings.issuer #{settings.issuer}"
          return soft ? false : validation_error("Errore su Asserzione: Audience su AudienceRestriction  vuoto") if node_conditions_audience_restrictions_audience.blank? || node_conditions_audience_restrictions_audience.text != settings.issuer  #83 84
      else
          return soft ? false : validation_error("Errore su Asserzione: Conditions non presente")
      end

      
      node_auth_stat_context_class_ref = xpath_first_from_signed_assertion('/a:AuthnStatement/a:AuthnContext/a:AuthnContextClassRef')
      
      node_attr_stmt_attribute_value = xpath_first_from_signed_assertion("/a:AttributeStatement/a:Attribute/a:AttributeValue")
      #Elemento AttributeStatement presente, ma sottoelemento Attribute non specificato, caso 99
      return soft ? false : validation_error("Errore su Asserzione: AttributeValue di Attribute su AttributeStatement vuoto") if node_attr_stmt_attribute_value.blank?
      

      else
        return soft ? false : validation_error("Errore su Asserzione: non presente")
    end
    true
end
validate_conditions(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 610
def validate_conditions(soft = true)
    return true if conditions.nil?
    return true if options[:skip_conditions]

    if not_before = parse_time(conditions, "NotBefore")
      if Time.now.utc < not_before
        return soft ? false : validation_error("Current time is earlier than NotBefore condition")
      end
    end

    if not_on_or_after = parse_time(conditions, "NotOnOrAfter")
      if Time.now.utc >= not_on_or_after
        return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
      end
    end

    true
end
validate_destination(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 488
def validate_destination(soft = true)
    return (soft ? false : validation_error("La response non ha destination")) if destination.nil?
    #return true if options[:skip_destination]

    if destination.empty?
      # error_msg = "The response has an empty Destination value"
      # return append_error(error_msg)
      return soft ? false : validation_error("The response has an empty Destination value")
    end

    return true if settings.assertion_consumer_service_url.nil? || settings.assertion_consumer_service_url.empty?

    unless Ciam::Saml::Utils.uri_match?(destination, settings.assertion_consumer_service_url)
      # error_msg = "The response was received at #{destination} instead of #{settings.assertion_consumer_service_url}"
      # return append_error(error_msg)
      return soft ? false : validation_error("The response was received at #{destination} instead of #{settings.assertion_consumer_service_url}")
    end

    true
end
validate_issuer(soft=true) click to toggle source

Validates the Issuer (Of the SAML Response and the SAML Assertion) @param soft [Boolean] soft Enable or Disable the soft mode (In order to raise exceptions when the response is invalid or not) @return [Boolean] True if the Issuer matchs the IdP entityId, otherwise False if soft=True @raise [ValidationError] if soft == false and validation fails

# File lib/ciam/ruby-saml/response.rb, line 298
def validate_issuer(soft=true)
  obtained_issuers = issuers(soft)
  if obtained_issuers == false
    return false #errori all'interno del metodo issuers
  else
    obtained_issuers.each do |iss|

      unless Ciam::Saml::Utils.uri_match?(iss, settings.idp_entity_id)
        # error_msg = "Doesn't match the issuer, expected: <#{settings.idp_entity_id}>, but was: <#{issuer}>"
        # return append_error(error_msg)
        return (soft ? false : validation_error("Elemento Issuer diverso da EntityID IdP, expected: <#{settings.idp_entity_id}>, but was: <#{iss}>"))
      end
    end

    true
  end
end
validate_name_format_attributes(soft=true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 590
def validate_name_format_attributes(soft=true)
    unless attributes.blank?
        return false if @attr_name_format.blank? || (@attr_name_format.length != (attributes.length / 2))
    end 
    true
end
validate_presence_inresponseto(soft=true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 316
def validate_presence_inresponseto(soft=true)
  response_to_id_value = response_to_id
  return (soft ? false : validation_error("InResponseTo non specificato o mancante")) if response_to_id_value.blank?
end
validate_response_state(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 454
def validate_response_state(soft = true)
    if response.empty?
      return soft ? false : validation_error("Blank response")
    end

    if settings.nil?
      return soft ? false : validation_error("No settings on response")
    end

    if settings.idp_cert_fingerprint.nil? && settings.idp_cert.nil?
      return soft ? false : validation_error("No fingerprint or certificate on settings")
    end

    true
end
validate_signed_elements(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 380
def validate_signed_elements(soft = true)
    signature_nodes = REXML::XPath.match(decrypted_document.nil? ? document : decrypted_document,"//ds:Signature",{"ds"=>DSIG})
    signed_elements = []
    verified_seis = []
    verified_ids = []
    signature_nodes.each do |signature_node|
      signed_element = signature_node.parent.name
      if signed_element != 'Response' && signed_element != 'Assertion'
        return soft ? false : validation_error("Invalid Signature Element '#{signed_element}'. SAML Response rejected")
        #return append_error("Invalid Signature Element '#{signed_element}'. SAML Response rejected")
      end

      if signature_node.parent.attributes['ID'].nil?
        return soft ? false : validation_error("Signed Element must contain an ID. SAML Response rejected")
        #return append_error("Signed Element must contain an ID. SAML Response rejected")
      end

      id = signature_node.parent.attributes.get_attribute("ID").value
      if verified_ids.include?(id)
        return soft ? false : validation_error("Duplicated ID. SAML Response rejected")
        #return append_error("Duplicated ID. SAML Response rejected")
      end
      verified_ids.push(id)

      # Check that reference URI matches the parent ID and no duplicate References or IDs
      ref = REXML::XPath.first(signature_node, ".//ds:Reference", {"ds"=>DSIG})
      if ref
        uri = ref.attributes.get_attribute("URI")
        if uri && !uri.value.empty?
          sei = uri.value[1..-1]

          unless sei == id
            #return append_error("Found an invalid Signed Element. SAML Response rejected")
            return soft ? false : validation_error("Found an invalid Signed Element. SAML Response rejected")
          end

          if verified_seis.include?(sei)
            #return append_error("Duplicated Reference URI. SAML Response rejected")
            return soft ? false : validation_error("Duplicated Reference URI. SAML Response rejected")
          end

          verified_seis.push(sei)
        end
      end

      signed_elements << signed_element
    end

    unless signature_nodes.length < 3 && !signed_elements.empty?
      #return append_error("Found an unexpected number of Signature Element. SAML Response rejected")
      return soft ? false : validation_error("Found an unexpected number of Signature Element. SAML Response rejected")
    end

    #if settings.security[:want_assertions_signed] && !(signed_elements.include? "Assertion")
    if !(signed_elements.include? "Assertion")
    #return append_error("The Assertion of the Response is not signed and the SP requires it")
      return soft ? false : validation_error("L'asserzione non è firmata.")
    end

    true
end
validate_status(soft=true) click to toggle source

validate status e status code

# File lib/ciam/ruby-saml/response.rb, line 324
def validate_status(soft=true)
  #controlli su status
  node_status = REXML::XPath.first(document, "/p:Response/p:Status", { "p" => PROTOCOL, "a" => ASSERTION })
  return (soft ? false : validation_error("Status non presente")) if node_status.blank?
  #controlli su status code
  node_status_code = REXML::XPath.first(document, "/p:Response/p:Status/p:StatusCode", { "p" => PROTOCOL, "a" => ASSERTION })
  return (soft ? false : validation_error("Status code non presente")) if node_status_code.blank?
  return (soft ? false : validation_error("Status non presente")) unless node_status_code.attributes["Value"] == "urn:oasis:names:tc:SAML:2.0:status:Success"
  true
end
validate_structure(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 442
def validate_structure(soft = true)
    Dir.chdir(File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'schemas'))) do
      @schema = Nokogiri::XML::Schema(IO.read('saml20protocol_schema.xsd'))
      @xml = Nokogiri::XML(self.document.to_s)
    end
    if soft
      @schema.validate(@xml).map{ return false }
    else
      @schema.validate(@xml).map{ |error| raise(Exception.new("#{error.message}\n\n#{@xml.to_s}")) }
    end
end
validate_version(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 364
def validate_version(soft = true)
    unless version(self.document) == "2.0"
      #return append_error("Unsupported SAML version")
      return soft ? false : validation_error("Unsupported SAML version")
    end
    true
end
validate_version_assertion(soft = true) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 372
def validate_version_assertion(soft = true)
    unless version_assertion(self.document) == "2.0"
      #return append_error("Unsupported SAML version")
      return soft ? false : validation_error("Unsupported SAML Assertion version")
    end
    true
end
validation_error(message) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 239
def validation_error(message)
  raise ValidationError.new(message)
end
version(document) click to toggle source

Validates the SAML version (2.0) If fails, the error is added to the errors array. @return [Boolean] True if the SAML Response is 2.0, otherwise returns False

# File lib/ciam/ruby-saml/response.rb, line 341
def version(document)
    @version ||= begin
      node = REXML::XPath.first(
        document,
        "/p:AuthnRequest | /p:Response | /p:LogoutResponse | /p:LogoutRequest",
        { "p" => PROTOCOL }
      )
      node.nil? ? nil : node.attributes['Version']
    end
end
version_assertion(document) click to toggle source
# File lib/ciam/ruby-saml/response.rb, line 352
def version_assertion(document)
    assertion_nodes = xpath_from_signed_assertion()
    @version_assertion = "2.0"
    #ciclo sui nodi delle asserzioni, se uno ha una versione diversa da 2.0 ritorno nil
    unless assertion_nodes.blank?
      assertion_nodes.each{ |ass_node|
        return nil if ass_node.attributes['Version'] != "2.0"
      }
    end
    @version_assertion 
end
xpath_first_from_signed_assertion(subelt=nil) click to toggle source

Extracts the first appearance that matchs the subelt (pattern) Search on any Assertion that is signed, or has a Response parent signed @param subelt [String] The XPath pattern @return [REXML::Element | nil] If any matches, return the Element

# File lib/ciam/ruby-saml/response.rb, line 661
def xpath_first_from_signed_assertion(subelt=nil)
  doc = decrypted_document.nil? ? document : decrypted_document
  node = REXML::XPath.first(
      doc,
      "/p:Response/a:Assertion[@ID=$id]#{subelt}",
      { "p" => PROTOCOL, "a" => ASSERTION },
      { 'id' => doc.signed_element_id }
  )
  node ||= REXML::XPath.first(
      doc,
      "/p:Response[@ID=$id]/a:Assertion#{subelt}",
      { "p" => PROTOCOL, "a" => ASSERTION },
      { 'id' => doc.signed_element_id }
  )
  node
end
xpath_from_signed_assertion(subelt=nil) click to toggle source

Extracts all the appearances that matchs the subelt (pattern) Search on any Assertion that is signed, or has a Response parent signed @param subelt [String] The XPath pattern @return [Array of REXML::Element] Return all matches

# File lib/ciam/ruby-saml/response.rb, line 640
def xpath_from_signed_assertion(subelt=nil)
  doc = decrypted_document.nil? ? document : decrypted_document
  node = REXML::XPath.match(
      doc,
      "/p:Response/a:Assertion[@ID=$id]#{subelt}",
      { "p" => PROTOCOL, "a" => ASSERTION },
      { 'id' => doc.signed_element_id }
  )
  node.concat( REXML::XPath.match(
      doc,
      "/p:Response[@ID=$id]/a:Assertion#{subelt}",
      { "p" => PROTOCOL, "a" => ASSERTION },
      { 'id' => doc.signed_element_id }
  ))
end