Skip to content

Commit b0b79f1

Browse files
author
Rudolf Vriend
committed
Added support for SP ACS metadata publishing.
Fixed broken tests.
1 parent 5c31a8d commit b0b79f1

7 files changed

Lines changed: 98 additions & 10 deletions

File tree

Gemfile.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
omniauth-saml (0.9.1)
4+
omniauth-saml (0.9.3.dev)
55
omniauth (~> 1.0)
66
uuid (~> 2.3)
77
xmlcanonicalizer (= 0.1.1)
@@ -18,11 +18,11 @@ GEM
1818
guard-rspec (0.6.0)
1919
guard (>= 0.10.0)
2020
hashie (1.2.0)
21-
macaddr (1.5.0)
22-
systemu (>= 2.4.0)
21+
macaddr (1.6.0)
22+
systemu (~> 2.2.0)
2323
method_source (0.7.1)
2424
multi_json (1.1.0)
25-
omniauth (1.0.3)
25+
omniauth (1.1.0)
2626
hashie (~> 1.2)
2727
rack
2828
pry (0.9.8.4)
@@ -45,7 +45,7 @@ GEM
4545
simplecov-html (~> 0.5.3)
4646
simplecov-html (0.5.3)
4747
slop (2.4.4)
48-
systemu (2.4.2)
48+
systemu (2.2.0)
4949
thor (0.14.6)
5050
uuid (2.3.5)
5151
macaddr (~> 1.0)

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,16 @@ Rails.application.config.middleware.use OmniAuth::Builder do
4646
end
4747
```
4848

49+
## Metadata
50+
51+
To ease the configuration of the SAML SP on IdP side, the required SAML ACS metadata that is needed for
52+
the IdP configuration can be retrieved from 'http://yourhost.com/auth/saml/metdata'.
53+
Just give this URL to your IdP administrator and he'll be happy..
54+
4955
## Options
5056

5157
* `:assertion_consumer_service_url` - The URL at which the SAML assertion should be
52-
received. With OmniAuth this is typically `http://example.com/auth/callback`.
58+
received. With OmniAuth this is typically `http://example.com/auth/saml/callback`.
5359
**Required**.
5460

5561
* `:issuer` - The name of your application. Some identity providers might need this

lib/omniauth-saml/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module OmniAuth
22
module SAML
3-
VERSION = "0.9.2"
3+
VERSION = "0.9.3.dev"
44
end
55
end

lib/omniauth/strategies/saml.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class SAML
88
autoload :AuthResponse, 'omniauth/strategies/saml/auth_response'
99
autoload :ValidationError, 'omniauth/strategies/saml/validation_error'
1010
autoload :XMLSecurity, 'omniauth/strategies/saml/xml_security'
11+
autoload :MetadataResponse, 'omniauth/strategies/saml/metadata_response'
1112

1213
option :name_identifier_format, "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
1314

@@ -24,10 +25,19 @@ def callback_phase
2425
@name_id = response.name_id
2526
@attributes = response.attributes
2627

27-
return fail!(:invalid_ticket, 'Invalid SAML Ticket') if @name_id.nil? || @name_id.empty? || !response.valid?
28+
return fail!(:invalid_ticket) if @name_id.nil? || @name_id.empty? || !response.valid?
2829
super
2930
rescue ArgumentError => e
30-
fail!(:invalid_ticket, 'Invalid SAML Response')
31+
fail!(:invalid_ticket, e)
32+
end
33+
end
34+
35+
def other_phase
36+
if on_path?("#{request_path}/metadata")
37+
response = OmniAuth::Strategies::SAML::MetadataResponse.new
38+
Rack::Response.new(response.create(options), 200, { "Content-Type" => "application/xml" })
39+
else
40+
call_app!
3141
end
3242
end
3343

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module OmniAuth
2+
module Strategies
3+
class SAML
4+
class MetadataResponse
5+
def create(settings, params = { })
6+
response =
7+
"<?xml version='1.0'?>\n" +
8+
"<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"#{settings[:issuer]}\">\n" +
9+
"<md:SPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n"
10+
unless settings[:name_identifier_format].nil?
11+
response << "<md:NameIDFormat>#{settings[:name_identifier_format]}</md:NameIDFormat>\n"
12+
end
13+
response <<
14+
"<md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"#{settings[:assertion_consumer_service_url]}\"/>\n" +
15+
"</md:SPSSODescriptor>\n" +
16+
"</md:EntityDescriptor>"
17+
end
18+
end
19+
end
20+
end
21+
end
22+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
require 'spec_helper'
2+
3+
describe OmniAuth::Strategies::SAML::MetadataResponse do
4+
describe :create do
5+
let(:metadata) 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+
20+
describe "the saml SP metadata" do
21+
subject { metadata }
22+
23+
let(:xml) { REXML::Document.new(metadata) }
24+
25+
it "should contain the issuer" do
26+
REXML::XPath.first(xml, '//md:EntityDescriptor').attributes['entityID'].should == 'This is an issuer'
27+
end
28+
29+
it "should contain the callback url in the settings" do
30+
REXML::XPath.first(xml, '//md:AssertionConsumerService').attributes['Location'].should == 'http://example.com/auth/saml/callback'
31+
end
32+
33+
it "should contain the name identifier format" do
34+
REXML::XPath.first(xml, '//md:NameIDFormat').text.should == 'Some Policy'
35+
end
36+
37+
end
38+
end
39+
end

spec/omniauth/strategies/saml_spec.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
RSpec::Matchers.define :fail_with do |message|
44
match do |actual|
5-
actual.redirect? && actual.location == "/auth/failure?message=#{message}"
5+
actual.redirect? && actual.location == "/auth/failure?message=#{message}&strategy=saml"
66
end
77
end
88

@@ -130,4 +130,15 @@ def post_xml(xml=:example_response)
130130
it { should fail_with(:invalid_ticket) }
131131
end
132132
end
133+
134+
describe 'GET /auth/saml/metadata' do
135+
before do
136+
get '/auth/saml/metadata'
137+
end
138+
139+
it 'should get SP metadata page' do
140+
last_response.status.should == 200
141+
last_response.header["Content-Type"].should == "application/xml"
142+
end
143+
end
133144
end

0 commit comments

Comments
 (0)