omniauth-saml 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of omniauth-saml might be problematic. Click here for more details.

data/README.md CHANGED
@@ -4,6 +4,13 @@ A generic SAML strategy for OmniAuth.
4
4
 
5
5
  https://github.com/PracticallyGreen/omniauth-saml
6
6
 
7
+ ## Requirements
8
+
9
+ * [OmniAuth](http://www.omniauth.org/) 1.0+
10
+ * Ruby 1.9.2
11
+
12
+ ## Usage
13
+
7
14
  Use the SAML strategy as a middleware in your application:
8
15
 
9
16
  ```ruby
@@ -12,6 +19,7 @@ use OmniAuth::Strategies::SAML,
12
19
  :assertion_consumer_service_url => "consumer_service_url",
13
20
  :issuer => "issuer",
14
21
  :idp_sso_target_url => "idp_sso_target_url",
22
+ :idp_cert => "-----BEGIN CERTIFICATE-----\n...-----END CERTIFICATE-----",
15
23
  :idp_cert_fingerprint => "E7:91:B2:E1:...",
16
24
  :name_identifier_format => "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
17
25
  ```
@@ -32,6 +40,7 @@ Rails.application.config.middleware.use OmniAuth::Builder do
32
40
  :assertion_consumer_service_url => "consumer_service_url",
33
41
  :issuer => "rails-application",
34
42
  :idp_sso_target_url => "idp_sso_target_url",
43
+ :idp_cert => "-----BEGIN CERTIFICATE-----\n...-----END CERTIFICATE-----",
35
44
  :idp_cert_fingerprint => "E7:91:B2:E1:...",
36
45
  :name_identifier_format => "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
37
46
  end
@@ -49,9 +58,13 @@ end
49
58
  * `:idp_sso_target_url` - The URL to which the authentication request should be sent.
50
59
  This would be on the identity provider. **Required**.
51
60
 
52
- * `:idp_cert_fingerprint` - The certificate fingerprint, e.g. "90:CC:16:F0:8D:...".
53
- This is provided from the identity provider when setting up the relationship.
54
- Optional.
61
+ * `:idp_cert` - The identity provider's certificate in PEM format. Takes precedence
62
+ over the fingerprint option below. This option or `:idp_cert_fingerprint` must
63
+ be present.
64
+
65
+ * `:idp_cert_fingerprint` - The SHA1 fingerprint of the certificate, e.g.
66
+ "90:CC:16:F0:8D:...". This is provided from the identity provider when setting up
67
+ the relationship. This option or `:idp_cert` must be present.
55
68
 
56
69
  * `:name_identifier_format` - Describes the format of the username required by this
57
70
  application. If you need the email address, use "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress".
@@ -59,15 +72,18 @@ end
59
72
  other options. Note that the identity provider might not support all options.
60
73
  Optional.
61
74
 
75
+ ## Authors
76
+
77
+ Authored by Raecoo Cao, Todd W Saxton, Ryan Wilcox, Rajiv Aaron Manglani, and Steven Anderson.
78
+
79
+ Maintained by [Rajiv Aaron Manglani](http://www.rajivmanglani.com/).
80
+
62
81
  ## License
63
82
 
64
- Copyright (c) 2011-2012 [Practically Green, Inc.](http://practicallygreen.com/) and [Rajiv Aaron Manglani](http://www.rajivmanglani.com/).
83
+ Copyright (c) 2011-2012 [Practically Green, Inc.](http://www.practicallygreen.com/).
65
84
  All rights reserved. Released under the MIT license.
66
85
 
67
- Portions Copyright (c) 2007 Sun Microsystems Inc.
68
- Portions Copyright (c) 2007 Todd W Saxton.
69
- Portions Copyright (c) 2011 Raecoo Cao.
70
- Portions Copyright (c) 2011 Ryan Wilcox.
86
+ Portions Copyright (c) 2007 Sun Microsystems Inc.
71
87
 
72
88
  Permission is hereby granted, free of charge, to any person obtaining a copy
73
89
  of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module SAML
3
- VERSION = "0.9.1"
3
+ VERSION = "0.9.2"
4
4
  end
5
5
  end
@@ -20,9 +20,11 @@ module OmniAuth
20
20
  begin
21
21
  response = OmniAuth::Strategies::SAML::AuthResponse.new(request.params['SAMLResponse'])
22
22
  response.settings = options
23
+
23
24
  @name_id = response.name_id
24
25
  @attributes = response.attributes
25
- return fail!(:invalid_ticket, 'Invalid SAML Ticket') if @name_id.nil? || @name_id.empty?
26
+
27
+ return fail!(:invalid_ticket, 'Invalid SAML Ticket') if @name_id.nil? || @name_id.empty? || !response.valid?
26
28
  super
27
29
  rescue ArgumentError => e
28
30
  fail!(:invalid_ticket, 'Invalid SAML Response')
@@ -35,4 +35,4 @@ module OmniAuth
35
35
  end
36
36
  end
37
37
  end
38
- end
38
+ end
@@ -18,7 +18,7 @@ module OmniAuth
18
18
  self.document = OmniAuth::Strategies::SAML::XMLSecurity::SignedDocument.new(Base64.decode64(response))
19
19
  end
20
20
 
21
- def is_valid?
21
+ def valid?
22
22
  validate(soft = true)
23
23
  end
24
24
 
@@ -29,39 +29,33 @@ module OmniAuth
29
29
  # The value of the user identifier as designated by the initialization request response
30
30
  def name_id
31
31
  @name_id ||= begin
32
- 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 })
33
- 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 })
34
- node.nil? ? nil : node.text
32
+ node = xpath("/p:Response/a:Assertion[@ID='#{signed_element_id}']/a:Subject/a:NameID")
33
+ node ||= xpath("/p:Response[@ID='#{signed_element_id}']/a:Assertion/a:Subject/a:NameID")
34
+ node.nil? ? nil : strip(node.text)
35
35
  end
