Giter Site home page Giter Site logo

libsaml's Introduction

Build status Coverage status Code climate

libsaml

Libsaml is a Ruby gem to easily create SAML 2.0 messages. This gem was written because other SAML gems were missing functionality such as XML signing.

Libsaml's features include:

  • Multiple bindings:
    • HTTP-Post
    • HTTP-Redirect
    • HTTP-Artifact
    • SOAP
  • XML signing and verification
  • Pluggable backend for providers (FileStore backend included)

Copyright Digidentity B.V., released under the MIT license. This gem was written by Benoist Claassen.

Installation

Place in your Gemfile:

gem 'libsaml', require: 'saml'

Usage

Below follows how to configure the SAML gem in a service provider.

Store the private key in: config/ssl/key.pem

Store the public key of the identity provider in: config/ssl/trust-federate.cert

Add the Identity Provider web container configuration file to config/metadata/service_provider.xml.

This contains an encoded version of the public key, generate this in the ruby console by typing:

require 'openssl'
require 'base64'

pem = File.open("config/ssl/trust-federate.cert").read
cert = OpenSSL::X509::Certificate.new(pem)
output = Base64.encode64(cert.to_der).gsub("\n", "")

Add the Service Provider configuration file to: config/metadata/service_provider.xml:

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor ID="_052c51476c9560a429e1171e8c9528b96b69fb57" entityID="my:very:original:entityid" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
  <md:SPSSODescriptor>
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>SAME_KEY_AS_GENERATED_IN_THE_CONSOLE_BEFORE</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Post" Location="http://localhost:3000/saml/receive_response" index="0" isDefault="true"/>
  </md:SPSSODescriptor>
</md:EntityDescriptor>

Add the Identity Provider configuration file that your IdP should provide as config/metadata/service_provider.xml. It should have IDPSSODescriptor in it.

Set up an intializer in config/initializers/saml_config.rb:

Saml.setup do |config|
  config.register_store :file, Saml::ProviderStores::File.new("config/metadata", "config/ssl/key.pem"), default: true
end

By default this will use a SamlProvider model that uses the filestore, if you want a database driven model comment out the #provider_store function in the initializer and make a model that defines #find_by_entity_id:

class SamlProvider < ActiveRecord::Base
  include Saml::Provider

  def self.find_by_entity_id(entity_id)
    find_by entity_id: entity_id
  end
end

Now you can make a SAML controller in app/controllers/saml_controller.rb:

class SamlController < ApplicationController
  extend Saml::Rails::ControllerHelper
  current_provider "<sp_entity_id>"

  def request_authentication
    provider = Saml.provider("<idp_enity_id>")
    destination = provider.single_sign_on_service_url(Saml::ProtocolBinding::HTTP_POST)

    authn_request = Saml::AuthnRequest.new(destination: destination)

    session[:authn_request_id] = authn_request._id

    @saml_attributes = Saml::Bindings::HTTPPost.create_form_attributes(authn_request)
  end

  def receive_response
    if params["SAMLart"]
      # provider should be of type Saml::Provider
      @response = Saml::Bindings::HTTPArtifact.resolve(request, provider.artifact_resolution_service_url)
    elsif params["SAMLResponse"]
      @response = Saml::Bindings::HTTPPost.receive_message(request, :response)
    else
       # handle invalid request
    end

    if @response && @response.success?
      if session[:authn_request_id] == @response.in_response_to
        @response.assertion.fetch_attribute('any_attribute')
      else
        # handle unrecognized response
      end
      reset_session # It's good practice to reset sessions after authenticating to mitigate session fixation attacks
    else
      # handle failure
    end
  end
end

Add app/views/saml/request_authentication.html.erb for the POST binding:

<!DOCTYPE html>
<html>
<body>
<form method="post" action="<%= @saml_attributes[:location] %>" id="SAMLRequestForm">
  <%= @saml_attributes[:variables].each do |key, value| %>
    <input type="hidden" name="<%= key %>" value="<%= value %>"/>
  <%= end %>
  <input id="SAMLSubmitButton" type="submit" value="Submit"/>
</form>
<script>
  document.getElementById('SAMLSubmitButton').style.visibility = "hidden";
  document.getElementById('SAMLRequestForm').submit();
</script>
</body>
</html>

Don't forget to define the routes in config/routes.rb:

  get "/saml/request_authentication" => "saml#request_authentication"
  get "/saml/receive_response" => "saml#receive_response"
  post "/saml/receive_response" => "saml#receive_response"

Using libsaml as an IDP

Writing a solid identity provider really requires a deeper knowledge of the SAML protocol, so it's recommended to read more on the SAML 2.0 Wiki http://en.wikipedia.org/wiki/SAML_2.0. When you understand what it says, read these parts of the specification: http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf

Below is an example of a very primitive IDP Saml Controller

class SamlController < ActionController::Base
  extend Saml::Rails::ControllerHelper
  current_provider "<idp_entity_id>"

  def receive_authn_request
    authn_request = if request.get?
      Saml::Bindings::HTTPRedirect.receive_message(request, type: :authn_request)
    elsif request.post?
      Saml::Bindings::HTTPPost.receive_message(request, :authn_request)
    else
      return head :not_allowed
    end
    request_id = authn_request._id

    session[:saml_request] = {
      request_id:    request_id,
      relay_state:   params['RelayState'],
      authn_request: authn_request.to_xml
    }

    if authn_request.invalid?
      redirect_to send_response_path(request_id: request_id)
    else
      redirect_to sign_in_path(return_to: send_response_path(request_id: request_id))
    end
  end

  def send_response
    return head :not_found if session[:saml_request][:request_id] != params[:request_id]

    authn_request = Saml::AuthnRequest.parse(session[:saml_request][:authn_request], single: true)

    response = if authn_request.invalid?
      build_failure(Saml::TopLevelCodes::REQUESTER, Saml::SubStatusCodes::REQUEST_DENIED)
    elsif account_signed_in?
      build_success_response
    else
      build_failure(Saml::TopLevelCodes::RESPONDER, Saml::SubStatusCodes::NO_AUTHN_CONTEXT, 'cancelled')
    end

    if authn_request.protocol_binding == Saml::ProtocolBinding::HTTP_POST
      # render an auto submit form with hidden fields set in the attributes hash
      @attribute = Saml::Bindings::HTTPPost.create_form_attributes(response, relay_state: session[:saml_request][:relay_state])
    else
      # handle unsupported binding
    end
  end

  private

  def build_failure(status_value, sub_status_value, status_detail)
    Saml::Response.new(in_response_to:   session[:saml_request][:request_id],
                       status_value:     status_value,
                       sub_status_value: sub_status_value,
                       status_detail:    status_detail)
  end

  def build_success_response(authn_request)
    assertion = Saml::Assertion.new(
      name_id:                 current_account.username, # Return anything that you can link to an account
      name_id_format:          'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
      authn_context_class_ref: Saml::ClassRefs::PASSWORD_PROTECTED,
      in_response_to:          authn_request._id,
      recipient:               authn_request.assertion_url,
      audience:                authn_request.issuer)

    # adding custom attributes
    assertion.add_attribute('name', 'value')

    Saml::Response.new(in_response_to: authn_request._id,
                       assertion:      assertion,
                       status_value:   Saml::TopLevelCodes::SUCCESS)
  end
end

Caveats

  • SAMLResponse and Assertions have to be signed as per the SAML security guidelines (Some IDP's don't do this by default and require special configuration)

Contributing

  • Fork the project
  • Contribute your changes. Please make sure your changes are properly documented and covered by tests.
  • Send a pull request

libsaml's People

Contributors

aaaknowit avatar aaiiit avatar benoist avatar buffym avatar chaimsolomon avatar dannyvanderheiden avatar gyng avatar jandintel avatar jdongelmans avatar jonathan avatar kevintuhumury avatar lawliet89 avatar middagj avatar nddeluca avatar nov avatar p8 avatar pieterlange avatar pzgz avatar sahild avatar soartec-lab avatar truongnmt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libsaml's Issues

