saml_idp 0.12.0 → 0.15.0

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.
@@ -19,6 +19,9 @@ module SamlIdp
19
19
  key_transport: 'rsa-oaep-mgf1p',
20
20
  }
21
21
  end
22
+ let(:session_expiry) { nil }
23
+ let(:name_id_formats_opt) { nil }
24
+ let(:asserted_attributes_opt) { nil }
22
25
  subject { described_class.new(
23
26
  reference_id,
24
27
  issuer_uri,
@@ -103,6 +106,76 @@ module SamlIdp
103
106
  expect(encrypted_xml).to_not match(audience_uri)
104
107
  end
105
108
 
109
+ describe "with name_id_formats_opt" do
110
+ let(:name_id_formats_opt) {
111
+ {
112
+ persistent: -> (principal) {
113
+ principal.unique_identifier
114
+ }
115
+ }
116
+ }
117
+ it "delegates name_id_formats to opts" do
118
+ UserWithUniqueId = Struct.new(:unique_identifier, :email, :asserted_attributes)
119
+ principal = UserWithUniqueId.new('unique_identifier_123456', 'foo@example.com', { emailAddress: { getter: :email } })
120
+ builder = described_class.new(
121
+ reference_id,
122
+ issuer_uri,
123
+ principal,
124
+ audience_uri,
125
+ saml_request_id,
126
+ saml_acs_url,
127
+ algorithm,
128
+ authn_context_classref,
129
+ expiry,
130
+ encryption_opts,
131
+ session_expiry,
132
+ name_id_formats_opt,
133
+ asserted_attributes_opt
134
+ )
135
+ Timecop.travel(Time.zone.local(2010, 6, 1, 13, 0, 0)) do
136
+ expect(builder.raw).to eq("<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_abc\" IssueInstant=\"2010-06-01T13:00:00Z\" Version=\"2.0\"><Issuer>http://sportngin.com</Issuer><Subject><NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent\">unique_identifier_123456</NameID><SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData InResponseTo=\"123\" NotOnOrAfter=\"2010-06-01T13:03:00Z\" Recipient=\"http://saml.acs.url\"></SubjectConfirmationData></SubjectConfirmation></Subject><Conditions NotBefore=\"2010-06-01T12:59:55Z\" NotOnOrAfter=\"2010-06-01T16:00:00Z\"><AudienceRestriction><Audience>http://example.com</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"2010-06-01T13:00:00Z\" SessionIndex=\"_abc\"><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef></AuthnContext></AuthnStatement><AttributeStatement><Attribute Name=\"emailAddress\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" FriendlyName=\"emailAddress\"><AttributeValue>foo@example.com</AttributeValue></Attribute></AttributeStatement></Assertion>")
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "with asserted_attributes_opt" do
142
+ let(:asserted_attributes_opt) {
143
+ {
144
+ 'GivenName' => {
145
+ getter: :first_name
146
+ },
147
+ 'SurName' => {
148
+ getter: -> (principal) {
149
+ principal.last_name
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ it "delegates asserted_attributes to opts" do
156
+ UserWithName = Struct.new(:email, :first_name, :last_name)
157
+ principal = UserWithName.new('foo@example.com', 'George', 'Washington')
158
+ builder = described_class.new(
159
+ reference_id,
160
+ issuer_uri,
161
+ principal,
162
+ audience_uri,
163
+ saml_request_id,
164
+ saml_acs_url,
165
+ algorithm,
166
+ authn_context_classref,
167
+ expiry,
168
+ encryption_opts,
169
+ session_expiry,
170
+ name_id_formats_opt,
171
+ asserted_attributes_opt
172
+ )
173
+ Timecop.travel(Time.zone.local(2010, 6, 1, 13, 0, 0)) do
174
+ expect(builder.raw).to eq("<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_abc\" IssueInstant=\"2010-06-01T13:00:00Z\" Version=\"2.0\"><Issuer>http://sportngin.com</Issuer><Subject><NameID Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\">foo@example.com</NameID><SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData InResponseTo=\"123\" NotOnOrAfter=\"2010-06-01T13:03:00Z\" Recipient=\"http://saml.acs.url\"></SubjectConfirmationData></SubjectConfirmation></Subject><Conditions NotBefore=\"2010-06-01T12:59:55Z\" NotOnOrAfter=\"2010-06-01T16:00:00Z\"><AudienceRestriction><Audience>http://example.com</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"2010-06-01T13:00:00Z\" SessionIndex=\"_abc\"><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef></AuthnContext></AuthnStatement><AttributeStatement><Attribute Name=\"GivenName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" FriendlyName=\"GivenName\"><AttributeValue>George</AttributeValue></Attribute><Attribute Name=\"SurName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" FriendlyName=\"SurName\"><AttributeValue>Washington</AttributeValue></Attribute></AttributeStatement></Assertion>")
175
+ end
176
+ end
177
+ end
178
+
106
179
  describe "with custom session_expiry configuration" do
107
180
  let(:config) { SamlIdp::Configurator.new }
108
181
  before do
@@ -126,5 +199,75 @@ module SamlIdp
126
199
  expect(builder.session_expiry).to eq(8)
127
200
  end
128
201
  end
202
+
203
+ describe "with name_id_formats_opt" do
204
+ let(:name_id_formats_opt) {
205
+ {
206
+ persistent: -> (principal) {
207
+ principal.unique_identifier
208
+ }
209
+ }
210
+ }
211
+ it "delegates name_id_formats to opts" do
212
+ UserWithUniqueId = Struct.new(:unique_identifier, :email, :asserted_attributes)
213
+ principal = UserWithUniqueId.new('unique_identifier_123456', 'foo@example.com', { emailAddress: { getter: :email } })
214
+ builder = described_class.new(
215
+ reference_id,
216
+ issuer_uri,
217
+ principal,
218
+ audience_uri,
219
+ saml_request_id,
220
+ saml_acs_url,
221
+ algorithm,
222
+ authn_context_classref,
223
+ expiry,
224
+ encryption_opts,
225
+ session_expiry,
226
+ name_id_formats_opt,
227
+ asserted_attributes_opt
228
+ )
229
+ Timecop.travel(Time.zone.local(2010, 6, 1, 13, 0, 0)) do
230
+ expect(builder.raw).to eq("<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_abc\" IssueInstant=\"2010-06-01T13:00:00Z\" Version=\"2.0\"><Issuer>http://sportngin.com</Issuer><Subject><NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent\">unique_identifier_123456</NameID><SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData InResponseTo=\"123\" NotOnOrAfter=\"2010-06-01T13:03:00Z\" Recipient=\"http://saml.acs.url\"></SubjectConfirmationData></SubjectConfirmation></Subject><Conditions NotBefore=\"2010-06-01T12:59:55Z\" NotOnOrAfter=\"2010-06-01T16:00:00Z\"><AudienceRestriction><Audience>http://example.com</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"2010-06-01T13:00:00Z\" SessionIndex=\"_abc\"><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef></AuthnContext></AuthnStatement><AttributeStatement><Attribute Name=\"emailAddress\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" FriendlyName=\"emailAddress\"><AttributeValue>foo@example.com</AttributeValue></Attribute></AttributeStatement></Assertion>")
231
+ end
232
+ end
233
+ end
234
+
235
+ describe "with asserted_attributes_opt" do
236
+ let(:asserted_attributes_opt) {
237
+ {
238
+ 'GivenName' => {
239
+ getter: :first_name
240
+ },
241
+ 'SurName' => {
242
+ getter: -> (principal) {
243
+ principal.last_name
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ it "delegates asserted_attributes to opts" do
250
+ UserWithName = Struct.new(:email, :first_name, :last_name)
251
+ principal = UserWithName.new('foo@example.com', 'George', 'Washington')
252
+ builder = described_class.new(
253
+ reference_id,
254
+ issuer_uri,
255
+ principal,
256
+ audience_uri,
257
+ saml_request_id,
258
+ saml_acs_url,
259
+ algorithm,
260
+ authn_context_classref,
261
+ expiry,
262
+ encryption_opts,
263
+ session_expiry,
264
+ name_id_formats_opt,
265
+ asserted_attributes_opt
266
+ )
267
+ Timecop.travel(Time.zone.local(2010, 6, 1, 13, 0, 0)) do
268
+ expect(builder.raw).to eq("<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_abc\" IssueInstant=\"2010-06-01T13:00:00Z\" Version=\"2.0\"><Issuer>http://sportngin.com</Issuer><Subject><NameID Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\">foo@example.com</NameID><SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><SubjectConfirmationData InResponseTo=\"123\" NotOnOrAfter=\"2010-06-01T13:03:00Z\" Recipient=\"http://saml.acs.url\"></SubjectConfirmationData></SubjectConfirmation></Subject><Conditions NotBefore=\"2010-06-01T12:59:55Z\" NotOnOrAfter=\"2010-06-01T16:00:00Z\"><AudienceRestriction><Audience>http://example.com</Audience></AudienceRestriction></Conditions><AuthnStatement AuthnInstant=\"2010-06-01T13:00:00Z\" SessionIndex=\"_abc\"><AuthnContext><AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef></AuthnContext></AuthnStatement><AttributeStatement><Attribute Name=\"GivenName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" FriendlyName=\"GivenName\"><AttributeValue>George</AttributeValue></Attribute><Attribute Name=\"SurName\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" FriendlyName=\"SurName\"><AttributeValue>Washington</AttributeValue></Attribute></AttributeStatement></Assertion>")
269
+ end
270
+ end
271
+ end
129
272
  end
130
273
  end
@@ -17,6 +17,7 @@ module SamlIdp
17
17
  it { should respond_to :attributes }
18
18
  it { should respond_to :service_provider }
19
19
  it { should respond_to :session_expiry }
20
+ it { should respond_to :logger }
20
21
 
21
22
  it "has a valid x509_certificate" do
22
23
  expect(subject.x509_certificate).to eq(Default::X509_CERTIFICATE)
@@ -1,7 +1,10 @@
1
1
  require 'spec_helper'
2
2
  module SamlIdp
3
3
  describe Request do
4
- let(:raw_authn_request) { "<samlp:AuthnRequest AssertionConsumerServiceURL='http://localhost:3000/saml/consume' Destination='http://localhost:1337/saml/auth' ID='_af43d1a0-e111-0130-661a-3c0754403fdb' IssueInstant='2013-08-06T22:01:35Z' Version='2.0' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol'><saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>localhost:3000</saml:Issuer><samlp:NameIDPolicy AllowCreate='true' Format='urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol'/><samlp:RequestedAuthnContext Comparison='exact'><saml:AuthnContextClassRef xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>" }
4
+ let(:issuer) { 'localhost:3000' }
5
+ let(:raw_authn_request) do
6
+ "<samlp:AuthnRequest AssertionConsumerServiceURL='http://localhost:3000/saml/consume' Destination='http://localhost:1337/saml/auth' ID='_af43d1a0-e111-0130-661a-3c0754403fdb' IssueInstant='2013-08-06T22:01:35Z' Version='2.0' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol'><saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>#{issuer}</saml:Issuer><samlp:NameIDPolicy AllowCreate='true' Format='urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol'/><samlp:RequestedAuthnContext Comparison='exact'><saml:AuthnContextClassRef xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></samlp:RequestedAuthnContext></samlp:AuthnRequest>"
7
+ end
5
8
 
6
9
  describe "deflated request" do
7
10
  let(:deflated_request) { Base64.encode64(Zlib::Deflate.deflate(raw_authn_request, 9)[2..-5]) }
@@ -57,16 +60,47 @@ module SamlIdp
57
60
  expect(subject.request['ID']).to eq(subject.request_id)
58
61
  end
59
62
 
60
- it "has a valid authn context" do
61
- expect(subject.requested_authn_context).to eq("urn:oasis:names:tc:SAML:2.0:ac:classes:Password")
63
+ it 'has a valid authn context' do
64
+ expect(subject.requested_authn_context).to eq('urn:oasis:names:tc:SAML:2.0:ac:classes:Password')
62
65
  end
63
66
 
64
- it "does not permit empty issuer" do
65
- raw_req = raw_authn_request.gsub('localhost:3000', '')
66
- authn_request = described_class.new raw_req
67
- expect(authn_request.issuer).to_not eq('')
68
- expect(authn_request.issuer).to be_nil
69
- expect(authn_request.valid?).to eq(false)
67
+ context 'the issuer is empty' do
68
+ let(:issuer) { nil }
69
+ let(:logger) { ->(msg) { puts msg } }
70
+
71
+ before do
72
+ allow(SamlIdp.config).to receive(:logger).and_return(logger)
73
+ end
74
+
75
+ it 'is invalid' do
76
+ expect(subject.issuer).to_not eq('')
77
+ expect(subject.issuer).to be_nil
78
+ expect(subject.valid?).to eq(false)
79
+ end
80
+
81
+ context 'a Ruby Logger is configured' do
82
+ let(:logger) { Logger.new($stdout) }
83
+
84
+ before do
85
+ allow(logger).to receive(:info)
86
+ end
87
+
88
+ it 'logs an error message' do
89
+ expect(subject.valid?).to be false
90
+ expect(logger).to have_received(:info).with('Unable to find service provider for issuer ')
91
+ end
92
+ end
93
+
94
+ context 'a logger lambda is configured' do
95
+ let(:logger) { double }
96
+
97
+ before { allow(logger).to receive(:call) }
98
+
99
+ it 'logs an error message' do
100
+ expect(subject.valid?).to be false
101
+ expect(logger).to have_received(:call).with('Unable to find service provider for issuer ')
102
+ end
103
+ end
70
104
  end
71
105
  end
72
106
 
@@ -26,6 +26,8 @@ module SamlIdp
26
26
  end
27
27
  let(:signed_response_opts) { true }
28
28
  let(:unsigned_response_opts) { false }
29
+ let(:signed_assertion_opts) { true }
30
+ let(:compress_opts) { false }
29
31
  let(:subject_encrypted) { described_class.new(reference_id,
30
32
  response_id,
31
33
  issuer_uri,
@@ -38,7 +40,11 @@ module SamlIdp
38
40
  expiry,
39
41
  encryption_opts,
40
42
  session_expiry,
41
- unsigned_response_opts
43
+ nil,
44
+ nil,
45
+ unsigned_response_opts,
46
+ signed_assertion_opts,
47
+ compress_opts
42
48
  )
43
49
  }
44
50
 
@@ -54,7 +60,11 @@ module SamlIdp
54
60
  expiry,
55
61
  nil,
56
62
  session_expiry,
57
- signed_response_opts
63
+ nil,
64
+ nil,
65
+ signed_response_opts,
66
+ signed_assertion_opts,
67
+ compress_opts
58
68
  )
59
69
  }
60
70
 
@@ -70,15 +80,97 @@ module SamlIdp
70
80
  expect(subject.build).to be_present
71
81
  end
72
82
 
73
- it "builds encrypted" do
74
- expect(subject_encrypted.build).to_not match(audience_uri)
75
- encoded_xml = subject_encrypted.build
76
- resp_settings = saml_settings(saml_acs_url)
77
- resp_settings.private_key = Default::SECRET_KEY
78
- resp_settings.issuer = audience_uri
79
- saml_resp = OneLogin::RubySaml::Response.new(encoded_xml, settings: resp_settings)
80
- saml_resp.soft = false
81
- expect(saml_resp.is_valid?).to eq(true)
83
+ context "encrypted" do
84
+ it "builds encrypted" do
85
+ expect(subject_encrypted.build).to_not match(audience_uri)
86
+ encoded_xml = subject_encrypted.build
87
+ resp_settings = saml_settings(saml_acs_url)
88
+ resp_settings.private_key = Default::SECRET_KEY
89
+ resp_settings.issuer = audience_uri
90
+ saml_resp = OneLogin::RubySaml::Response.new(encoded_xml, settings: resp_settings)
91
+ saml_resp.soft = false
92
+ expect(saml_resp.is_valid?).to eq(true)
93
+ end
94
+ end
95
+
96
+ context "signed response" do
97
+ let(:resp_settings) do
98
+ resp_settings = saml_settings(saml_acs_url)
99
+ resp_settings.private_key = Default::SECRET_KEY
100
+ resp_settings.issuer = audience_uri
101
+ resp_settings
102
+ end
103
+
104
+ it "will build signed valid response" do
105
+ expect { subject.build }.not_to raise_error
106
+ signed_encoded_xml = subject.build
107
+ saml_resp = OneLogin::RubySaml::Response.new(signed_encoded_xml, settings: resp_settings)
108
+ expect(
109
+ Nokogiri::XML(saml_resp.response).at_xpath(
110
+ "//p:Response//ds:Signature",
111
+ {
112
+ "p" => "urn:oasis:names:tc:SAML:2.0:protocol",
113
+ "ds" => "http://www.w3.org/2000/09/xmldsig#"
114
+ }
115
+ )).to be_present
116
+ expect(saml_resp.send(:validate_signature)).to eq(true)
117
+ expect(saml_resp.is_valid?).to eq(true)
118
+ end
119
+
120
+ context "when signed_assertion_opts is true" do
121
+ it "builds a signed assertion" do
122
+ expect { subject.build }.not_to raise_error
123
+ signed_encoded_xml = subject.build
124
+ saml_resp = OneLogin::RubySaml::Response.new(signed_encoded_xml, settings: resp_settings)
125
+ expect(
126
+ Nokogiri::XML(saml_resp.response).at_xpath(
127
+ "//p:Response//a:Assertion//ds:Signature",
128
+ {
129
+ "p" => "urn:oasis:names:tc:SAML:2.0:protocol",
130
+ "a" => "urn:oasis:names:tc:SAML:2.0:assertion",
131
+ "ds" => "http://www.w3.org/2000/09/xmldsig#"
132
+ }
133
+ )).to be_present
134
+ end
135
+ end
136
+
137
+ context "when signed_assertion_opts is false" do
138
+ let(:signed_assertion_opts) { false }
139
+
140
+ it "builds a raw assertion" do
141
+ expect { subject.build }.not_to raise_error
142
+ signed_encoded_xml = subject.build
143
+ saml_resp = OneLogin::RubySaml::Response.new(signed_encoded_xml, settings: resp_settings)
144
+ expect(
145
+ Nokogiri::XML(saml_resp.response).at_xpath(
146
+ "//p:Response//a:Assertion",
147
+ {
148
+ "p" => "urn:oasis:names:tc:SAML:2.0:protocol",
149
+ "a" => "urn:oasis:names:tc:SAML:2.0:assertion"
150
+ }
151
+ )).to be_present
152
+
153
+ expect(
154
+ Nokogiri::XML(saml_resp.response).at_xpath(
155
+ "//p:Response//Assertion//ds:Signature",
156
+ {
157
+ "p" => "urn:oasis:names:tc:SAML:2.0:protocol",
158
+ "ds" => "http://www.w3.org/2000/09/xmldsig#"
159
+ }
160
+ )).to_not be_present
161
+ end
162
+ end
163
+
164
+ context "when compress opts is true" do
165
+ let(:compress_opts) { true }
166
+ it "will build a compressed valid response" do
167
+ expect { subject.build }.not_to raise_error
168
+ compressed_signed_encoded_xml = subject.build
169
+ saml_resp = OneLogin::RubySaml::Response.new(compressed_signed_encoded_xml, settings: resp_settings)
170
+ expect(saml_resp.send(:validate_signature)).to eq(true)
171
+ expect(saml_resp.is_valid?).to eq(true)
172
+ end
173
+ end
82
174
  end
83
175
 
84
176
  it "will build signed valid response" do
@@ -2,11 +2,7 @@ class SamlController < ApplicationController
2
2
 
3
3
  def consume
4
4
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse])
5
- if Gem::Requirement.new('< 4.1') =~ Gem::Version.new(Rails.version)
6
- render :text => response.name_id
7
- else
8
- render :plain => response.name_id
9
- end
5
+ render :plain => response.name_id
10
6
  end
11
7
 
12
8
  end
@@ -1,9 +1,61 @@
1
- class SamlIdpController < SamlIdp::IdpController
1
+ class SamlIdpController < ApplicationController
2
+ include SamlIdp::Controller
3
+
4
+ if Rails::VERSION::MAJOR >= 4
5
+ before_action :add_view_path, only: [:new, :create, :logout]
6
+ before_action :validate_saml_request, only: [:new, :create, :logout]
7
+ else
8
+ before_filter :add_view_path, only: [:new, :create, :logout]
9
+ before_filter :validate_saml_request, only: [:new, :create, :logout]
10
+ end
11
+
12
+ def new
13
+ render template: "saml_idp/idp/new"
14
+ end
15
+
16
+ def show
17
+ render xml: SamlIdp.metadata.signed
18
+ end
19
+
20
+ def create
21
+ unless params[:email].blank? && params[:password].blank?
22
+ person = idp_authenticate(params[:email], params[:password])
23
+ if person.nil?
24
+ @saml_idp_fail_msg = "Incorrect email or password."
25
+ else
26
+ @saml_response = idp_make_saml_response(person)
27
+ render :template => "saml_idp/idp/saml_post", :layout => false
28
+ return
29
+ end
30
+ end
31
+ render :template => "saml_idp/idp/new"
32
+ end
33
+
34
+ def logout
35
+ idp_logout
36
+ @saml_response = idp_make_saml_response(nil)
37
+ render :template => "saml_idp/idp/saml_post", :layout => false
38
+ end
39
+
40
+ def idp_logout
41
+ raise NotImplementedError
42
+ end
43
+ private :idp_logout
44
+
2
45
  def idp_authenticate(email, password)
3
46
  { :email => email }
4
47
  end
48
+ protected :idp_authenticate
5
49
 
6
- def idp_make_saml_response(user)
7
- encode_response(user[:email])
50
+ def idp_make_saml_response(person)
51
+ encode_response(person[:email])
8
52
  end
53
+ protected :idp_make_saml_response
54
+
55
+ private
56
+
57
+ def add_view_path
58
+ prepend_view_path("app/views")
59
+ end
60
+
9
61
  end
@@ -1,22 +1,18 @@
1
1
  <% if @saml_idp_fail_msg %>
2
2
  <div id="saml_idp_fail_msg" class="flash error"><%= @saml_idp_fail_msg %></div>
3
3
  <% end %>
4
-
5
4
  <%= form_tag do %>
6
5
  <%= hidden_field_tag("SAMLRequest", params[:SAMLRequest]) %>
7
6
  <%= hidden_field_tag("RelayState", params[:RelayState]) %>
8
-
9
7
  <p>
10
8
  <%= label_tag :email %>
11
9
  <%= email_field_tag :email, params[:email], :autocapitalize => "off", :autocorrect => "off", :autofocus => "autofocus", :spellcheck => "false", :size => 30, :class => "email_pwd txt" %>
12
10
  </p>
13
-
14
11
  <p>
15
12
  <%= label_tag :password %>
16
13
  <%= password_field_tag :password, params[:password], :autocapitalize => "off", :autocorrect => "off", :spellcheck => "false", :size => 30, :class => "email_pwd txt" %>
17
14
  </p>
18
-
19
15
  <p>
20
16
  <%= submit_tag "Sign in", :class => "button big blueish" %>
21
17
  </p>
22
- <% end %>
18
+ <% end %>
@@ -11,4 +11,4 @@
11
11
  <%= submit_tag "Submit" %>
12
12
  <% end %>
13
13
  </body>
14
- </html>
14
+ </html>
@@ -18,6 +18,7 @@ module RailsApp
18
18
 
19
19
  # Custom directories with classes and modules you want to be autoloadable.
20
20
  # config.autoload_paths += %W(#{config.root}/extras)
21
+ config.autoload_paths += %w[app/controllers]
21
22
 
22
23
  # Only load the plugins named here, in the order given (default is alphabetical).
23
24
  # :all can be used as a placeholder for all plugins not explicitly named.
@@ -3,4 +3,4 @@ require 'rubygems'
3
3
  # Set up gems listed in the Gemfile.
4
4
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5
5
 
6
- require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
6
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
@@ -29,4 +29,6 @@ RailsApp::Application.configure do
29
29
  # Log the query plan for queries taking more than this (works
30
30
  # with SQLite, MySQL, and PostgreSQL)
31
31
  #config.active_record.auto_explain_threshold_in_seconds = 0.5
32
+
33
+ config.hosts << "foo.example.com" if config.respond_to?(:hosts)
32
34
  end
data/spec/spec_helper.rb CHANGED
@@ -67,4 +67,4 @@ end
67
67
  SamlIdp::Default::SERVICE_PROVIDER[:metadata_url] = 'https://example.com/meta'
68
68
  SamlIdp::Default::SERVICE_PROVIDER[:response_hosts] = ['foo.example.com']
69
69
  SamlIdp::Default::SERVICE_PROVIDER[:assertion_consumer_logout_service_url] = 'https://foo.example.com/saml/logout'
70
- Capybara.default_host = "https://app.example.com"
70
+ Capybara.default_host = "https://foo.example.com"