36
36
  end
37
37
 
38
38
  # A hash of all the attributes with the response. Assuming there is only one value for each key
39
39
  def attributes
40
40
  @attr_statements ||= begin
41
- result = {}
42
-
43
- stmt_element = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AttributeStatement", { "p" => PROTOCOL, "a" => ASSERTION })
41
+ stmt_element = xpath("/p:Response/a:Assertion/a:AttributeStatement")
44
42
  return {} if stmt_element.nil?
45
43
 
46
- stmt_element.elements.each do |attr_element|
47
- name = attr_element.attributes["Name"]
48
- value = attr_element.elements.first.text
49
-
50
- result[name] = value
51
- end
44
+ {}.tap do |result|
45
+ stmt_element.elements.each do |attr_element|
46
+ name = attr_element.attributes["Name"]
47
+ value = strip(attr_element.elements.first.text)
52
48
 
53
- result.keys.each do |key|
54
- result[key.intern] = result[key]
49
+ result[name] = result[name.to_sym] = value
50
+ end
55
51
  end
56
-
57
- result
58
52
  end
59
53
  end
60
54
 
61
55
  # When this user session should expire at latest
62
56
  def session_expires_at
63
57
  @expires_at ||= begin
64
- node = REXML::XPath.first(document, "/p:Response/a:Assertion/a:AuthnStatement", { "p" => PROTOCOL, "a" => ASSERTION })
58
+ node = xpath("/p:Response/a:Assertion/a:AuthnStatement")
65
59
  parse_time(node, "SessionNotOnOrAfter")
66
60
  end
67
61
  end
@@ -69,7 +63,7 @@ module OmniAuth
69
63
  # Conditions (if any) for the assertion to run
70
64
  def conditions
71
65
  @conditions ||= begin
72
- 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 })
66
+ xpath("/p:Response/a:Assertion[@ID='#{signed_element_id}']/a:Conditions")
73
67
  end
74
68
  end
75
69
 
@@ -103,7 +97,7 @@ module OmniAuth
103
97
 
104
98
  def get_fingerprint
105
99
  if settings.idp_cert