RSpec fails after upgrading(`~> 1.8`) gem `nokogiri`.

RSpec fails when using nokogiri 1.12.0 or higher

[vagrant@localhost libsaml]$ gem list nokogiri

*** LOCAL GEMS ***

nokogiri (1.12.0 x86_64-linux)
[vagrant@localhost libsaml]$ bundle exec rspec
[vagrant@localhost libsaml]$ bundle exec rspec
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}

Randomized with seed 39206
.....................................................FFFFFFFFFFFFF..................................................................................................F......................................................FFFFFFFFFF..............................................................................FFFFFFFF..FFFFFF..................................................................................................................................................................................................................................................................................................................................FF.FFF................................FFF.FF......................................................................................................................................................................................................

Failures:

  1) Saml::Bindings::SOAP.receive_message creates a notification
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./spec/lib/saml/bindings/soap_spec.rb:89:in `block (3 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:90:in `block (3 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:113:in `block (4 levels) in <top (required)>'
     # ./spec/support/notification_matcher.rb:12:in `block in matches?'
     # ./spec/support/notification_matcher.rb:11:in `matches?'
     # ./spec/lib/saml/bindings/soap_spec.rb:112:in `block (3 levels) in <top (required)>'

  2) Saml::Bindings::SOAP.receive_message with invalid signature adds an error if the signature is invalid
     Failure/Error:
       expect {
         response
       }.to raise_error(Saml::Errors::SignatureInvalid)
     
       expected Saml::Errors::SignatureInvalid, got #<NoMethodError: undefined method `content' for nil:NilClass> with backtrace:
         # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
         # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
         # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
         # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
         # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
         # ./lib/saml/util.rb:57:in `sign_xml'
         # ./spec/lib/saml/bindings/soap_spec.rb:89:in `block (3 levels) in <top (required)>'
         # ./spec/lib/saml/bindings/soap_spec.rb:90:in `block (3 levels) in <top (required)>'
         # ./spec/lib/saml/bindings/soap_spec.rb:106:in `block (5 levels) in <top (required)>'
         # ./spec/lib/saml/bindings/soap_spec.rb:105:in `block (4 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:105:in `block (4 levels) in <top (required)>'

  3) Saml::Bindings::SOAP.receive_message with valid signature verifies the signature in the artifact response
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./spec/lib/saml/bindings/soap_spec.rb:89:in `block (3 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:90:in `block (3 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:98:in `block (4 levels) in <top (required)>'

  4) Saml::Bindings::SOAP.receive_message with valid signature returns a logout request
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./spec/lib/saml/bindings/soap_spec.rb:89:in `block (3 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:90:in `block (3 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:94:in `block (4 levels) in <top (required)>'

  5) Saml::Bindings::SOAP.create_response_xml signs the response xml
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./lib/saml/bindings/soap.rb:11:in `create_response_xml'
     # ./spec/lib/saml/bindings/soap_spec.rb:10:in `block (2 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:14:in `block (3 levels) in <top (required)>'

  6) Saml::Bindings::SOAP.create_response_xml creates a notification
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./lib/saml/bindings/soap.rb:11:in `create_response_xml'
     # ./spec/lib/saml/bindings/soap_spec.rb:10:in `block (2 levels) in <top (required)>'
     # ./spec/lib/saml/bindings/soap_spec.rb:19:in `block (4 levels) in <top (required)>'
     # ./spec/support/notification_matcher.rb:12:in `block in matches?'
     # ./spec/support/notification_matcher.rb:11:in `matches?'
     # ./spec/lib/saml/bindings/soap_spec.rb:18:in `block (3 levels) in <top (required)>'

  7) Saml::Bindings::SOAP.post_message creates a notification
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./lib/saml/bindings/soap.rb:15:in `post_message'
     # ./spec/lib/saml/bindings/soap_spec.rb:32:in `block (4 levels) in <top (required)>'
     # ./spec/support/notification_matcher.rb:12:in `block in matches?'
     # ./spec/support/notification_matcher.rb:11:in `matches?'
     # ./spec/lib/saml/bindings/soap_spec.rb:27:in `block (3 levels) in <top (required)>'

  8) Saml::Bindings::SOAP.post_message with valid response verifies the signature in the artifact response
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./lib/saml/bindings/soap.rb:15:in `post_message'
     # ./spec/lib/saml/bindings/soap_spec.rb:42:in `block (4 levels) in <top (required)>'

  9) Saml::Bindings::SOAP.post_message with valid response sends the logout_request to the request destination
     Failure/Error:
       document.sign do |data, signature_algorithm|
         message.provider.sign(signature_algorithm, data)
       end
     
     NoMethodError:
       undefined method `content' for nil:NilClass
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
     # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
     # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
     # ./lib/saml/util.rb:57:in `sign_xml'
     # ./lib/saml/bindings/soap.rb:15:in `post_message'
     # ./spec/lib/saml/bindings/soap_spec.rb:42:in `block (4 levels) in <top (required)>'

  10) Saml::Bindings::SOAP.post_message with valid response signs the artifact resolve
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/soap.rb:15:in `post_message'
      # ./spec/lib/saml/bindings/soap_spec.rb:42:in `block (4 levels) in <top (required)>'

  11) Saml::Bindings::SOAP.post_message with valid response returns the logout_response
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/soap.rb:15:in `post_message'
      # ./spec/lib/saml/bindings/soap_spec.rb:42:in `block (4 levels) in <top (required)>'

  12) Saml::Bindings::SOAP.post_message with valid response creates a signed logout_request message
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/soap.rb:15:in `post_message'
      # ./spec/lib/saml/bindings/soap_spec.rb:42:in `block (4 levels) in <top (required)>'

  13) Saml::Bindings::SOAP.post_message with invalid signature adds an error if the signature is invalid
      Failure/Error:
        expect {
          described_class.post_message(logout_request, :logout_response)
        }.to raise_error(Saml::Errors::SignatureInvalid)
      
        expected Saml::Errors::SignatureInvalid, got #<NoMethodError: undefined method `content' for nil:NilClass> with backtrace:
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
          # ./lib/saml/util.rb:57:in `sign_xml'
          # ./lib/saml/bindings/soap.rb:15:in `post_message'
          # ./spec/lib/saml/bindings/soap_spec.rb:82:in `block (5 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/soap_spec.rb:81:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/soap_spec.rb:81:in `block (4 levels) in <top (required)>'

  14) BaseDummy parse override preserves the original value
      Failure/Error:
        document.sign do |data, signature_algorithm|
          new_artifact_response.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./spec/lib/saml/base_spec.rb:121:in `block (3 levels) in <top (required)>'

  15) Saml::Bindings::HTTPPost.create_form_attributes signs the document
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:12:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:23:in `block (3 levels) in <top (required)>'

  16) Saml::Bindings::HTTPPost.create_form_attributes sets the SAMLRequest variable if the message is a request
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:30:in `block (3 levels) in <top (required)>'

  17) Saml::Bindings::HTTPPost.create_form_attributes adds the relay_state
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:12:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:19:in `block (3 levels) in <top (required)>'

  18) Saml::Bindings::HTTPPost.create_form_attributes creates a hash with the destination as url
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:12:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:15:in `block (3 levels) in <top (required)>'

  19) Saml::Bindings::HTTPPost.create_form_attributes creates a notification
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:12:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:35:in `block (4 levels) in <top (required)>'
      # ./spec/support/notification_matcher.rb:12:in `block in matches?'
      # ./spec/support/notification_matcher.rb:11:in `matches?'
      # ./spec/lib/saml/bindings/http_post_spec.rb:35:in `block (3 levels) in <top (required)>'

  20) Saml::Bindings::HTTPPost.receive_message it verifies the xml
      Failure/Error:
        expect {
          message
        }.to raise_error(Saml::Errors::SignatureInvalid)
      
        expected Saml::Errors::SignatureInvalid, got #<NoMethodError: undefined method `content' for nil:NilClass> with backtrace:
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
          # ./lib/saml/util.rb:57:in `sign_xml'
          # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
          # ./spec/lib/saml/bindings/http_post_spec.rb:40:in `block (3 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_post_spec.rb:43:in `block (3 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_post_spec.rb:46:in `block (3 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_post_spec.rb:55:in `block (4 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_post_spec.rb:54:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:54:in `block (3 levels) in <top (required)>'

  21) Saml::Bindings::HTTPPost.receive_message creates a notification
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:40:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:43:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:46:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:69:in `block (4 levels) in <top (required)>'
      # ./spec/support/notification_matcher.rb:12:in `block in matches?'
      # ./spec/support/notification_matcher.rb:11:in `matches?'
      # ./spec/lib/saml/bindings/http_post_spec.rb:68:in `block (3 levels) in <top (required)>'

  22) Saml::Bindings::HTTPPost.receive_message sets the actual destination on the message
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:40:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:43:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:46:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:64:in `block (3 levels) in <top (required)>'

  23) Saml::Bindings::HTTPPost.receive_message returns the parsed message
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:40:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:43:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:46:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:60:in `block (3 levels) in <top (required)>'

  24) Saml::Bindings::HTTPPost.receive_message has no errors when signature is valid
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_post.rb:10:in `create_form_attributes'
      # ./spec/lib/saml/bindings/http_post_spec.rb:40:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:43:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:46:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_post_spec.rb:49:in `block (3 levels) in <top (required)>'

  25) Saml::Bindings::HTTPArtifact.create_response returns the content type
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:9:in `create_response_xml'
      # ./lib/saml/bindings/http_artifact.rb:13:in `create_response'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:17:in `block (2 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:36:in `block (3 levels) in <top (required)>'

  26) Saml::Bindings::HTTPArtifact.create_response returns the response xml
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:9:in `create_response_xml'
      # ./lib/saml/bindings/http_artifact.rb:13:in `create_response'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:17:in `block (2 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:32:in `block (3 levels) in <top (required)>'

  27) Saml::Bindings::HTTPArtifact.create_response_xml creates a notification
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:9:in `create_response_xml'
      # ./lib/saml/bindings/http_artifact.rb:13:in `create_response'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:17:in `block (2 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:26:in `block (4 levels) in <top (required)>'
      # ./spec/support/notification_matcher.rb:12:in `block in matches?'
      # ./spec/support/notification_matcher.rb:11:in `matches?'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:26:in `block (3 levels) in <top (required)>'

  28) Saml::Bindings::HTTPArtifact.create_response_xml signs the response xml
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:9:in `create_response_xml'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:16:in `block (2 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:22:in `block (3 levels) in <top (required)>'

  29) Saml::Bindings::HTTPArtifact.receive_message adds an error if the signature is invalid
      Failure/Error: expect { message }.to raise_error(Saml::Errors::SignatureInvalid)
      
        expected Saml::Errors::SignatureInvalid, got #<NoMethodError: undefined method `content' for nil:NilClass> with backtrace:
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
          # ./lib/saml/util.rb:57:in `sign_xml'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:58:in `block (3 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:61:in `block (3 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:62:in `block (3 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:74:in `block (4 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:74:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:74:in `block (3 levels) in <top (required)>'

  30) Saml::Bindings::HTTPArtifact.receive_message verifies the signature in the artifact resolve
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:58:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:61:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:62:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:69:in `block (3 levels) in <top (required)>'

  31) Saml::Bindings::HTTPArtifact.receive_message creates a notification
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:58:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:61:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:62:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:78:in `block (4 levels) in <top (required)>'
      # ./spec/support/notification_matcher.rb:12:in `block in matches?'
      # ./spec/support/notification_matcher.rb:11:in `matches?'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:78:in `block (3 levels) in <top (required)>'

  32) Saml::Bindings::HTTPArtifact.receive_message returns an artifact resolve
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:58:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:61:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:62:in `block (3 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:65:in `block (3 levels) in <top (required)>'

  33) Saml::Bindings::HTTPArtifact.resolve notifications creates a notification
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:37:in `resolve'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:94:in `block (5 levels) in <top (required)>'
      # ./spec/support/notification_matcher.rb:12:in `block in matches?'
      # ./spec/support/notification_matcher.rb:11:in `matches?'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:93:in `block (4 levels) in <top (required)>'

  34) Saml::Bindings::HTTPArtifact.resolve with invalid response adds an error if the signature is invalid
      Failure/Error:
        expect {
          described_class.resolve(request, identity_provider.artifact_resolution_service_url)
        }.to raise_error(Saml::Errors::SignatureInvalid)
      
        expected Saml::Errors::SignatureInvalid, got #<NoMethodError: undefined method `content' for nil:NilClass> with backtrace:
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
          # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
          # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
          # ./lib/saml/util.rb:57:in `sign_xml'
          # ./lib/saml/bindings/http_artifact.rb:37:in `resolve'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:141:in `block (5 levels) in <top (required)>'
          # ./spec/lib/saml/bindings/http_artifact_spec.rb:140:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:140:in `block (4 levels) in <top (required)>'

  35) Saml::Bindings::HTTPArtifact.resolve with valid response returns the response
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:37:in `resolve'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:105:in `block (4 levels) in <top (required)>'

  36) Saml::Bindings::HTTPArtifact.resolve with valid response creates a signed artifact_resolve message
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:37:in `resolve'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:105:in `block (4 levels) in <top (required)>'

  37) Saml::Bindings::HTTPArtifact.resolve with valid response signs the artifact resolve
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:37:in `resolve'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:105:in `block (4 levels) in <top (required)>'

  38) Saml::Bindings::HTTPArtifact.resolve with valid response sends the artifact_resolve to the identity provider
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./lib/saml/bindings/http_artifact.rb:37:in `resolve'
      # ./spec/lib/saml/bindings/http_artifact_spec.rb:105:in `block (4 levels) in <top (required)>'

  39) Saml::Util authn_request .sign_xml "format" parameter when no format is given formats the message as xml by default
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:34:in `block (6 levels) in <top (required)>'

  40) Saml::Util authn_request .sign_xml "format" parameter when a format is given formats the message as the given format
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:41:in `block (6 levels) in <top (required)>'

  41) Saml::Util authn_request .sign_xml "include_nested_prefixlist" parameter when disabled adds the default prefixlists to the unsigned signatures
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:72:in `block (6 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:50:in `block (5 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:75:in `block (6 levels) in <top (required)>'

  42) Saml::Util authn_request .sign_xml "include_nested_prefixlist" parameter when enabled by parameter adds the nested and the default prefixlists to the unsigned signatures
      Failure/Error: if signature.unsigned?
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # ./lib/saml/util.rb:47:in `block in sign_xml'
      # ./lib/saml/util.rb:41:in `each'
      # ./lib/saml/util.rb:41:in `each_with_object'
      # ./lib/saml/util.rb:41:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:64:in `block (6 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:50:in `block (5 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:67:in `block (6 levels) in <top (required)>'

  43) Saml::Util authn_request .sign_xml "include_nested_prefixlist" parameter when enabled by config adds the nested and the default prefixlists to the unsigned signatures
      Failure/Error: if signature.unsigned?
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # ./lib/saml/util.rb:47:in `block in sign_xml'
      # ./lib/saml/util.rb:41:in `each'
      # ./lib/saml/util.rb:41:in `each_with_object'
      # ./lib/saml/util.rb:41:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:56:in `block (6 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:50:in `block (5 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:59:in `block (6 levels) in <top (required)>'

  44) Saml::Util.verify_xml assertion verifies all the signatures in the file
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:317:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:320:in `block (4 levels) in <top (required)>'

  45) Saml::Util.verify_xml assertion returns the signed message type
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:317:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:328:in `block (4 levels) in <top (required)>'

  46) Saml::Util.verify_xml response returns the signed message type
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:282:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:307:in `block (4 levels) in <top (required)>'

  47) Saml::Util.verify_xml response verifies all the signatures in the file
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:282:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:285:in `block (4 levels) in <top (required)>'

  48) Saml::Util.verify_xml authn request within an artifact response parses the authn request from the signed XML without an undefined samlp prefix error
      Failure/Error:
        document.sign do |data, signature_algorithm|
          message.provider.sign(signature_algorithm, data)
        end
      
      NoMethodError:
        undefined method `content' for nil:NilClass
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:31:in `signature_value'
      # /home/vagrant/xmldsig/lib/xmldsig/signature.rb:48:in `unsigned?'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:22:in `block in sign'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `each'
      # /home/vagrant/xmldsig/lib/xmldsig/signed_document.rb:21:in `sign'
      # ./lib/saml/util.rb:57:in `sign_xml'
      # ./spec/lib/saml/util_spec.rb:338:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:340:in `block (4 levels) in <top (required)>'
      # ./spec/lib/saml/util_spec.rb:343:in `block (4 levels) in <top (required)>'

