omniauth-saml 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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