106
- cert = OpenSSL::X509::Certificate.new(settings.idp_cert)
100
+ cert = OpenSSL::X509::Certificate.new(settings.idp_cert.gsub(/^ +/, ''))
107
101
  Digest::SHA1.hexdigest(cert.to_der).upcase.scan(/../).join(":")
108
102
  else
109
103
  settings.idp_cert_fingerprint
@@ -135,7 +129,20 @@ module OmniAuth
135
129
  end
136
130
  end
137
131
 
132
+ def strip(string)
133
+ return string unless string
134
+ string.gsub(/^\s+/, '').gsub(/\s+$/, '')
135
+ end
136
+
137
+ def xpath(path)
138
+ REXML::XPath.first(document, path, { "p" => PROTOCOL, "a" => ASSERTION })
139
+ end
140
+
141
+ def signed_element_id
142
+ doc_id = document.signed_element_id
143
+ doc_id[1, doc_id.size]
144
+ end
138
145
  end
139
146
  end
140
147
  end
141
- end
148
+ end
@@ -123,4 +123,4 @@ module OmniAuth
123
123
 
124
124
  end
125
125
  end
126
- end
126
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe OmniAuth::Strategies::SAML::AuthRequest do
4
+ describe :create do
5
+ let(:url) do
6
+ described_class.new.create(
7
+ {
8
+ :idp_sso_target_url => 'example.com',
9
+ :assertion_consumer_service_url => 'http://example.com/auth/saml/callback',
10
+ :issuer => 'This is an issuer',
11
+ :name_identifier_format => 'Some Policy'
12
+ },
13
+ {
14
+ :some_param => 'foo',
15
+ :some_other => 'bar'
16
+ }
17
+ )
18
+ end
19
+ let(:saml_request) { url.match(/SAMLRequest=(.*)/)[1] }
20
+
21
+ describe "the url" do
22
+ subject { url }
23
+
24
+ it "should contain a SAMLRequest query string param" do
25
+ subject.should match /^example\.com\?SAMLRequest=/
26
+ end
27
+
28
+ it "should contain any other parameters passed through" do
29
+ subject.should match /^example\.com\?SAMLRequest=(.*)&some_param=foo&some_other=bar/
30
+ end
31
+ end
32
+
33
+ describe "the saml request" do
34
+ subject { saml_request }
35
+
36
+ let(:decoded) do
37
+ cgi_unescaped = CGI.unescape(subject)
38
+ base64_decoded = Base64.decode64(cgi_unescaped)
39
+ Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(base64_decoded)
40
+ end
41
+
42
+ let(:xml) { REXML::Document.new(decoded) }
43
+ let(:root_element) { REXML::XPath.first(xml, '//samlp:AuthnRequest') }
44
+
45
+ it "should contain base64 encoded and zlib deflated xml" do
46
+ decoded.should match /^<samlp:AuthnRequest/
47
+ end
48
+
49
+ it "should contain a uuid with an underscore in front" do
50
+ UUID.any_instance.stub(:generate).and_return('MY_UUID')
51
+
52
+ root_element.attributes['ID'].should == '_MY_UUID'
53
+ end
54
+
55
+ it "should contain the current time as the IssueInstant" do
56
+ t = Time.now
57
+ Time.stub(:now).and_return(t)
58
+
59
+ root_element.attributes['IssueInstant'].should == t.utc.iso8601
60
+ end
61
+
62
+ it "should contain the callback url in the settings" do
63
+ root_element.attributes['AssertionConsumerServiceURL'].should == 'http://example.com/auth/saml/callback'
64
+ end
65
+
66
+ it "should contain the issuer" do
67
+ REXML::XPath.first(xml, '//saml:Issuer').text.should == 'This is an issuer'
68
+ end
69
+
70
+ it "should contain the name identifier format" do
71
+ REXML::XPath.first(xml, '//samlp:NameIDPolicy').attributes['Format'].should == 'Some Policy'
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe OmniAuth::Strategies::SAML::AuthResponse do
4
+ let(:xml) { :example_response }
5
+ subject { described_class.new(load_xml(xml)) }
6
+
7
+ describe :initialize do
8
+ context "when the response is nil" do
9
+ it "should raise an exception" do
10
+ expect { described_class.new(nil) }.to raise_error ArgumentError
11
+ end
12
+ end
13
+ end
14
+
15
+ describe :name_id do
16
+ it "should load the name id from the assertion" do
17
+ subject.name_id.should == 'THISISANAMEID'
18
+ end
19
+
20
+ context "when the response contains the signed_element_id" do
21
+ let(:xml) { :response_contains_signed_element }
22
+
23
+ it "should load the name id from the assertion" do
24
+ subject.name_id.should == 'THISISANAMEID'
25
+ end
26
+ end
27
+ end
28
+
29
+ describe :attributes do
30
+ it "should return all of the attributes as a hash" do
31
+ subject.attributes.should == {
32
+ :forename => 'Steven',
33
+ :surname => 'Anderson',
34
+ :address_1 => '24 Made Up Drive',
35
+ :address_2 => nil,
36
+ :companyName => 'Test Company Ltd',
37
+ :postcode => 'XX2 4XX',
38
+ :city => 'Newcastle',
39
+ :country => 'United Kingdom',
40
+ :userEmailID => 'steve@example.com',
41
+ :county => 'TYNESIDE',
42
+ :versionID => '1',
43
+ :bundleID => '1',
44
+
45
+ 'forename' => 'Steven',
46
+ 'surname' => 'Anderson',
47
+ 'address_1' => '24 Made Up Drive',
48
+ 'address_2' => nil,
49
+ 'companyName' => 'Test Company Ltd',
50
+ 'postcode' => 'XX2 4XX',
51
+ 'city' => 'Newcastle',
52
+ 'country' => 'United Kingdom',
53
+ 'userEmailID' => 'steve@example.com',
54
+ 'county' => 'TYNESIDE',
55
+ 'versionID' => '1',
56
+ 'bundleID' => '1'
57
+ }
58
+ end
59
+
60
+ context "when no attributes exist in the XML" do
61
+ let(:xml) { :no_attributes }
62
+
63
+ it "should return an empty hash" do
64
+ subject.attributes.should == {}
65
+ end
66
+ end
67
+ end
68
+
69
+ describe :session_expires_at do
70
+ it "should return the SessionNotOnOrAfter as a Ruby date" do
71
+ subject.session_expires_at.to_i.should == Time.new(2012, 04, 8, 12, 0, 24, 0).to_i
72
+ end
73
+ end
74
+
75
+ describe :conditions do
76
+ it "should return the conditions element from the XML" do
77
+ subject.conditions.attributes['NotOnOrAfter'].should == '2012-03-08T16:30:01.336Z'
78
+ subject.conditions.attributes['NotBefore'].should == '2012-03-08T16:20:01.336Z'
79
+ REXML::XPath.first(subject.conditions, '//saml:Audience').text.should include 'AUDIENCE'
80
+ end
81
+ end
82
+
83
+ describe :valid? do
84
+ it_should_behave_like 'a validating method', true
85
+ end
86
+
87
+ describe :validate! do
88
+ it_should_behave_like 'a validating method', false
89
+ end
90
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe OmniAuth::Strategies::SAML::ValidationError do
4
+ it { should be_a Exception }
5
+ end
@@ -1,18 +1,29 @@
1
- require File.expand_path('../../../spec_helper', __FILE__)
1
+ require 'spec_helper'
2
2
 