Finished in 4.53 seconds (files took 2.4 seconds to load)
887 examples, 48 failures

Failed examples:

rspec ./spec/lib/saml/bindings/soap_spec.rb:111 # Saml::Bindings::SOAP.receive_message creates a notification
rspec ./spec/lib/saml/bindings/soap_spec.rb:103 # Saml::Bindings::SOAP.receive_message with invalid signature adds an error if the signature is invalid
rspec ./spec/lib/saml/bindings/soap_spec.rb:97 # Saml::Bindings::SOAP.receive_message with valid signature verifies the signature in the artifact response
rspec ./spec/lib/saml/bindings/soap_spec.rb:93 # Saml::Bindings::SOAP.receive_message with valid signature returns a logout request
rspec ./spec/lib/saml/bindings/soap_spec.rb:13 # Saml::Bindings::SOAP.create_response_xml signs the response xml
rspec ./spec/lib/saml/bindings/soap_spec.rb:17 # Saml::Bindings::SOAP.create_response_xml creates a notification
rspec ./spec/lib/saml/bindings/soap_spec.rb:26 # Saml::Bindings::SOAP.post_message creates a notification
rspec ./spec/lib/saml/bindings/soap_spec.rb:55 # Saml::Bindings::SOAP.post_message with valid response verifies the signature in the artifact response
rspec ./spec/lib/saml/bindings/soap_spec.rb:59 # Saml::Bindings::SOAP.post_message with valid response sends the logout_request to the request destination
rspec ./spec/lib/saml/bindings/soap_spec.rb:50 # Saml::Bindings::SOAP.post_message with valid response signs the artifact resolve
rspec ./spec/lib/saml/bindings/soap_spec.rb:66 # Saml::Bindings::SOAP.post_message with valid response returns the logout_response
rspec ./spec/lib/saml/bindings/soap_spec.rb:45 # Saml::Bindings::SOAP.post_message with valid response creates a signed logout_request message
rspec ./spec/lib/saml/bindings/soap_spec.rb:79 # Saml::Bindings::SOAP.post_message with invalid signature adds an error if the signature is invalid
rspec ./spec/lib/saml/base_spec.rb:67 # BaseDummy parse override preserves the original value
rspec ./spec/lib/saml/bindings/http_post_spec.rb:22 # Saml::Bindings::HTTPPost.create_form_attributes signs the document
rspec ./spec/lib/saml/bindings/http_post_spec.rb:29 # Saml::Bindings::HTTPPost.create_form_attributes sets the SAMLRequest variable if the message is a request
rspec ./spec/lib/saml/bindings/http_post_spec.rb:18 # Saml::Bindings::HTTPPost.create_form_attributes adds the relay_state
rspec ./spec/lib/saml/bindings/http_post_spec.rb:14 # Saml::Bindings::HTTPPost.create_form_attributes creates a hash with the destination as url
rspec ./spec/lib/saml/bindings/http_post_spec.rb:34 # Saml::Bindings::HTTPPost.create_form_attributes creates a notification
rspec ./spec/lib/saml/bindings/http_post_spec.rb:52 # Saml::Bindings::HTTPPost.receive_message it verifies the xml
rspec ./spec/lib/saml/bindings/http_post_spec.rb:67 # Saml::Bindings::HTTPPost.receive_message creates a notification
rspec ./spec/lib/saml/bindings/http_post_spec.rb:63 # Saml::Bindings::HTTPPost.receive_message sets the actual destination on the message
rspec ./spec/lib/saml/bindings/http_post_spec.rb:59 # Saml::Bindings::HTTPPost.receive_message returns the parsed message
rspec ./spec/lib/saml/bindings/http_post_spec.rb:48 # Saml::Bindings::HTTPPost.receive_message has no errors when signature is valid
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:35 # Saml::Bindings::HTTPArtifact.create_response returns the content type
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:31 # Saml::Bindings::HTTPArtifact.create_response returns the response xml
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:25 # Saml::Bindings::HTTPArtifact.create_response_xml creates a notification
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:21 # Saml::Bindings::HTTPArtifact.create_response_xml signs the response xml
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:72 # Saml::Bindings::HTTPArtifact.receive_message adds an error if the signature is invalid
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:68 # Saml::Bindings::HTTPArtifact.receive_message verifies the signature in the artifact resolve
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:77 # Saml::Bindings::HTTPArtifact.receive_message creates a notification
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:64 # Saml::Bindings::HTTPArtifact.receive_message returns an artifact resolve
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:87 # Saml::Bindings::HTTPArtifact.resolve notifications creates a notification
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:138 # Saml::Bindings::HTTPArtifact.resolve with invalid response adds an error if the signature is invalid
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:125 # Saml::Bindings::HTTPArtifact.resolve with valid response returns the response
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:108 # Saml::Bindings::HTTPArtifact.resolve with valid response creates a signed artifact_resolve message
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:113 # Saml::Bindings::HTTPArtifact.resolve with valid response signs the artifact resolve
rspec ./spec/lib/saml/bindings/http_artifact_spec.rb:118 # Saml::Bindings::HTTPArtifact.resolve with valid response sends the artifact_resolve to the identity provider
rspec ./spec/lib/saml/util_spec.rb:32 # Saml::Util authn_request .sign_xml "format" parameter when no format is given formats the message as xml by default
rspec ./spec/lib/saml/util_spec.rb:39 # Saml::Util authn_request .sign_xml "format" parameter when a format is given formats the message as the given format
rspec ./spec/lib/saml/util_spec.rb:74 # Saml::Util authn_request .sign_xml "include_nested_prefixlist" parameter when disabled adds the default prefixlists to the unsigned signatures
rspec ./spec/lib/saml/util_spec.rb:66 # Saml::Util authn_request .sign_xml "include_nested_prefixlist" parameter when enabled by parameter adds the nested and the default prefixlists to the unsigned signatures
rspec ./spec/lib/saml/util_spec.rb:58 # Saml::Util authn_request .sign_xml "include_nested_prefixlist" parameter when enabled by config adds the nested and the default prefixlists to the unsigned signatures
rspec ./spec/lib/saml/util_spec.rb:319 # Saml::Util.verify_xml assertion verifies all the signatures in the file
rspec ./spec/lib/saml/util_spec.rb:326 # Saml::Util.verify_xml assertion returns the signed message type
rspec ./spec/lib/saml/util_spec.rb:305 # Saml::Util.verify_xml response returns the signed message type
rspec ./spec/lib/saml/util_spec.rb:284 # Saml::Util.verify_xml response verifies all the signatures in the file
rspec ./spec/lib/saml/util_spec.rb:342 # Saml::Util.verify_xml authn request within an artifact response parses the authn request from the signed XML without an undefined samlp prefix error

