From 9153a6565b381777e6eb6c094856376d937af84c Mon Sep 17 00:00:00 2001 From: Steven Anderson Date: Fri, 9 Mar 2012 14:41:14 +0000 Subject: [PATCH] Working on code coverage 100% test coverage --- .gitignore | 2 + .rspec | 1 + Gemfile | 7 + Gemfile.lock | 64 +++++++++ Guardfile | 9 ++ lib/omniauth/strategies/saml.rb | 3 +- lib/omniauth/strategies/saml/auth_request.rb | 2 +- lib/omniauth/strategies/saml/auth_response.rb | 47 ++++--- lib/omniauth/strategies/saml/xml_security.rb | 2 +- omniauth-saml.gemspec | 8 +- .../strategies/saml/auth_request_spec.rb | 75 ++++++++++ .../strategies/saml/auth_response_spec.rb | 90 ++++++++++++ .../strategies/saml/validation_error_spec.rb | 5 + spec/omniauth/strategies/saml_spec.rb | 120 ++++++++++++++-- spec/shared/validating_method.rb | 129 +++++++++++++++++ spec/spec_helper.rb | 18 +++ spec/support/digest_mismatch.xml | 133 ++++++++++++++++++ spec/support/example_cert.pem | 57 ++++++++ spec/support/example_response.xml | 131 +++++++++++++++++ spec/support/invalid_signature.xml | 131 +++++++++++++++++ spec/support/no_attributes.xml | 57 ++++++++ spec/support/no_conditions.xml | 110 +++++++++++++++ spec/support/no_name_id.xml | 128 +++++++++++++++++ .../response_contains_signed_element.xml | 117 +++++++++++++++ 24 files changed, 1409 insertions(+), 37 deletions(-) create mode 100644 .gitignore create mode 100644 .rspec create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 Guardfile create mode 100644 spec/omniauth/strategies/saml/auth_request_spec.rb create mode 100644 spec/omniauth/strategies/saml/auth_response_spec.rb create mode 100644 spec/omniauth/strategies/saml/validation_error_spec.rb create mode 100644 spec/shared/validating_method.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/support/digest_mismatch.xml create mode 100644 spec/support/example_cert.pem create mode 100644 spec/support/example_response.xml create mode 100644 spec/support/invalid_signature.xml create mode 100644 spec/support/no_attributes.xml create mode 100644 spec/support/no_conditions.xml create mode 100644 spec/support/no_name_id.xml create mode 100644 spec/support/response_contains_signed_element.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c897b22e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +coverage/ +spec/support/example_private_key.pem diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..4e1e0d2f --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..7dc004ca --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source :rubygems + +gemspec + +group :development do + gem 'pry' +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..f8404d46 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,64 @@ +PATH + remote: . + specs: + omniauth-saml (0.9.1) + omniauth (~> 1.0) + uuid (~> 2.3) + xmlcanonicalizer (= 0.1.1) + +GEM + remote: http://rubygems.org/ + specs: + coderay (1.0.5) + diff-lcs (1.1.3) + ffi (1.0.11) + guard (1.0.1) + ffi (>= 0.5.0) + thor (~> 0.14.6) + guard-rspec (0.6.0) + guard (>= 0.10.0) + hashie (1.2.0) + macaddr (1.5.0) + systemu (>= 2.4.0) + method_source (0.7.1) + multi_json (1.1.0) + omniauth (1.0.3) + hashie (~> 1.2) + rack + pry (0.9.8.4) + coderay (~> 1.0.5) + method_source (~> 0.7.1) + slop (>= 2.4.4, < 3) + rack (1.4.1) + rack-test (0.6.1) + rack (>= 1.0) + rspec (2.8.0) + rspec-core (~> 2.8.0) + rspec-expectations (~> 2.8.0) + rspec-mocks (~> 2.8.0) + rspec-core (2.8.0) + rspec-expectations (2.8.0) + diff-lcs (~> 1.1.2) + rspec-mocks (2.8.0) + simplecov (0.6.1) + multi_json (~> 1.0) + simplecov-html (~> 0.5.3) + simplecov-html (0.5.3) + slop (2.4.4) + systemu (2.4.2) + thor (0.14.6) + uuid (2.3.5) + macaddr (~> 1.0) + xmlcanonicalizer (0.1.1) + +PLATFORMS + ruby + +DEPENDENCIES + guard (= 1.0.1) + guard-rspec (= 0.6.0) + omniauth-saml! + pry + rack-test (= 0.6.1) + rspec (= 2.8) + simplecov (= 0.6.1) diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..767287d8 --- /dev/null +++ b/Guardfile @@ -0,0 +1,9 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard 'rspec', :version => 2 do + watch(%r{^spec/.+_spec\.rb$}) + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { "spec" } +end + diff --git a/lib/omniauth/strategies/saml.rb b/lib/omniauth/strategies/saml.rb index 80ee17aa..8c02e701 100644 --- a/lib/omniauth/strategies/saml.rb +++ b/lib/omniauth/strategies/saml.rb @@ -20,12 +20,11 @@ def callback_phase begin response = OmniAuth::Strategies::SAML::AuthResponse.new(request.params['SAMLResponse']) response.settings = options - response.validate! @name_id = response.name_id @attributes = response.attributes - return fail!(:invalid_ticket, 'Invalid SAML Ticket') if @name_id.nil? || @name_id.empty? + return fail!(:invalid_ticket, 'Invalid SAML Ticket') if @name_id.nil? || @name_id.empty? || !response.valid? super rescue ArgumentError => e fail!(:invalid_ticket, 'Invalid SAML Response') diff --git a/lib/omniauth/strategies/saml/auth_request.rb b/lib/omniauth/strategies/saml/auth_request.rb index 39b9df0a..5ea48949 100644 --- a/lib/omniauth/strategies/saml/auth_request.rb +++ b/lib/omniauth/strategies/saml/auth_request.rb @@ -35,4 +35,4 @@ def create(settings, params = {}) end end end -end \ No newline at end of file +end diff --git a/lib/omniauth/strategies/saml/auth_response.rb b/lib/omniauth/strategies/saml/auth_response.rb index 410d50af..1d2ac0d9 100644 --- a/lib/omniauth/strategies/saml/auth_response.rb +++ b/lib/omniauth/strategies/saml/auth_response.rb @@ -18,7 +18,7 @@ def initialize(response, options = {}) self.document = OmniAuth::Strategies::SAML::XMLSecurity::SignedDocument.new(Base64.decode64(response)) end - def is_valid? + def valid? validate(soft = true) end @@ -29,39 +29,33 @@ def validate! # The value of the user identifier as designated by the initialization request response def name_id @name_id ||= begin - node = REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id[1,document.signed_element_id.size]}']/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION }) - node ||= REXML::XPath.first(document, "/p:Response[@ID='#{document.signed_element_id[1,document.signed_element_id.size]}']/a:Assertion/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION }) - node.nil? ? nil : node.text + node = xpath("/p:Response/a:Assertion[@ID='#{signed_element_id}']/a:Subject/a:NameID") + node ||= xpath("/p:Response[@ID='#{signed_element_id}']/a:Assertion/a:Subject/a:NameID") + node.nil? ? nil : strip(node.text) end end # A hash of all the attributes with the response. Assuming there is only one value for each key def attributes @attr_statements ||= begin - result = {} - - stmt_element = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AttributeStatement", { "p" => PROTOCOL, "a" => ASSERTION }) + stmt_element = xpath("/p:Response/a:Assertion/a:AttributeStatement") return {} if stmt_element.nil? - stmt_element.elements.each do |attr_element| - name = attr_element.attributes["Name"] - value = attr_element.elements.first.text - - result[name] = value - end + {}.tap do |result| + stmt_element.elements.each do |attr_element| + name = attr_element.attributes["Name"] + value = strip(attr_element.elements.first.text) - result.keys.each do |key| - result[key.intern] = result[key] + result[name] = result[name.to_sym] = value + end end - - result end end # When this user session should expire at latest def session_expires_at @expires_at ||= begin - node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AuthnStatement", { "p" => PROTOCOL, "a" => ASSERTION }) + node = xpath("/p:Response/a:Assertion/a:AuthnStatement") parse_time(node, "SessionNotOnOrAfter") end end @@ -69,7 +63,7 @@ def session_expires_at # Conditions (if any) for the assertion to run def conditions @conditions ||= begin - REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id[1,document.signed_element_id.size]}']/a:Conditions", { "p" => PROTOCOL, "a" => ASSERTION }) + xpath("/p:Response/a:Assertion[@ID='#{signed_element_id}']/a:Conditions") end end @@ -135,7 +129,20 @@ def parse_time(node, attribute) end end + def strip(string) + return string unless string + string.gsub(/^\s+/, '').gsub(/\s+$/, '') + end + + def xpath(path) + REXML::XPath.first(document, path, { "p" => PROTOCOL, "a" => ASSERTION }) + end + + def signed_element_id + doc_id = document.signed_element_id + doc_id[1, doc_id.size] + end end end end -end \ No newline at end of file +end diff --git a/lib/omniauth/strategies/saml/xml_security.rb b/lib/omniauth/strategies/saml/xml_security.rb index 55669c93..a86edb30 100644 --- a/lib/omniauth/strategies/saml/xml_security.rb +++ b/lib/omniauth/strategies/saml/xml_security.rb @@ -123,4 +123,4 @@ def extract_signed_element_id end end -end \ No newline at end of file +end diff --git a/omniauth-saml.gemspec b/omniauth-saml.gemspec index f65bf1d0..8da46a59 100644 --- a/omniauth-saml.gemspec +++ b/omniauth-saml.gemspec @@ -11,9 +11,15 @@ Gem::Specification.new do |gem| gem.homepage = "https://github.com/PracticallyGreen/omniauth-saml" gem.add_runtime_dependency 'omniauth', '~> 1.0' - gem.add_runtime_dependency 'xmlcanonicalizer' + gem.add_runtime_dependency 'xmlcanonicalizer', '0.1.1' gem.add_runtime_dependency 'uuid', '~> 2.3' + gem.add_development_dependency 'guard', '1.0.1' + gem.add_development_dependency 'guard-rspec', '0.6.0' + gem.add_development_dependency 'rspec', '2.8' + gem.add_development_dependency 'simplecov', '0.6.1' + gem.add_development_dependency 'rack-test', '0.6.1' + gem.files = ['README.md'] + Dir['lib/**/*.rb'] gem.test_files = Dir['spec/**/*.rb'] gem.require_paths = ["lib"] diff --git a/spec/omniauth/strategies/saml/auth_request_spec.rb b/spec/omniauth/strategies/saml/auth_request_spec.rb new file mode 100644 index 00000000..5e59920c --- /dev/null +++ b/spec/omniauth/strategies/saml/auth_request_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe OmniAuth::Strategies::SAML::AuthRequest do + describe :create do + let(:url) do + described_class.new.create( + { + :idp_sso_target_url => 'example.com', + :assertion_consumer_service_url => 'http://example.com/auth/saml/callback', + :issuer => 'This is an issuer', + :name_identifier_format => 'Some Policy' + }, + { + :some_param => 'foo', + :some_other => 'bar' + } + ) + end + let(:saml_request) { url.match(/SAMLRequest=(.*)/)[1] } + + describe "the url" do + subject { url } + + it "should contain a SAMLRequest query string param" do + subject.should match /^example\.com\?SAMLRequest=/ + end + + it "should contain any other parameters passed through" do + subject.should match /^example\.com\?SAMLRequest=(.*)&some_param=foo&some_other=bar/ + end + end + + describe "the saml request" do + subject { saml_request } + + let(:decoded) do + cgi_unescaped = CGI.unescape(subject) + base64_decoded = Base64.decode64(cgi_unescaped) + Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(base64_decoded) + end + + let(:xml) { REXML::Document.new(decoded) } + let(:root_element) { REXML::XPath.first(xml, '//samlp:AuthnRequest') } + + it "should contain base64 encoded and zlib deflated xml" do + decoded.should match /^ 'Steven', + :surname => 'Anderson', + :address_1 => '24 Made Up Drive', + :address_2 => nil, + :companyName => 'Test Company Ltd', + :postcode => 'XX2 4XX', + :city => 'Newcastle', + :country => 'United Kingdom', + :userEmailID => 'steve@example.com', + :county => 'TYNESIDE', + :versionID => '1', + :bundleID => '1', + + 'forename' => 'Steven', + 'surname' => 'Anderson', + 'address_1' => '24 Made Up Drive', + 'address_2' => nil, + 'companyName' => 'Test Company Ltd', + 'postcode' => 'XX2 4XX', + 'city' => 'Newcastle', + 'country' => 'United Kingdom', + 'userEmailID' => 'steve@example.com', + 'county' => 'TYNESIDE', + 'versionID' => '1', + 'bundleID' => '1' + } + end + + context "when no attributes exist in the XML" do + let(:xml) { :no_attributes } + + it "should return an empty hash" do + subject.attributes.should == {} + end + end + end + + describe :session_expires_at do + it "should return the SessionNotOnOrAfter as a Ruby date" do + subject.session_expires_at.to_i.should == Time.new(2012, 04, 8, 12, 0, 24, '+00:00').to_i + end + end + + describe :conditions do + it "should return the conditions element from the XML" do + subject.conditions.attributes['NotOnOrAfter'].should == '2012-03-08T16:30:01.336Z' + subject.conditions.attributes['NotBefore'].should == '2012-03-08T16:20:01.336Z' + REXML::XPath.first(subject.conditions, '//saml:Audience').text.should include 'AUDIENCE' + end + end + + describe :valid? do + it_should_behave_like 'a validating method', true + end + + describe :validate! do + it_should_behave_like 'a validating method', false + end +end diff --git a/spec/omniauth/strategies/saml/validation_error_spec.rb b/spec/omniauth/strategies/saml/validation_error_spec.rb new file mode 100644 index 00000000..d8cab790 --- /dev/null +++ b/spec/omniauth/strategies/saml/validation_error_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe OmniAuth::Strategies::SAML::ValidationError do + it { should be_a Exception } +end diff --git a/spec/omniauth/strategies/saml_spec.rb b/spec/omniauth/strategies/saml_spec.rb index 5c174c56..5b851357 100644 --- a/spec/omniauth/strategies/saml_spec.rb +++ b/spec/omniauth/strategies/saml_spec.rb @@ -1,18 +1,29 @@ -require File.expand_path('../../../spec_helper', __FILE__) +require 'spec_helper' -describe OmniAuth::Strategies::SAML, :type => :strategy do +RSpec::Matchers.define :fail_with do |message| + match do |actual| + actual.redirect? && actual.location == "/auth/failure?message=#{message}" + end +end + +def post_xml(xml=:example_response) + post "/auth/saml/callback", {'SAMLResponse' => load_xml(xml)} +end +describe OmniAuth::Strategies::SAML, :type => :strategy do include OmniAuth::Test::StrategyTestCase - def strategy - [OmniAuth::Strategies::SAML, { - :assertion_consumer_service_url => "http://consumer.service.url/auth/saml/callback", + let(:auth_hash){ last_request.env['omniauth.auth'] } + let(:saml_options) do + { + :assertion_consumer_service_url => "http://localhost:3000/auth/saml/callback", :issuer => "https://saml.issuer.url/issuers/29490", :idp_sso_target_url => "https://idp.sso.target_url/signon/29490", - :idp_cert_fingerprint => "E7:91:B2:E1:4C:65:2C:49:F3:33:74:0A:58:5A:7E:55:F7:15:7A:33", + :idp_cert_fingerprint => "E6:87:89:FB:F2:5F:CD:B0:31:32:7E:05:44:84:53:B1:EC:4E:3F:FA", :name_identifier_format => "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" - }] + } end + let(:strategy) { [OmniAuth::Strategies::SAML, saml_options] } describe 'GET /auth/saml' do before do @@ -25,13 +36,98 @@ def strategy end describe 'POST /auth/saml/callback' do + subject { last_response } - it 'should raise ArgumentError exception without the SAMLResponse parameter' do - post '/auth/saml/callback' - last_response.should be_redirect - last_response.location.should == '/auth/failure?message=invalid_ticket' + let(:xml) { :example_response } + + before :each do + Time.stub(:now).and_return(Time.new(2012, 3, 8, 16, 25)) end - end + context "when the response is valid" do + before :each do + post_xml + end + it "should set the uid to the nameID in the SAML response" do + auth_hash['uid'].should == 'THISISANAMEID' + end + + it "should set the raw info to all attributes" do + auth_hash['extra']['raw_info'].to_hash.should == { + 'forename' => 'Steven', + 'surname' => 'Anderson', + 'address_1' => '24 Made Up Drive', + 'address_2' => nil, + 'companyName' => 'Test Company Ltd', + 'postcode' => 'XX2 4XX', + 'city' => 'Newcastle', + 'country' => 'United Kingdom', + 'userEmailID' => 'steve@example.com', + 'county' => 'TYNESIDE', + 'versionID' => '1', + 'bundleID' => '1' + } + end + end + + context "when there is no SAMLResponse parameter" do + before :each do + post '/auth/saml/callback' + end + + it { should fail_with(:invalid_ticket) } + end + + context "when there is no name id in the XML" do + before :each do + post_xml :no_name_id + end + + it { should fail_with(:invalid_ticket) } + end + + context "when the fingerprint is invalid" do + before :each do + saml_options[:idp_cert_fingerprint] = "E6:87:89:FB:F2:5F:CD:B0:31:32:7E:05:44:84:53:B1:EC:4E:3F:FB" + post_xml + end + + it { should fail_with(:invalid_ticket) } + end + + context "when the digest is invalid" do + before :each do + post_xml :digest_mismatch + end + + it { should fail_with(:invalid_ticket) } + end + + context "when the signature is invalid" do + before :each do + post_xml :invalid_signature + end + + it { should fail_with(:invalid_ticket) } + end + + context "when the time is before the NotBefore date" do + before :each do + Time.stub(:now).and_return(Time.new(2000, 3, 8, 16, 25)) + post_xml + end + + it { should fail_with(:invalid_ticket) } + end + + context "when the time is after the NotOnOrAfter date" do + before :each do + Time.stub(:now).and_return(Time.new(3000, 3, 8, 16, 25)) + post_xml + end + + it { should fail_with(:invalid_ticket) } + end + end end diff --git a/spec/shared/validating_method.rb b/spec/shared/validating_method.rb new file mode 100644 index 00000000..841bae4c --- /dev/null +++ b/spec/shared/validating_method.rb @@ -0,0 +1,129 @@ +def assert_is_valid(soft) + if soft + it { should be_valid } + else + it "should be valid" do + expect { subject.validate! }.not_to raise_error + end + end +end + +def assert_is_not_valid(soft) + if soft + it { should_not be_valid } + else + it "should be invalid" do + expect { subject.validate! }.to raise_error + end + end +end + +def stub_validate_to_fail(soft) + if soft + subject.document.stub(:validate).and_return(false) + else + subject.document.stub(:validate).and_raise(Exception) + end +end + +shared_examples_for 'a validating method' do |soft| + before :each do + subject.settings = mock(Object, :idp_cert_fingerprint => 'FINGERPRINT', :idp_cert => nil) + subject.document.stub(:validate).and_return(true) + end + + context "when the response is empty" do + subject { described_class.new('') } + + assert_is_not_valid(soft) + end + + context "when the settings are nil" do + before :each do + subject.settings = nil + end + + assert_is_not_valid(soft) + end + + context "when there is no idp_cert_fingerprint and idp_cert" do + before :each do + subject.settings = mock(Object, :idp_cert_fingerprint => nil, :idp_cert => nil) + end + + assert_is_not_valid(soft) + end + + context "when conditions are not given" do + let(:xml) { :no_conditions } + + assert_is_valid(soft) + end + + context "when the current time is before the NotBefore time" do + before :each do + Time.stub(:now).and_return(Time.new(2000, 01, 01, 10, 00, 00)) + end + + assert_is_not_valid(soft) + end + + context "when the current time is after the NotOnOrAfter time" do + before :each do + # We're assuming here that this code will be out of use in 1000 years... + Time.stub(:now).and_return(Time.new(3012, 01, 01, 10, 00, 00)) + end + + assert_is_not_valid(soft) + end + + context "when the current time is between the NotBefore and NotOnOrAfter times" do + before :each do + Time.stub(:now).and_return(Time.new(2012, 3, 8, 16, 25, 00)) + end + + assert_is_valid(soft) + end + + context "when skip_conditions option is given" do + before :each do + subject.options[:skip_conditions] = true + end + + assert_is_valid(soft) + end + + context "when the SAML document is valid" do + before :each do + subject.document.should_receive(:validate).with('FINGERPRINT', soft).and_return(true) + subject.options[:skip_conditions] = true + end + + assert_is_valid(soft) + end + + context "when the SAML document is valid and the idp_cert is given" do + let(:cert) do + filename = File.expand_path(File.join('..', '..', 'support', "example_cert.pem"), __FILE__) + IO.read(filename) + end + let(:expected) { 'E6:87:89:FB:F2:5F:CD:B0:31:32:7E:05:44:84:53:B1:EC:4E:3F:FA' } + + before :each do + subject.settings.stub(:idp_cert).and_return(cert) + subject.document.should_receive(:validate).with(expected, soft).and_return(true) + subject.options[:skip_conditions] = true + end + + assert_is_valid(soft) + end + + context "when the SAML document is invalid" do + before :each do + stub_validate_to_fail(soft) + subject.options[:skip_conditions] = true + end + + assert_is_not_valid(soft) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 00000000..2daaccf3 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,18 @@ +require 'simplecov' +SimpleCov.start + +require 'omniauth-saml' +require 'rack/test' +require 'rexml/document' +require 'rexml/xpath' +require 'base64' +require File.expand_path('../shared/validating_method.rb', __FILE__) + +RSpec.configure do |config| + config.include Rack::Test::Methods +end + +def load_xml(filename=:example_response) + filename = File.expand_path(File.join('..', 'support', "#{filename.to_s}.xml"), __FILE__) + Base64.encode64(IO.read(filename)) +end diff --git a/spec/support/digest_mismatch.xml b/spec/support/digest_mismatch.xml new file mode 100644 index 00000000..218b3261 --- /dev/null +++ b/spec/support/digest_mismatch.xml @@ -0,0 +1,133 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + + + k/GIuFyIu5Dn3qJuEW+SIaNs80t= + + + jA2H4Jwlt7vbWkDK2T3Ebh/tgJxuIjSZy/5HY2G0WJfCQr2xoqvES3GLr5psdOsCggAkJxk1ctSE7facWgwczaOlZAk8cgUixyKnt16iSmTjq9bqdSzOrnZIsdkWpVyYbaCcuqKtPxAA3p/Kc36K4fMWefk1k9FJ9K568aDcd3A= + + + +MIICZDCCAc2gAwIBAgIJAKrWB6yPsCvZMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRUwEwYDVQQKDAxUZXN0IENvbXBh +bnkxEDAOBgNVBAMMB01yIFRlc3QwHhcNMTIwMzA5MTQ1NzA3WhcNMTUwMzA5MTQ1 +NzA3WjBLMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEVMBMGA1UE +CgwMVGVzdCBDb21wYW55MRAwDgYDVQQDDAdNciBUZXN0MIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDTOjSvGtxyOrXyZWs5t613ChmdlNzSTpAKDVqgNpj6Fr4a +tO0L73RB8+dO49Yh8G7cSGvA4Ss+rfuBI0f+tm154D4AvpMmGM2xp/s5ZG5netOx +m04DdkEPJcweVzg5b8warrYXV2BBKz1HXd/ujfifN+frESTufYEHf4YSMc+aDQID +AQABo1AwTjAdBgNVHQ4EFgQUg+OQTycfwj+U9ovInipOi0WBFIowHwYDVR0jBBgw +FoAUg+OQTycfwj+U9ovInipOi0WBFIowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQBVml8ipPbVxg7+Mv6KUf84Xp4aR+ASG+y7kcsWbqNt+WYbfXYoB2Qa +UrGyRdNeKWo/cHuQncvLyvomW3iCE2zYVeoBqDn/zt5drXYIzvQwVmGslsLl5cju +yU7l/6A4j4Axq9nqC0VYbIzFumV3DK64OpgdDNjExbXWaDI3Zc36mA== + + + + + MODULUS + EXPONENT + + + + + + + THISISANAMEID + + + + + + + + + AUDIENCE + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + + + Steven + + + + + Anderson + + + + + 24 Made Up Drive + + + + + + + + Test Company Ltd + + + + + XX2 4XX + + + + + Newcastle + + + + + United Kingdom + + + + + steve@example.com + + + + + TYNESIDE + + + + + 1 + + + + + 1 + + + + + diff --git a/spec/support/example_cert.pem b/spec/support/example_cert.pem new file mode 100644 index 00000000..8f5748c8 --- /dev/null +++ b/spec/support/example_cert.pem @@ -0,0 +1,57 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + aa:d6:07:ac:8f:b0:2b:d9 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Some-State, O=Test Company, CN=Mr Test + Validity + Not Before: Mar 9 14:57:07 2012 GMT + Not After : Mar 9 14:57:07 2015 GMT + Subject: C=AU, ST=Some-State, O=Test Company, CN=Mr Test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:d3:3a:34:af:1a:dc:72:3a:b5:f2:65:6b:39:b7: + ad:77:0a:19:9d:94:dc:d2:4e:90:0a:0d:5a:a0:36: + 98:fa:16:be:1a:b4:ed:0b:ef:74:41:f3:e7:4e:e3: + d6:21:f0:6e:dc:48:6b:c0:e1:2b:3e:ad:fb:81:23: + 47:fe:b6:6d:79:e0:3e:00:be:93:26:18:cd:b1:a7: + fb:39:64:6e:67:7a:d3:b1:9b:4e:03:76:41:0f:25: + cc:1e:57:38:39:6f:cc:1a:ae:b6:17:57:60:41:2b: + 3d:47:5d:df:ee:8d:f8:9f:37:e7:eb:11:24:ee:7d: + 81:07:7f:86:12:31:cf:9a:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 83:E3:90:4F:27:1F:C2:3F:94:F6:8B:C8:9E:2A:4E:8B:45:81:14:8A + X509v3 Authority Key Identifier: + keyid:83:E3:90:4F:27:1F:C2:3F:94:F6:8B:C8:9E:2A:4E:8B:45:81:14:8A + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 55:9a:5f:22:a4:f6:d5:c6:0e:fe:32:fe:8a:51:ff:38:5e:9e: + 1a:47:e0:12:1b:ec:bb:91:cb:16:6e:a3:6d:f9:66:1b:7d:76: + 28:07:64:1a:52:b1:b2:45:d3:5e:29:6a:3f:70:7b:90:9d:cb: + cb:ca:fa:26:5b:78:82:13:6c:d8:55:ea:01:a8:39:ff:ce:de: + 5d:ad:76:08:ce:f4:30:56:61:ac:96:c2:e5:e5:c8:ee:c9:4e: + e5:ff:a0:38:8f:80:31:ab:d9:ea:0b:45:58:6c:8c:c5:ba:65: + 77:0c:ae:b8:3a:98:1d:0c:d8:c4:c5:b5:d6:68:32:37:65:cd: + fa:98 +-----BEGIN CERTIFICATE----- +MIICZDCCAc2gAwIBAgIJAKrWB6yPsCvZMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRUwEwYDVQQKDAxUZXN0IENvbXBh +bnkxEDAOBgNVBAMMB01yIFRlc3QwHhcNMTIwMzA5MTQ1NzA3WhcNMTUwMzA5MTQ1 +NzA3WjBLMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEVMBMGA1UE +CgwMVGVzdCBDb21wYW55MRAwDgYDVQQDDAdNciBUZXN0MIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDTOjSvGtxyOrXyZWs5t613ChmdlNzSTpAKDVqgNpj6Fr4a +tO0L73RB8+dO49Yh8G7cSGvA4Ss+rfuBI0f+tm154D4AvpMmGM2xp/s5ZG5netOx +m04DdkEPJcweVzg5b8warrYXV2BBKz1HXd/ujfifN+frESTufYEHf4YSMc+aDQID +AQABo1AwTjAdBgNVHQ4EFgQUg+OQTycfwj+U9ovInipOi0WBFIowHwYDVR0jBBgw +FoAUg+OQTycfwj+U9ovInipOi0WBFIowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQBVml8ipPbVxg7+Mv6KUf84Xp4aR+ASG+y7kcsWbqNt+WYbfXYoB2Qa +UrGyRdNeKWo/cHuQncvLyvomW3iCE2zYVeoBqDn/zt5drXYIzvQwVmGslsLl5cju +yU7l/6A4j4Axq9nqC0VYbIzFumV3DK64OpgdDNjExbXWaDI3Zc36mA== +-----END CERTIFICATE----- diff --git a/spec/support/example_response.xml b/spec/support/example_response.xml new file mode 100644 index 00000000..77eb0937 --- /dev/null +++ b/spec/support/example_response.xml @@ -0,0 +1,131 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + k/GIuFyIu5Dn3qJuEW+SIaNs80s= + + + jA2H4Jwlt7vbWkDK2T3Ebh/tgJxuIjSZy/5HY2G0WJfCQr2xoqvES3GLr5psdOsCggAkJxk1ctSE7facWgwczaOlZAk8cgUixyKnt16iSmTjq9bqdSzOrnZIsdkWpVyYbaCcuqKtPxAA3p/Kc36K4fMWefk1k9FJ9K568aDcd3A= + + + +MIICZDCCAc2gAwIBAgIJAKrWB6yPsCvZMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRUwEwYDVQQKDAxUZXN0IENvbXBh +bnkxEDAOBgNVBAMMB01yIFRlc3QwHhcNMTIwMzA5MTQ1NzA3WhcNMTUwMzA5MTQ1 +NzA3WjBLMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEVMBMGA1UE +CgwMVGVzdCBDb21wYW55MRAwDgYDVQQDDAdNciBUZXN0MIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDTOjSvGtxyOrXyZWs5t613ChmdlNzSTpAKDVqgNpj6Fr4a +tO0L73RB8+dO49Yh8G7cSGvA4Ss+rfuBI0f+tm154D4AvpMmGM2xp/s5ZG5netOx +m04DdkEPJcweVzg5b8warrYXV2BBKz1HXd/ujfifN+frESTufYEHf4YSMc+aDQID +AQABo1AwTjAdBgNVHQ4EFgQUg+OQTycfwj+U9ovInipOi0WBFIowHwYDVR0jBBgw +FoAUg+OQTycfwj+U9ovInipOi0WBFIowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQBVml8ipPbVxg7+Mv6KUf84Xp4aR+ASG+y7kcsWbqNt+WYbfXYoB2Qa +UrGyRdNeKWo/cHuQncvLyvomW3iCE2zYVeoBqDn/zt5drXYIzvQwVmGslsLl5cju +yU7l/6A4j4Axq9nqC0VYbIzFumV3DK64OpgdDNjExbXWaDI3Zc36mA== + + + + + MODULUS + EXPONENT + + + + + + + THISISANAMEID + + + + + + + + + AUDIENCE + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + + + Steven + + + + + Anderson + + + + + 24 Made Up Drive + + + + + + + + Test Company Ltd + + + + + XX2 4XX + + + + + Newcastle + + + + + United Kingdom + + + + + steve@example.com + + + + + TYNESIDE + + + + + 1 + + + + + 1 + + + + + diff --git a/spec/support/invalid_signature.xml b/spec/support/invalid_signature.xml new file mode 100644 index 00000000..f5a94fe7 --- /dev/null +++ b/spec/support/invalid_signature.xml @@ -0,0 +1,131 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + k/GIuFyIu5Dn3qJuEW+SIaNs80s= + + + jA2H4Jwlt7vbWkDK2T3Ebh/tgJxuIjSZy/5HY2G0WJfCQr2xoqvES3GLr5psdOsCggAkJxk1ctSE7facWgwczaOlZAk8cgUixyKnt16iSmTjq9bqdSzOrTZIsdkWpVyYbaCcuqKtPxAA3p/Kc36K4fMWefk1k9FJ9K568aDcd3A= + + + +MIICZDCCAc2gAwIBAgIJAKrWB6yPsCvZMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRUwEwYDVQQKDAxUZXN0IENvbXBh +bnkxEDAOBgNVBAMMB01yIFRlc3QwHhcNMTIwMzA5MTQ1NzA3WhcNMTUwMzA5MTQ1 +NzA3WjBLMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEVMBMGA1UE +CgwMVGVzdCBDb21wYW55MRAwDgYDVQQDDAdNciBUZXN0MIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDTOjSvGtxyOrXyZWs5t613ChmdlNzSTpAKDVqgNpj6Fr4a +tO0L73RB8+dO49Yh8G7cSGvA4Ss+rfuBI0f+tm154D4AvpMmGM2xp/s5ZG5netOx +m04DdkEPJcweVzg5b8warrYXV2BBKz1HXd/ujfifN+frESTufYEHf4YSMc+aDQID +AQABo1AwTjAdBgNVHQ4EFgQUg+OQTycfwj+U9ovInipOi0WBFIowHwYDVR0jBBgw +FoAUg+OQTycfwj+U9ovInipOi0WBFIowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQBVml8ipPbVxg7+Mv6KUf84Xp4aR+ASG+y7kcsWbqNt+WYbfXYoB2Qa +UrGyRdNeKWo/cHuQncvLyvomW3iCE2zYVeoBqDn/zt5drXYIzvQwVmGslsLl5cju +yU7l/6A4j4Axq9nqC0VYbIzFumV3DK64OpgdDNjExbXWaDI3Zc36mA== + + + + + MODULUS + EXPONENT + + + + + + + THISISANAMEID + + + + + + + + + AUDIENCE + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + + + Steven + + + + + Anderson + + + + + 24 Made Up Drive + + + + + + + + Test Company Ltd + + + + + XX2 4XX + + + + + Newcastle + + + + + United Kingdom + + + + + steve@example.com + + + + + TYNESIDE + + + + + 1 + + + + + 1 + + + + + diff --git a/spec/support/no_attributes.xml b/spec/support/no_attributes.xml new file mode 100644 index 00000000..8aa8d879 --- /dev/null +++ b/spec/support/no_attributes.xml @@ -0,0 +1,57 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + DIGEST + + + SIGNATURE + + + X509CERT + + + + MODULUS + EXPONENT + + + + + + + THISISANAMEID + + + + + + + + + AUDIENCE + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + diff --git a/spec/support/no_conditions.xml b/spec/support/no_conditions.xml new file mode 100644 index 00000000..d9af7ad2 --- /dev/null +++ b/spec/support/no_conditions.xml @@ -0,0 +1,110 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + DIGEST + + + SIGNATURE + + + X509CERT + + + + MODULUS + EXPONENT + + + + + + + THISISANAMEID + + + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + + + Steven + + + + + Anderson + + + + + 24 Made Up Drive + + + + + + + + Test Company Ltd + + + + + XX2 4XX + + + + + Newcastle + + + + + United Kingdom + + + + + steve@example.com + + + + + TYNESIDE + + + + + 1 + + + + + 1 + + + + + diff --git a/spec/support/no_name_id.xml b/spec/support/no_name_id.xml new file mode 100644 index 00000000..6c9c9bd3 --- /dev/null +++ b/spec/support/no_name_id.xml @@ -0,0 +1,128 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + nRILJkxvBxWgaWMMLzOfeXowxZU= + + + gWjejUGA8W/ndqLmglf6dNUqeJ2QRB6T7Vto6wXkcUgkjqT3XkDN4BIsNB6U4SLv28zr/eYhQFF4keQ3DCrHcUuerpmnPMyk1HjDMPie6qrI5oVKy4W7SpV6MWE3E1ZlBYGGmTDLCh3fBzgv36mZn2eCHYwCfYEikVs2FnHXob0= + + + +MIICZDCCAc2gAwIBAgIJAKrWB6yPsCvZMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRUwEwYDVQQKDAxUZXN0IENvbXBh +bnkxEDAOBgNVBAMMB01yIFRlc3QwHhcNMTIwMzA5MTQ1NzA3WhcNMTUwMzA5MTQ1 +NzA3WjBLMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEVMBMGA1UE +CgwMVGVzdCBDb21wYW55MRAwDgYDVQQDDAdNciBUZXN0MIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDTOjSvGtxyOrXyZWs5t613ChmdlNzSTpAKDVqgNpj6Fr4a +tO0L73RB8+dO49Yh8G7cSGvA4Ss+rfuBI0f+tm154D4AvpMmGM2xp/s5ZG5netOx +m04DdkEPJcweVzg5b8warrYXV2BBKz1HXd/ujfifN+frESTufYEHf4YSMc+aDQID +AQABo1AwTjAdBgNVHQ4EFgQUg+OQTycfwj+U9ovInipOi0WBFIowHwYDVR0jBBgw +FoAUg+OQTycfwj+U9ovInipOi0WBFIowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQBVml8ipPbVxg7+Mv6KUf84Xp4aR+ASG+y7kcsWbqNt+WYbfXYoB2Qa +UrGyRdNeKWo/cHuQncvLyvomW3iCE2zYVeoBqDn/zt5drXYIzvQwVmGslsLl5cju +yU7l/6A4j4Axq9nqC0VYbIzFumV3DK64OpgdDNjExbXWaDI3Zc36mA== + + + + + MODULUS + EXPONENT + + + + + + + + + + + + + AUDIENCE + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + + + Steven + + + + + Anderson + + + + + 24 Made Up Drive + + + + + + + + Test Company Ltd + + + + + XX2 4XX + + + + + Newcastle + + + + + United Kingdom + + + + + steve@example.com + + + + + TYNESIDE + + + + + 1 + + + + + 1 + + + + + diff --git a/spec/support/response_contains_signed_element.xml b/spec/support/response_contains_signed_element.xml new file mode 100644 index 00000000..765a0bd8 --- /dev/null +++ b/spec/support/response_contains_signed_element.xml @@ -0,0 +1,117 @@ + + ISSUER + + + + + ISSUER + + + + + + + + + + + DIGEST + + + SIGNATURE + + + X509CERT + + + + MODULUS + EXPONENT + + + + + + + THISISANAMEID + + + + + + + + + AUDIENCE + + + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified + + + + + + + Steven + + + + + Anderson + + + + + 24 Made Up Drive + + + + + + + + Test Company Ltd + + + + + XX2 4XX + + + + + Newcastle + + + + + United Kingdom + + + + + steve@example.com + + + + + TYNESIDE + + + + + 1 + + + + + 1 + + + + +