3
- describe OmniAuth::Strategies::SAML, :type => :strategy do
3
+ RSpec::Matchers.define :fail_with do |message|
4
+ match do |actual|
5
+ actual.redirect? && actual.location == "/auth/failure?message=#{message}"
6
+ end
7
+ end
8
+
9
+ def post_xml(xml=:example_response)
10
+ post "/auth/saml/callback", {'SAMLResponse' => load_xml(xml)}
11
+ end
4
12
 
13
+ describe OmniAuth::Strategies::SAML, :type => :strategy do
5
14
  include OmniAuth::Test::StrategyTestCase
6
15
 
7
- def strategy
8
- [OmniAuth::Strategies::SAML, {
9
- :assertion_consumer_service_url => "http://consumer.service.url/auth/saml/callback",
16
+ let(:auth_hash){ last_request.env['omniauth.auth'] }
17
+ let(:saml_options) do
18
+ {
19
+ :assertion_consumer_service_url => "http://localhost:3000/auth/saml/callback",
10
20
  :issuer => "https://saml.issuer.url/issuers/29490",
11
21
  :idp_sso_target_url => "https://idp.sso.target_url/signon/29490",
12
- :idp_cert_fingerprint => "E7:91:B2:E1:4C:65:2C:49:F3:33:74:0A:58:5A:7E:55:F7:15:7A:33",
22
+ :idp_cert_fingerprint => "E6:87:89:FB:F2:5F:CD:B0:31:32:7E:05:44:84:53:B1:EC:4E:3F:FA",
13
23
  :name_identifier_format => "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
14
- }]
24
+ }
15
25
  end