Randomized with seed 39206

Coverage report generated for RSpec to /home/vagrant/libsaml/coverage. 1964 / 1999 LOC (98.25%) covered.
[Coveralls] Outside the CI environment, not sending data.

Support for SAML responses where only the assertion is signed

Hi there,

I'm using this lib to implement SSO in our application. One of our clients does not sign their whole HTTP Post SAML response but only the assertion and this doesn't seem to be supported by libsaml.
Saml::Util.verify_xml expects the whole message to be signed but I don't understand why. Is it really necessary?

Regardless, we have asked our client to sign the complete message so this should not be a problem for us.

I'm just asking here because I don't understand why Saml::Util.verify_xml requires the message to be signed like this and I would be happy if someone could explain this to me.

And maybe this case should be handle explicitly because right now it will just blow up on signed_node.canonicalize (NoMethodError: undefined method `canonicalize' for nil:NilClass).

Removing curb dependency / JRuby support

Hi, I want use libsaml with JRuby but JRuby does not support C extensions in the 'curb' gem.

Why is curb a required dependency in the gemspec? I looked through the source and can't find anything that depends on curb.

Would you be OK with a pull request to remove curb?

Thanks.

Assertions can be signed without the saml response being signed

I've noticed that Saml::Util.sign_xml can only sign a saml response and assertions but not just assertions. It looks like a provider is required on the element before it can be signed. Since an assertion has an issuer I think it should have a provider on it and be able to be signed without the entire saml message being signed.

Support version of rails <= 4.2

Bundler could not find compatible versions for gem "activemodel":
  In snapshot (Gemfile.lock):
    activemodel (= 3.2.22.10)

  In Gemfile:
    rails3_acts_as_paranoid was resolved to 0.1.1, which depends on
      activerecord (>= 3.0.9) was resolved to 3.2.22.10, which depends on
        activemodel (= 3.2.22.10)

    libsaml (= 3.3.0) was resolved to 3.3.0, which depends on
      activemodel (>= 4.2)

Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.

KeyInfo node in EncryptedData node

Hey, guys!

Let me explain myself before doing my question:

Playing as an IdP (I am testing a SP application) I created, signed and encrypted a SAML document so the EncryptedData node result is something like this:

<xenc:EncryptedData Id="_e9bc13fa4e" Type="http://www.w3.org/2001/04/xmlenc#Element">
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
    <xenc:CipherData>
        <xenc:CipherValue>...
        </xenc:CipherValue>
    </xenc:CipherData>
</xenc:EncryptedData>

However, when I use Okta the generated SAML response has this:

<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_3bfac90f8f5bcec1ccbbcd65c35b9c58" Type="http://www.w3.org/2001/04/xmlenc#Element">
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:RetrievalMethod Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey" URI="#_931a8a29943a8407a4de23276473c22b"/>
    </ds:KeyInfo>
    <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
        <xenc:CipherValue>...</xenc:CipherValue>
    </xenc:CipherData>
</xenc:EncryptedData>

As you can see in my SAML response the ds:KeyInfo node is missing, now when I send my encrypted SAML response to the SP I am testing, it always fails when trying to validate the XML because the SP is using ruby-saml gem to validate the XML and I notice the ruby-saml gem is expecting for the KeyInfo node to decrypt the assertion, if the response does not have it, it fails to decrypt it.

Now, my question is: is there a way to add the KeyInfo data when encrypting an assertion?

Thanks in advance

Saml.provider(entity_id) should handle 2 kind of entity_id when acting as IdP

when handling authn request, the Entity ID given to Saml.provider(entity_id) is of SP (= request issuer).
however, when generating response, the Entity ID given to Saml.provider(entity_id) is of IdP (= response issuer).

So, current_provider && current_provider.entity_id == entity_id used in Saml.provider(entity_id) doesn't work well in IdP context.

module Saml
  def self.provider(entity_id)
    if current_provider && current_provider.entity_id == entity_id
      current_provider
    else
      current_store.find_by_entity_id(entity_id) || raise(Saml::Errors::InvalidProvider.new("Cannot find provider with entity_id: #{entity_id}"))
    end
  end
end

Do you have any advice to handle such case?

Rails 5 deprecation warnings

Rails 5.0.0.1 throws the warning when used with libsaml:

DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead.

The warning is thrown inside controller_helper.rb. before_action is not available in Rails 3, which, according to the gemspec, is supported by libsaml.

Will libsaml up the Rails requirement to Rails 4? I updated activemodel and activesupport to >=4 and tests are still passing. While just annoying right now, it will break with Rails 5.1.

chomp vs gsub("\n", "") on Base64 encoding

Hi there,

The SAML specification says when encoding base64 in urls linefeeds or other whitepsace MUST be removed from the result. Libsaml is using Base64.encode64(string).chomp which only removes the '\n' at the end of the string, is this on purpose?

https://www.oasis-open.org/committees/download.php/35387/sstc-saml-bindings-errata-2.0-wd-05-diff.pdf

The compressed data is subsequently base64-encoded according to the rules specified in IETF
RFC 2045 [RFC2045]. Linefeeds or other whitespace MUST be removed from the result.

Building Response does not populate digest or signature

I have added the assertion.add_attribute after specifying all assertions. The tag structure is correct and I do have the certificate populated. However, the digest and signature sections do not. I am not sure if this is incorrect configuration, or missing information. According to requirements this signature section is suppose to show in under the response and assertion tags. Below is some of my code used:

This is modeled after your build_success_response off the front page...

assertion = Saml::Assertion.new(
        name_id:                 user.login,
        name_id_format:          'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
        authn_context_class_ref: Saml::ClassRefs::PASSWORD_PROTECTED,
        in_response_to:          '2345678',
        recipient:               "#{url}",
        audience:                'COMPANY')

    # adding custom attributes


    assertion.add_attribute('anotherType', params[:login])
    assertion.add_attribute('someType', runAs)
    assertion.add_signature

    new_response = Saml::Response.new(in_response_to: 'company.com',
                       assertion:      assertion,
                       status_value:   Saml::TopLevelCodes::SUCCESS)
    new_response.add_signature

Support versions of rails before 4.0

Rails 4 introduced before_action in the controllers but still supports before_filters. It'd be nice if before_filter was used in the controller helper at least until they become deprecated so people still using rails 3.2 can use this lib.

Issues with decrypting assertions

Hello,

Thanks for this gem! It's been super helpful for us. Here's a bit of context around what I am trying to do on my current project.

I'm trying to integrate a rails app with a SAML 2.0 based IDP using HTTP Artifact binding. The IDP has a sample java client as a POC for integration. The flow is as follows -

  1. A user access the rails app's login page. We redirect the user to the IDP page where auhtentication happens.
  2. After successful login, the user is redirect to an end point hosted in the rails app with a SAMLART query parameter.
  3. We then make a server-server SOAP call to the Artifact resolution service to get an ArtifcatResponse which we then validate.
  4. The response contains an Encrypted Assertion that we decrypt and extract the details of the user to create a login.

We're roughly following the code listed in one of the previous issues for Steps 3 & 4. A fairly simple setup so far.

We have encountered an issue while trying to decrypt the encrypted assertion that we receive from the IDP. Here is the relevant part of the artifact response -

<?xml version="1.0" encoding="UTF-8"?>
<samlp:ArtifactResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" ID="_563b8aa41af86b3dd6fe6a10f5d60a37" Version="2.0" IssueInstant="2015-10-20T10:38:05Z" InResponseTo="_9ff8bd6dc633099357fe3bdaf87f206c1f9ad48e">
  <saml:Issuer>ISSUER</saml:Issuer>
  <ds:Signature>SIGNATURE_GOES_HERE</ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>
  <samlp:Response ID="_3f0a0590c33a341561ba5841dafaedc5" Version="2.0" IssueInstant="2015-10-20T10:38:05Z">
    <saml:Issuer>ISSUER</saml:Issuer>
    <samlp:Status>
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml2:EncryptedAssertion>
      <xenc:EncryptedData Id="_e618a8161efd727f135b546ec3c9c141" Type="http://www.w3.org/2001/04/xmlenc#Element">
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
        <ds:KeyInfo>
          <xenc:EncryptedKey>
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
              <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            </xenc:EncryptionMethod>
            <ds:KeyInfo/>
            <xenc:CipherData>
              <xenc:CipherValue>CIPHER_VALUE</xenc:CipherValue>
            </xenc:CipherData>
          </xenc:EncryptedKey>
        </ds:KeyInfo>
        <xenc:CipherData>
          <xenc:CipherValue>CIPHER_VALUE</xenc:CipherValue>
        </xenc:CipherData>
      </xenc:EncryptedData>
      <xenc:EncryptedKey>
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
          <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        </xenc:EncryptionMethod>
        <ds:KeyInfo/>
        <xenc:CipherData>
          <xenc:CipherValue>CIPHER_VALUE</xenc:CipherValue>
        </xenc:CipherData>
      </xenc:EncryptedKey>
    </saml2:EncryptedAssertion>
  </samlp:Response>
</samlp:ArtifactResponse>

The parsed artifact response has 2 EncryptedKey elements - one inside the EncryptedData node and the other exists as a sibling to the EncryptedData node. This causes an issue when we try to decrypt the EncryptedAsserstion as Xmlenc cannot find the relevent EncryptedData node.

Further, the additional EncryptedKey node is created after Saml::ArtifactResponse.parse is invoked.

Can you please shed some light on this? Why is the additional EncryptedKey node being created by ArtifactResponse#parse?

Also, on a tangent DigestMethod hardcodes the algorithm to http://www.w3.org/2001/0/xmlenc#sha256. We are using sha1. Any reason why this is so?

Thanks!

Nokogiri Bug Overpruning Namespace

There is an issue with Nokogiri (sparklemotion/nokogiri#1332) that causes some operations with libsaml to fail.

Namely, when a SAML response contains an EncryptedAssertion which itself contains an EncryptedID, the bug mentioned will prune the ds namespace from EncryptedID and ID decryption will fail.

There are two PRs that attempt to fix this. I am monitoring them, and will submit a PR to libsaml to update the dependencies when it's fixed in 1.6.8 release of Nokogiri (or xmlmapper?).

This issue is just as a reminder to do that -- hope you don't mind!

Redundant use of XmlMini_REXML

On reading XML parsing code, I noticed these lines of code:

libsaml/lib/saml/base.rb

Lines 45 to 47 in e2d3e12

if xml.is_a?(String)
ActiveSupport::XmlMini_REXML.parse(xml)
end

Why we're using another library REXML to parse XML, while the next line:

object = super

Which will call xmlmapper:

https://github.com/digidentity/xmlmapper/blob/24b38813cb461c8b6975dd553e1ffed3f32429d2/lib/xmlmapper.rb#L282-L289

    # @param [Nokogiri::XML::Node,Nokogiri:XML::Document,String] xml the XML
    #     contents to convert into Object.
    # @param [Hash] options additional information for parsing. :single => true
    #     if requesting a single object, otherwise it defaults to retuning an
    #     array of multiple items. :xpath information where to start the parsing
    #     :namespace is the namespace to use for additional information.
    #
    def parse(xml, options = {})

XMLMapper can receive String as a parameter type as well, why we need to use REXML to parse XML string? Besides, I don't see the parsed result by REXML is used anywhere.

Signature verification with multiple certificates when validating SAML responses

I'm having a problem implementing SP with libsaml.

In libsaml, if the metadata contains multiple certificates and no KeyName is specified in the SAML response, Saml::Util.verify_xml will always verify the signature with the first certificate.

return key_descriptors.first unless key_name_or_use_specified?

This means that the signature verification will always fail if the second certificate is actually used.
In fact, even IdPs like Google and Azure AD do not specify the KeyName in the SAML response when there are multiple certificates. (KeyName does not even exist in metadata)
This causes the problem that there are times when the user cannot log in during certificate rotation.

How about changing the implementation (or providing it as an option) to try to verify signatures using all certificates included in the metadata?
This idea has been implemented in OSS such as ruby-saml and Keycloak.
https://github.com/onelogin/ruby-saml/blob/master/lib/onelogin/ruby-saml/response.rb#L884-L898
https://github.com/keycloak/keycloak/blob/8e6489459dac322bbc61b6a63b7cb2d5aa9870af/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java#L498-L513


I'd like to contribute with a PullRequest, but I'm not familiar with libsam's implementation so it's going to take some time. I hope someone can help me.

nhosoya@e3be603 nhosoya@e4ac421
This change is sufficient to solve the problem I'm concerned about, but I still don't fully understand how this change will affect other features of libsaml.

ECP profile support?

Hi, I'm now working on SAML ECP implementation (for O365 users who uses Thunderbird).
It seems ECP isn't supported by this gem.
Do you have any plan for that?

Issues with `EncryptedID` decryption

Consider the <EncryptedID>:

<saml:EncryptedID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
  <EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
                 Id="uuid1b748bbd-0153-104f-8e34-b25c43474153" Type="http://www.w3.org/2001/04/xmlenc#Element">
    <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#" Id="uuid1b748bbe-0153-1d16-8fc6-b25c43474153">
        <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <CipherData>
          <CipherValue>
            ZxRgg1wMNqyVU/P6XbVsqKBTp6vGabMx46HjB5LrpBpVvPyEynaQDkCP39wk7P0A/kEtkxHj8k3sYczIS0mMv87XQ8R/3KyKdxqhxQNEmdiADKV67q2vvYmwQyLDzRZBfK1k3h9MLqGNFVSImV2U1yM6BfOxoGyIrwz0w3PWAks=
          </CipherValue>
        </CipherData>
      </EncryptedKey>
    </ds:KeyInfo>
    <CipherData>
      <CipherValue>
        RiBoXFMxB79gblJMaCk5eXORO3VxyrUQprKI9ZRKn9JiJQyZJVuNXoFMQFH2C9bhFHWkpgcP+ZBgWLXl+1+ALt6/pVXns43M2NzkOsH6H9i5A3BiOrHQdynw7413WX8vMK45a1Q3RbG4/FqBwqzI3y+pJUpQwDk2F+f6YH+wFHpP3FNuX9JIDMt8LXfPl3U1Py1TCiAeGZnLWm1fqoSAIMy/gRYbbJ5ZzCZlRjrhmlXEISoka4ktZhkidVBHgOxnyBom2cd4Os9P40xSLofByA==
      </CipherValue>
    </CipherData>
  </EncryptedData>
</saml:EncryptedID>

If we were to run the following:

xml = File.read 'encrypted_id.xml'
id = Saml::Elements::EncryptedID.parse xml
print id.to_xml

We will get (reformatted for readibility)

<?xml version="1.0" encoding="UTF-8"?>
<saml:EncryptedID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
                  xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <xenc:EncryptedData Id="uuid1b748bbd-0153-104f-8e34-b25c43474153" Type="http://www.w3.org/2001/04/xmlenc#Element">
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
    <ds:KeyInfo>
      <xenc:EncryptedKey Id="uuid1b748bbe-0153-1d16-8fc6-b25c43474153">
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <xenc:CipherData>
          <xenc:CipherValue>
            ZxRgg1wMNqyVU/P6XbVsqKBTp6vGabMx46HjB5LrpBpVvPyEynaQDkCP39wk7P0A/kEtkxHj8k3sYczIS0mMv87XQ8R/3KyKdxqhxQNEmdiADKV67q2vvYmwQyLDzRZBfK1k3h9MLqGNFVSImV2U1yM6BfOxoGyIrwz0w3PWAks=
          </xenc:CipherValue>
        </xenc:CipherData>
      </xenc:EncryptedKey>
    </ds:KeyInfo>
    <xenc:CipherData>
      <xenc:CipherValue>
        RiBoXFMxB79gblJMaCk5eXORO3VxyrUQprKI9ZRKn9JiJQyZJVuNXoFMQFH2C9bhFHWkpgcP+ZBgWLXl+1+ALt6/pVXns43M2NzkOsH6H9i5A3BiOrHQdynw7413WX8vMK45a1Q3RbG4/FqBwqzI3y+pJUpQwDk2F+f6YH+wFHpP3FNuX9JIDMt8LXfPl3U1Py1TCiAeGZnLWm1fqoSAIMy/gRYbbJ5ZzCZlRjrhmlXEISoka4ktZhkidVBHgOxnyBom2cd4Os9P40xSLofByA==
      </xenc:CipherValue>
    </xenc:CipherData>
  </xenc:EncryptedData>
  <xenc:EncryptedKey Id="uuid1b748bbe-0153-1d16-8fc6-b25c43474153">
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
    <xenc:CipherData>
      <xenc:CipherValue>
        ZxRgg1wMNqyVU/P6XbVsqKBTp6vGabMx46HjB5LrpBpVvPyEynaQDkCP39wk7P0A/kEtkxHj8k3sYczIS0mMv87XQ8R/3KyKdxqhxQNEmdiADKV67q2vvYmwQyLDzRZBfK1k3h9MLqGNFVSImV2U1yM6BfOxoGyIrwz0w3PWAks=
      </xenc:CipherValue>
    </xenc:CipherData>
  </xenc:EncryptedKey>
</saml:EncryptedID>

Notice that we now get an additional <xenc:EncryptedKey> element at the end of the XML output.

This causes an issue when trying to decrypt the ID and we will get the following exception:

  Xmlenc::EncryptedDataNotFound:
       Encrypted data not in ancestore element

This is because Xmlenc::EncryptedDocument.encrypted_keys now finds two keys, but only one encrypted_data is in the XML.

This issue can be fixed by changing line 16 of Saml::Elements::EncryptedID (by adding the xpath restriction) to

has_many :encrypted_keys, Xmlenc::Builder::EncryptedKey, xpath: './'

I'm not sure if this is an issue in libsaml or xmlmapper, and I don't quite understand how adding the xpath restriction fixes the issue.

`Saml::Elements::KeyInfo.key_name` being automatically generated

In the initializer for Saml::Elements::KeyInfo, the key_name attribute is automatically generated.

When we try to do the following where the key defined in the IdP metadata has no ds:KeyName assigned:

saml_response = Saml::Response.new(...)
artifact_response = Saml::ArtifactResponse.new(status_value: Saml::TopLevelCodes::SUCCESS,
                                             issuer: 'https://idp.example.com',
                                             destination: 'https://sp.example.com/acs')
artifact_response.response = saml_response

artifact_resolution_url = Saml.provider( 'https://idp.example.com').artifact_resolution_service_url
stub_request(:post, artifact_resolution_url).to_return(body: Saml::Util.sign_xml(artifact_response, :soap))
request = ... # A mock request object with SAMLart set to some arbitrary value
Saml::Bindings::HTTPArtifact.resolve(request, artifact_resolution_url)

Then we will get a SignatureInvalid error. This is because in Saml::Provider.verify, it tries to find a key with the ID generated during the signing, but this key in the IdP metadata has no name and is thus not found. Thus the call certificate(key_name).public_key.verify(digest_method(signature_algorithm).new, signature, data) in Saml::Provider.verify fails because certificate(key_name) returns nil.

Azure AADSTS700016: Application with identifier 'https://sts.windows.net/xxxx-xxxx-xxxx/' was not found in the directory 'xxxx-xxxx-xxxx'.

I have a sample project to test SAML Authentication using Azure as IdP. I have Azure metadata configuration saved as file in config/metadata.

After create AuthnRequest and send to Azure, I got this result from Azure:

AADSTS700016: Application with identifier 'https://sts.windows.net/xxxx-xxxx-xxxx/' was not found in the directory 'xxxx-xxxx-xxxx'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.

image

I create AuthnRequest by this command:

destination = Saml.current_provider.single_sign_on_service_url(Saml::ProtocolBinding::HTTP_REDIRECT)
authn_request = Saml::AuthnRequest.new(destination: destination)

The AuthnRequest issuer is taken from current_provider 's metadata. Which is IdP's entity id https://sts.windows.net/xxxx-xxxx-xxxx/. I think the right issuer should be the one who sent the request, which is the SP entity id: 'http://localhost:3000/saml/metadata'.

With that thought in mind, I specify issuer:

destination = Saml.current_provider.single_sign_on_service_url(Saml::ProtocolBinding::HTTP_REDIRECT)
authn_request = Saml::AuthnRequest.new(
    destination: destination,
    issuer: 'http://localhost:3000/saml/metadata'
)

However, when signing the SAML parameter, I got this error:

Cannot find provider with entity_id: http://localhost:3000/saml/metadata

https://github.com/digidentity/libsaml/blob/master/lib/saml/bindings/http_redirect.rb#L105

Because I specify the issuer so it will use that issuer as entity id to find for provider in providers store. That means it's finding the SP's provider metadata, which is either wrong (should be Idp metadata) or it's don't exist (I don't add that in config/metadata).

If I change like this it's worked. The AuthnRequest is accepted by Azure.

      def signed_params
-        signature = request_or_response.provider.sign(signature_algorithm, encoded_params)
+        signature = Saml.current_provider.sign(signature_algorithm, encoded_params)

        encoded_signature = CGI.escape(Saml::Encoding.encode_64(signature))

        "#{encoded_params}&Signature=#{encoded_signature}"
      end

SAMLResponse Examples

Do you have any documentation regarding receiving and parsing a SAMLResponse as the result of an auth request. Thanks to your great gem the IdP I'm working with will finally accept my signed Auth request! 😉

I see in the readme you have

 def receive_response
 end

Questions about documentation

By default this will use a SamlProvider model that uses the filestore, if you want a database driven model comment out the #provider_store function in the initializer and make a model that defines #find_by_entity_id:

class SamlProvider < ActiveRecord::Base
  include Saml::Provider

  def self.find_by_entity_id(entity_id)
    find_by entity_id: entity_id
  end
end

I have several questions regarding the documentation:

  • where is #provider_store function
  • by "database-driven model" means that we don't save metadata files and save them in the database?

Thanks for your time!

Possible bug - Should the x509 data in the KeyInfo remove new lines?

On https://github.com/digidentity/libsaml/blob/master/lib/saml/elements/key_info/x509_data.rb#L10, the certificate is base64 encoded and new lines are not removed. However, in the readme, the example code and service provider metadata removes the new lines from the certificate.

I'm using your gem to auto-generate service provider metadata from stored options and it's not clear to me which is the correct approach. Any guidance would be appreciated and thanks for the awesome gem !

Onelogin: undefined method `canonicalize' for nil:NilClass

I'm implementing libsaml as an SP provider. The configuration is the same as documentation:

https://github.com/truongnmt/ruby-saml-sample/tree/master/config

In config/metadata I have 2 IdPs metadata Azure and Onelogin.
On testing SSO with Onelogin, I got this error:

image

def verify_xml(message, raw_body)
  document = Xmldsig::SignedDocument.new(raw_body)

  signature_valid = document.validate do |signature, data, signature_algorithm|
    node = document.signatures.find { |s| s.signature_value == signature }.signature.at_xpath('descendant::ds:KeyName', Xmldsig::NAMESPACES)
    key_name = node.present? ? node.content : nil

    message.provider.verify(signature_algorithm, signature, data, key_name)
  end

  fail Saml::Errors::SignatureInvalid unless signature_valid

  signed_node = document.signed_nodes.find { |node| node['ID'] == message._id }
  message.class.parse(signed_node.canonicalize, single: true)
end

undefined method `canonicalize' for nil:NilClass

The error is this line message.class.parse(signed_node.canonicalize, single: true)

On testing SSO with Azure, I got this error:
image

AADSTS90015: Requested query string is too long.

Same code but I got SAML Request from Onelogin, while in Azure, the SAML Request is invalid.

RSA KeyValue tag in the KeyInfo.

Hi,

    <ds:KeyInfo>
      <ds:X509Data>
        <ds:X509Certificate>
          xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        </ds:X509Certificate>
      </ds:X509Data>
      <ds:KeyValue>
        <ds:RSAKeyValue>
          <ds:Modulus>
            xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
          </ds:Modulus>
          <ds:Exponent>AQAB</ds:Exponent>
        </ds:RSAKeyValue>
      </ds:KeyValue>
    </ds:KeyInfo>

but my keyInfo tags looks something like this:

      <ds:KeyInfo>
        <ds:KeyName>8b020738a9974ddf495fdf275527ad0ecc437c02</ds:KeyName>
        <ds:X509Data>
          <ds:X509Certificate> Some text
</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>

I was going through the file here:
https://github.com/digidentity/libsaml/blob/master/lib/saml/elements/key_info.rb#L12-L14
And noticed KeyInfo do not have has_one :key_value .
I am not sure if this out of purpose? or this attribute is depreceted and no longer needed?
Any quick or non-quick solution to include this in the KeyInfo node.

Regards
Sahil

Signature Invalid error

I'm tearing my hair out over this one. It seems that no matter what I do I am getting Signature Invalid errors. I'm trying to set up a Shibboleth server to work with a Rails app, and I'm almost there except for this one error. I've put everything with repeatable steps into this example app:

https://github.com/eltiare/libsaml-shib-test

From my reading of the code, it seems that responses are not decrypted. Is that true?

Ability To Specify A different Signature Algorithm.

Hi,
I was comparing the SAML generated and the sample SAML request i needed to create and noticed that signature algorithms are different.

<ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI="#_7bf53f24a45449258e6a9dc9d575314e57ca9e15"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <ec:InclusiveNamespaces PrefixList="ds saml samlp xs"/> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>N6RFW+/Y+PQXV6wks3oZqieraTJdxVr+9pQd8LIGwtQ=</ds:DigestValue> </ds:Reference> </ds:SignedInfo>

<ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#YdLC00_3TUAUV.gHa9jUb.4J5fP"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>/F6w5kUzhV6FINapRt/MkNr9Te8=</ds:DigestValue> </ds:Reference> </ds:SignedInfo>

this lead me to this line of code:
https://github.com/digidentity/libsaml/blob/master/lib/saml/elements/signature/signature_method.rb#L13

Is it possible to use a different signature algorithm like http://www.w3.org/2000/09/xmldsig#rsa-sha1

I am not even sure is at verification level it even matters, since it is mentioned in the Assertion which signature algorithm is used and the assertion should be verified against that only.

Question about SAML Response validation

When receiving response message, I only see that we verify the XML only

Saml::Util.verify_xml(request_or_response, message)

What about other validations?

  • response's state
  • SAML version
  • condition
  • response id
  • success status
  • in response to
  • audience
  • response's issuer
  • ...

Just to confirm that does these validations is DIY or libsaml already do these validations?

Add element SessionNotOnOrAfter

From SAML core spec:

SessionNotOnOrAfter [Optional]

Specifies a time instant at which the session between the principal identified by the subject and the SAML authority issuing this statement MUST be considered ended. The time value is encoded in UTC, as described in Section 1.3.3. There is no required relationship between this attribute and a NotOnOrAfter condition attribute that may be present in the assertion.

I'm about to validate this attribute from the assertion just to find out that we haven't had SessionNotOnOrAfter element yet.

https://github.com/digidentity/libsaml/blob/e2d3e126fef84e489281efed08602202b41447eb/lib/saml/elements/authn_statement.rb

module Saml
  module Elements
    class AuthnStatement
      include Saml::Base

      tag "AuthnStatement"
      namespace 'saml'

      attribute :authn_instant, Time, tag: "AuthnInstant", on_save: lambda { |val| val.utc.xmlschema }
      attribute :session_index, String, tag: "SessionIndex"

      has_one :subject_locality, Saml::Elements::SubjectLocality, tag: "SubjectLocality"
      has_one :authn_context, Saml::Elements::AuthnContext, tag: "AuthnContext"

      validates :authn_instant, :authn_context, presence: true

      def initialize(*args)
        options = args.extract_options!
        @subject_locality = Saml::Elements::SubjectLocality.new(address: options.delete(:address)) if options[:address]
        @authn_context = Saml::Elements::AuthnContext.new(authn_context_class_ref: options.delete(:authn_context_class_ref)) if options[:authn_context_class_ref]
        super(*(args << options))
      end
    end
  end
end

Would you please confirm this? Thanks!

Example Identity Provider

The current Readme file has an example configuration and usage for a service provider. It would be great to have a matching example for an identity provider. I would be happy to either update the Readme file or add a wiki page, if someone could point me to a code example.

Help sought on “Digest value” & “Signature value”

@benoist .

We are doing an integration with DigiD, a digital identity service in the Netherlands, (its similar to authentication service like google or facebook and uses SAML 2.0).

To authenticate our application to their service ( to allow our users to log in to our application using this DigiD service), we have been asked for an xml with the certificate details, public key info, and some more details.

While we were able to furnish all the information to them, we could not figure out what do we enter in the below two tags and where do we obtain these values/information from :
snippet from the entire xml ( for security purpose) :


Ds:DigestValueirsh4GNXQcsbkUmex22XsUejBTXyDdHfaUL/MFFWQHs=</Ds:DigestValue>
</Ds:Reference>
</Ds:SignedInfo>
Ds:SignatureValueYJ0V4gCTwRYvgyLnOEvyF2ddwBFwILL4nCpw==</Ds:SignatureValue>
</Ds:Signature>


Note - the value you see in the above xml between these two tags are samples that was provided by the third party provider as a reference.

We are using "HTTP-Redirect" binding for the connection.

Any help in this regard is appreciated. thank you.

Best regards,
vikpande

xmldsig dependency issue

Any chance of a new 2.24.2 version that updates the xmldsig dependency from '~> 0.5.1' to '~> 0.6.0'?

The reason I ask: I'm dealing with a project that's still stuck on Rails3, but I'd like to take advantage of nokogiri 1.8.0. I can't because:

libsaml 2.24.1 is the highest version that doesn't require Rails4 and it depends on xmldsig '~> 0.5.1'.

xmldsig 0.5.1 is the latest 0.5.x. It depends on nokogiri '~> 1.6.8'. This dependency is changed to '< 2.0.0, >= 1.6.8' in xmldsig 0.6.3, which would allow for newer versions of nokogiri, but libsaml 2.24.1 prevents xmldsig from going up to 0.6.3.

AttributeValue for assertion attributes doesn't have "type" set

I'm using libsaml in my mock identity provider and have an issue with custom attributes.
Adding an additional attribute to the assertion, like:

assertion.add_attribute('FirstName', 'John')

produces SAMLResponse with such element:

<saml:Attribute Name="FirstName">
    <saml:AttributeValue>John</saml:AttributeValue>
</saml:Attribute>

which causes my service provider (based on OpenSAML) to crash with error:

java.lang.ClassCastException: org.opensaml.xml.schema.impl.XSAnyImpl cannot be cast to org.opensaml.xml.schema.impl.XSStringImpl

Comparing with SAMLResponse from other providers (like SSOCircle) I figured out that "type" attribute should be set for the value, like:

<saml:Attribute Name="FirstName">
    <saml:AttributeValue xsi:type="xs:string">John</saml:AttributeValue>
</saml:Attribute>

Saml::Elements::AttributeValue class has such attribute but it is not filled during initialization.

Currently I'm using a dirty hack setting this attribute in the Saml::ComplexTypes::AttributeType:

def attribute_value=(value)
    attribute_value = if value.is_a? String
      Saml::Elements::AttributeValue.new(content: value, type: 'xs:string')
    else
      value
    end
    self.attribute_values = [attribute_value]
end

but maybe there are other ways to deal with the problem?

How to populate DigestValue in the signed Info.

I am trying to add a siginature using add_signature present here:
https://github.com/digidentity/libsaml/blob/master/lib/saml/xml_helpers.rb#L5

but i am not sure where and how to calculate digest_value that is being passed to SignedInfo here:
https://github.com/digidentity/libsaml/blob/master/lib/saml/elements/signature.rb#L27

and hence DigestValue node in my final SAML node is always empty:
<ds:DigestValue/>

I am pretty sure i am doing something wrong but could not find anything in the code to figure this out.

Is it possible to add an example somewhere regarding this.

If you can let me know i can add a wiki page for the gem regarding this.

Sign using SHA1

Currently, I only see the algorithm used to sign the saml is SHA256, but I need to sign it by using SHA1, that feature is implemented? I don´t see it, if not I can do a PR with it

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.