26
+ let(:strategy) { [OmniAuth::Strategies::SAML, saml_options] }
16
27
 
17
28
  describe 'GET /auth/saml' do
18
29
  before do
@@ -25,13 +36,98 @@ describe OmniAuth::Strategies::SAML, :type => :strategy do
25
36
  end
26
37
 
27
38
  describe 'POST /auth/saml/callback' do
39
+ subject { last_response }
28
40
 
29
- it 'should raise ArgumentError exception without the SAMLResponse parameter' do
30
- post '/auth/saml/callback'
31
- last_response.should be_redirect
32
- last_response.location.should == '/auth/failure?message=invalid_ticket'
41
+ let(:xml) { :example_response }
42
+
43
+ before :each do
44
+ Time.stub(:now).and_return(Time.new(2012, 3, 8, 16, 25, 00, 0))
33
45
  end
34
46
 
35
- end
47
+ context "when the response is valid" do
48
+ before :each do
49
+ post_xml
50
+ end
36
51
 
52
+ it "should set the uid to the nameID in the SAML response" do
53
+ auth_hash['uid'].should == 'THISISANAMEID'
54
+ end
55
+
56
+ it "should set the raw info to all attributes" do
57
+ auth_hash['extra']['raw_info'].to_hash.should == {
58
+ 'forename' => 'Steven',
59
+ 'surname' => 'Anderson',
60
+ 'address_1' => '24 Made Up Drive',
61
+ 'address_2' => nil,
62
+ 'companyName' => 'Test Company Ltd',
63
+ 'postcode' => 'XX2 4XX',
64
+ 'city' => 'Newcastle',
65
+ 'country' => 'United Kingdom',
66
+ 'userEmailID' => 'steve@example.com',
67
+ 'county' => 'TYNESIDE',
68
+ 'versionID' => '1',
69
+ 'bundleID' => '1'
70
+ }
71
+ end
72
+ end
73
+
74
+ context "when there is no SAMLResponse parameter" do
75
+ before :each do
76
+ post '/auth/saml/callback'
77
+ end
78
+
79
+ it { should fail_with(:invalid_ticket) }
80
+ end
81
+
82
+ context "when there is no name id in the XML" do
83
+ before :each do
84
+ post_xml :no_name_id
85
+ end
86
+
87
+ it { should fail_with(:invalid_ticket) }
88
+ end
89
+
90
+ context "when the fingerprint is invalid" do
91
+ before :each do
92
+ 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"
93
+ post_xml
94
+ end
95
+
96
+ it { should fail_with(:invalid_ticket) }
97
+ end
98
+
99
+ context "when the digest is invalid" do
100
+ before :each do
101
+ post_xml :digest_mismatch
102
+ end
103
+
104
+ it { should fail_with(:invalid_ticket) }
105
+ end
106
+
107
+ context "when the signature is invalid" do
108
+ before :each do
109
+ post_xml :invalid_signature
110
+ end
111
+
112
+ it { should fail_with(:invalid_ticket) }
113
+ end
114
+
115
+ context "when the time is before the NotBefore date" do
116
+ before :each do
117
+ Time.stub(:now).and_return(Time.new(2000, 3, 8, 16, 25, 00, 0))
118
+ post_xml
119
+ end
120
+
121
+ it { should fail_with(:invalid_ticket) }
122
+ end
123
+
124
+ context "when the time is after the NotOnOrAfter date" do
125
+ before :each do
126
+ Time.stub(:now).and_return(Time.new(3000, 3, 8, 16, 25, 00, 0))
127
+ post_xml
128
+ end
129
+
130
+ it { should fail_with(:invalid_ticket) }
131
+ end
132
+ end
37
133
  end
@@ -0,0 +1,129 @@
1
+ def assert_is_valid(soft)
2
+ if soft
3
+ it { should be_valid }
4
+ else
5
+ it "should be valid" do
6
+ expect { subject.validate! }.not_to raise_error
7
+ end
8
+ end
9
+ end
10
+
11
+ def assert_is_not_valid(soft)
12
+ if soft
13
+ it { should_not be_valid }
14
+ else
15
+ it "should be invalid" do
16
+ expect { subject.validate! }.to raise_error
17
+ end
18
+ end
19
+ end
20
+
21
+ def stub_validate_to_fail(soft)
22
+ if soft
23
+ subject.document.stub(:validate).and_return(false)
24
+ else
25
+ subject.document.stub(:validate).and_raise(Exception)
26
+ end
27
+ end
28
+
29
+ shared_examples_for 'a validating method' do |soft|
30
+ before :each do
31
+ subject.settings = mock(Object, :idp_cert_fingerprint => 'FINGERPRINT', :idp_cert => nil)
32
+ subject.document.stub(:validate).and_return(true)
33
+ end
34
+
35
+ context "when the response is empty" do
36
+ subject { described_class.new('') }
37
+
38
+ assert_is_not_valid(soft)
39
+ end
40
+
41
+ context "when the settings are nil" do
42
+ before :each do
43
+ subject.settings = nil
44
+ end
45
+
46
+ assert_is_not_valid(soft)
47
+ end
48
+
49
+ context "when there is no idp_cert_fingerprint and idp_cert" do
50
+ before :each do
51
+ subject.settings = mock(Object, :idp_cert_fingerprint => nil, :idp_cert => nil)
52
+ end
53
+
54
+ assert_is_not_valid(soft)
55
+ end
56
+
57
+ context "when conditions are not given" do
58
+ let(:xml) { :no_conditions }
59
+
60
+ assert_is_valid(soft)
61
+ end
62
+
63
+ context "when the current time is before the NotBefore time" do
64
+ before :each do
65
+ Time.stub(:now).and_return(Time.new(2000, 01, 01, 10, 00, 00, 0))
66
+ end
67
+
68
+ assert_is_not_valid(soft)
69
+ end
70
+
71
+ context "when the current time is after the NotOnOrAfter time" do
72
+ before :each do
73
+ # We're assuming here that this code will be out of use in 1000 years...
74
+ Time.stub(:now).and_return(Time.new(3012, 01, 01, 10, 00, 00, 0))
75
+ end
76
+
77
+ assert_is_not_valid(soft)
78
+ end
79
+
80
+ context "when the current time is between the NotBefore and NotOnOrAfter times" do
81
+ before :each do
82
+ Time.stub(:now).and_return(Time.new(2012, 3, 8, 16, 25, 00, 0))
83
+ end
84
+
85
+ assert_is_valid(soft)
86
+ end
87
+
88
+ context "when skip_conditions option is given" do
89
+ before :each do
90
+ subject.options[:skip_conditions] = true
91
+ end
92
+
93
+ assert_is_valid(soft)
94
+ end
95
+
96
+ context "when the SAML document is valid" do
97
+ before :each do
98
+ subject.document.should_receive(:validate).with('FINGERPRINT', soft).and_return(true)
99
+ subject.options[:skip_conditions] = true
100
+ end
101
+
102
+ assert_is_valid(soft)
103
+ end
104
+
105
+ context "when the SAML document is valid and the idp_cert is given" do
106
+ let(:cert) do
107
+ filename = File.expand_path(File.join('..', '..', 'support', "example_cert.pem"), __FILE__)
108
+ IO.read(filename)
109
+ end
110
+ let(:expected) { 'E6:87:89:FB:F2:5F:CD:B0:31:32:7E:05:44:84:53:B1:EC:4E:3F:FA' }
111
+
112
+ before :each do
113
+ subject.settings.stub(:idp_cert).and_return(cert)
114
+ subject.document.should_receive(:validate).with(expected, soft).and_return(true)
115
+ subject.options[:skip_conditions] = true
116
+ end
117
+
118
+ assert_is_valid(soft)
119
+ end
120
+
121
+ context "when the SAML document is invalid" do
122
+ before :each do
123
+ stub_validate_to_fail(soft)
124
+ subject.options[:skip_conditions] = true
125
+ end
126
+
127
+ assert_is_not_valid(soft)
128
+ end
129
+ end
@@ -0,0 +1,18 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ require 'omniauth-saml'
5
+ require 'rack/test'
6
+ require 'rexml/document'
7
+ require 'rexml/xpath'
8
+ require 'base64'
9
+ require File.expand_path('../shared/validating_method.rb', __FILE__)
10
+
11
+ RSpec.configure do |config|
12
+ config.include Rack::Test::Methods
13
+ end
14
+
15
+ def load_xml(filename=:example_response)
16
+ filename = File.expand_path(File.join('..', 'support', "#{filename.to_s}.xml"), __FILE__)
17
+ Base64.encode64(IO.read(filename))
18
+ end
metadata CHANGED
@@ -1,83 +1,113 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: omniauth-saml
3
- version: !ruby/object:Gem::Version
4
- hash: 57
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.2
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 9
9
- - 1
10
- version: 0.9.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Raecoo Cao
14
9
  - Ryan Wilcox
15
10
  - Rajiv Aaron Manglani
11
+ - Steven Anderson
16
12
  autorequire:
17
13
  bindir: bin
18
14
  cert_chain: []
19
-
20
- date: 2012-02-23 00:00:00 -05:00
21
- default_executable:
22
- dependencies:
23
- - !ruby/object:Gem::Dependency
15
+ date: 2012-03-30 00:00:00.000000000Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
24
18
  name: omniauth
25
- prerelease: false
26
- requirement: &id001 !ruby/object:Gem::Requirement
19
+ requirement: &70159259960020 !ruby/object:Gem::Requirement
27
20
  none: false
28
- requirements:
21
+ requirements:
29
22
  - - ~>
30
- - !ruby/object:Gem::Version
31
- hash: 15
32
- segments:
33
- - 1
34
- - 0
35
- version: "1.0"
23
+ - !ruby/object:Gem::Version
24
+ version: '1.0'
36
25
  type: :runtime
37
- version_requirements: *id001
38
- - !ruby/object:Gem::Dependency
39
- name: XMLCanonicalizer
40
26
  prerelease: false
41
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ version_requirements: *70159259960020
28
+ - !ruby/object:Gem::Dependency
29
+ name: xmlcanonicalizer
30
+ requirement: &70159259959000 !ruby/object:Gem::Requirement
42
31
  none: false
43
- requirements:
44
- - - ~>
45
- - !ruby/object:Gem::Version
46
- hash: 21
47
- segments:
48
- - 1
49
- - 0
50
- - 1
51
- version: 1.0.1
32
+ requirements:
33
+ - - =
34
+ - !ruby/object:Gem::Version
35
+ version: 0.1.1
52
36
  type: :runtime
53
- version_requirements: *id002
54
- - !ruby/object:Gem::Dependency
55
- name: uuid
56
37
  prerelease: false
57
- requirement: &id003 !ruby/object:Gem::Requirement
38
+ version_requirements: *70159259959000
39
+ - !ruby/object:Gem::Dependency
40
+ name: uuid
41
+ requirement: &70159259958260 !ruby/object:Gem::Requirement
58
42
  none: false
59
- requirements:
43
+ requirements:
60
44
  - - ~>
61
- - !ruby/object:Gem::Version
62
- hash: 5
63
- segments:
64
- - 2
65
- - 3
66
- version: "2.3"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.3'
67
47
  type: :runtime
68
- version_requirements: *id003
48
+ prerelease: false
49
+ version_requirements: *70159259958260
50
+ - !ruby/object:Gem::Dependency
51
+ name: guard
52
+ requirement: &70159259957340 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - =
56
+ - !ruby/object:Gem::Version
57
+ version: 1.0.1
58
+ type: :development
59
+ prerelease: false
60
+ version_requirements: *70159259957340
61
+ - !ruby/object:Gem::Dependency
62
+ name: guard-rspec
63
+ requirement: &70159259956340 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - =
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.0
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: *70159259956340
72
+ - !ruby/object:Gem::Dependency
73
+ name: rspec
74
+ requirement: &70159259955720 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - =
78
+ - !ruby/object:Gem::Version
79
+ version: '2.8'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: *70159259955720
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: &70159259954920 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - =
89
+ - !ruby/object:Gem::Version
90
+ version: 0.6.1
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: *70159259954920
94
+ - !ruby/object:Gem::Dependency
95
+ name: rack-test
96
+ requirement: &70159259954240 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - =
100
+ - !ruby/object:Gem::Version
101
+ version: 0.6.1
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: *70159259954240
69
105
  description: A generic SAML strategy for OmniAuth.
70
- email:
71
- - raecoo@gmail.com
72
- - rwilcox@wilcoxd.com
73
- - rajiv@alum.mit.edu
106
+ email: rajiv@alum.mit.edu
74
107
  executables: []
75
-
76
108
  extensions: []
77
-
78
109
  extra_rdoc_files: []
79
-
80
- files:
110
+ files:
81
111
  - README.md
82
112
  - lib/omniauth/strategies/saml/auth_request.rb
83
113
  - lib/omniauth/strategies/saml/auth_response.rb
@@ -86,40 +116,40 @@ files:
86
116
  - lib/omniauth/strategies/saml.rb
87
117
  - lib/omniauth-saml/version.rb
88
118
  - lib/omniauth-saml.rb
119
+ - spec/omniauth/strategies/saml/auth_request_spec.rb
120
+ - spec/omniauth/strategies/saml/auth_response_spec.rb
121
+ - spec/omniauth/strategies/saml/validation_error_spec.rb
89
122
  - spec/omniauth/strategies/saml_spec.rb
90
- has_rdoc: true
123
+ - spec/shared/validating_method.rb
124
+ - spec/spec_helper.rb
91
125
  homepage: https://github.com/PracticallyGreen/omniauth-saml
92
126
  licenses: []
93
-
94
127
  post_install_message:
95
128
  rdoc_options: []
96
-
97
- require_paths:
129
+ require_paths:
98
130
  - lib
99
- required_ruby_version: !ruby/object:Gem::Requirement
131
+ required_ruby_version: !ruby/object:Gem::Requirement
100
132
  none: false
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- hash: 3
105
- segments:
106
- - 0
107
- version: "0"
108
- required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
138
  none: false
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- hash: 3
114
- segments:
115
- - 0
116
- version: "0"
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
117
143
  requirements: []
118
-
119
144
  rubyforge_project:
120
- rubygems_version: 1.6.2
145
+ rubygems_version: 1.8.10
121
146
  signing_key:
122
147
  specification_version: 3
123
148
  summary: A generic SAML strategy for OmniAuth.
124
- test_files:
149
+ test_files:
150
+ - spec/omniauth/strategies/saml/auth_request_spec.rb
151
+ - spec/omniauth/strategies/saml/auth_response_spec.rb
152
+ - spec/omniauth/strategies/saml/validation_error_spec.rb
125
153
  - spec/omniauth/strategies/saml_spec.rb
154
+ - spec/shared/validating_method.rb
155
+ - spec/spec_helper.rb