saml 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +6 -0
- data/README.md +71 -0
- data/lib/saml.rb +30 -0
- data/lib/saml/bindings.rb +17 -0
- data/lib/saml/bindings/http_post.rb +18 -0
- data/lib/saml/bindings/http_redirect.rb +72 -0
- data/lib/saml/core/assertion.rb +45 -0
- data/lib/saml/core/attribute.rb +25 -0
- data/lib/saml/core/attribute_statement.rb +20 -0
- data/lib/saml/core/authn_request.rb +15 -0
- data/lib/saml/core/authn_statement.rb +23 -0
- data/lib/saml/core/document.rb +25 -0
- data/lib/saml/core/logout_request.rb +24 -0
- data/lib/saml/core/request_abstract.rb +42 -0
- data/lib/saml/core/response.rb +28 -0
- data/lib/saml/core/status.rb +26 -0
- data/lib/saml/core/status_response.rb +24 -0
- data/lib/saml/core/subject.rb +13 -0
- data/lib/saml/core/xml_namespaces.rb +21 -0
- data/lib/saml/metadata/document.rb +14 -0
- data/lib/saml/metadata/endpoint.rb +22 -0
- data/lib/saml/metadata/entities_descriptor.rb +32 -0
- data/lib/saml/metadata/entity_descriptor.rb +40 -0
- data/lib/saml/metadata/idp_sso_descriptor.rb +25 -0
- data/lib/saml/metadata/indexed_endpoint.rb +19 -0
- data/lib/saml/metadata/key_descriptor.rb +21 -0
- data/lib/saml/metadata/role_descriptor.rb +21 -0
- data/lib/saml/metadata/sp_sso_descriptor.rb +23 -0
- data/lib/saml/metadata/sso_descriptor.rb +21 -0
- data/lib/saml/metadata/xml_namespaces.rb +19 -0
- data/lib/saml/session.rb +22 -0
- data/lib/saml/version.rb +3 -0
- data/saml.gemspec +24 -0
- data/spec/saml/bindings/http_redirect_spec.rb +49 -0
- data/spec/saml/core/assertion_spec.rb +50 -0
- data/spec/saml/core/attribute_spec.rb +36 -0
- data/spec/saml/core/attribute_statement_spec.rb +18 -0
- data/spec/saml/core/authn_request_spec.rb +39 -0
- data/spec/saml/core/authn_statement_spec.rb +17 -0
- data/spec/saml/core/logout_request_spec.rb +36 -0
- data/spec/saml/core/request_abstract_spec.rb +55 -0
- data/spec/saml/core/response_spec.rb +32 -0
- data/spec/saml/core/status_response_spec.rb +49 -0
- data/spec/saml/core/status_spec.rb +27 -0
- data/spec/saml/core/subject_spec.rb +17 -0
- data/spec/saml/metadata/endpoint_spec.rb +17 -0
- data/spec/saml/metadata/entities_descriptor_spec.rb +18 -0
- data/spec/saml/metadata/entity_descriptor_spec.rb +9 -0
- data/spec/saml/metadata/idp_sso_descriptor_spec.rb +10 -0
- data/spec/saml/metadata/indexed_endpoint_spec.rb +20 -0
- data/spec/saml/metadata/sp_sso_descriptor_spec.rb +8 -0
- data/spec/saml/metadata/sso_descriptor_spec.rb +9 -0
- data/spec/spec_helper.rb +20 -0
- metadata +131 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
# HTTP Redirect Binding
|
2
|
+
#
|
3
|
+
# SAML v2.0 Bindings
|
4
|
+
#
|
5
|
+
# Section 3.4
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Bindings
|
14
|
+
describe HTTPRedirect do
|
15
|
+
|
16
|
+
let :endpoint do
|
17
|
+
endpoint = double('Endpoint')
|
18
|
+
endpoint.stub(:location).and_return('')
|
19
|
+
endpoint
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:rake) { double('Rake') }
|
23
|
+
|
24
|
+
describe "#send_request" do
|
25
|
+
it "should base64 and url encode the SAMLRequest query parameter" do
|
26
|
+
sr = Core::AuthnRequest.new
|
27
|
+
rake.should_receive(:redirect).with(/\?SAMLRequest=[A-za-z0-9%]+/)
|
28
|
+
|
29
|
+
subject.build_request(rake, endpoint, sr)
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with relay_state parameter" do
|
33
|
+
let(:saml_request) { double('SAMLRequest').as_null_object }
|
34
|
+
|
35
|
+
it "should accept a relay_state and URL encode it" do
|
36
|
+
rake.should_receive(:redirect).with(/RelayState=A\+relay\+state/)
|
37
|
+
subject.build_request(rake, endpoint, saml_request, 'A relay state')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not accept relay_state longer than 80 bytes" do
|
41
|
+
expect {
|
42
|
+
subject.build_request(rake, endpoint, saml_request, 'x'*81)
|
43
|
+
}.to raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Assertion
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 2.3.3
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require "spec_helper"
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe Assertion do
|
15
|
+
|
16
|
+
describe "#from_xml" do
|
17
|
+
|
18
|
+
def xml(str='')
|
19
|
+
Document.new(<<EOT).root
|
20
|
+
<s:Assertion xmlns:s='urn:oasis:names:tc:SAML:2.0:assertion' ID="1" Version="2.0" IssueInstant="2012-01-01T07:00:00Z">
|
21
|
+
<s:Issuer>Me</s:Issuer>
|
22
|
+
#{str}
|
23
|
+
</s:Assertion>
|
24
|
+
EOT
|
25
|
+
end
|
26
|
+
|
27
|
+
context "Minimal valid XML" do
|
28
|
+
|
29
|
+
subject do
|
30
|
+
Assertion.from_xml(xml)
|
31
|
+
end
|
32
|
+
|
33
|
+
its(:id) { should == "1" }
|
34
|
+
its(:version) { should == "2.0" }
|
35
|
+
its(:issue_instant) { should == "2012-01-01T07:00:00Z" }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "With AttributeStatement" do
|
39
|
+
it do
|
40
|
+
a = Assertion.from_xml(xml('<s:AttributeStatement><s:Attribute Name="Foo"><s:AttributeValue>Bar</s:AttributeValue></s:Attribute></s:AttributeStatement>'))
|
41
|
+
a.attribute_statement.attributes.first.name.should == "Foo"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should fail when required fields are missing"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Attribute
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 2.7.3.1
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe Attribute do
|
15
|
+
|
16
|
+
describe "#from_xml" do
|
17
|
+
|
18
|
+
context "Minimal valid XML" do
|
19
|
+
|
20
|
+
subject do
|
21
|
+
r = Attribute.from_xml(Document.new(<<EOT).root)
|
22
|
+
<s:Attribute xmlns:s='urn:oasis:names:tc:SAML:2.0:assertion' Name="Foo">
|
23
|
+
<s:AttributeValue>Hei</s:AttributeValue>
|
24
|
+
</s:Attribute>
|
25
|
+
EOT
|
26
|
+
end
|
27
|
+
|
28
|
+
its(:name) { should == "Foo" }
|
29
|
+
its(:name_format) { should == "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified" }
|
30
|
+
its(:attribute_values) { subject.first.should =~ /Hei/ }
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# AttributeStatement
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 2.7.3
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require "spec_helper"
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe AttributeStatement do
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# AuthnRequest
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 3.4.1
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe AuthnRequest do
|
15
|
+
|
16
|
+
it "should extend RequestAbstract" do
|
17
|
+
AuthnRequest.new.should be_kind_of(RequestAbstract)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#to_xml" do
|
21
|
+
context "attributes" do
|
22
|
+
subject { AuthnRequest.new.to_xml.root.attributes }
|
23
|
+
it { should include('Version') }
|
24
|
+
it { should include('ID') }
|
25
|
+
it { should include('IssueInstant') }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with Issuer" do
|
29
|
+
it "should have an Issuer element in the xml" do
|
30
|
+
r = AuthnRequest.new
|
31
|
+
r.issuer = "me"
|
32
|
+
xml = r.to_xml.root
|
33
|
+
xml.get_elements('saml:Issuer').first.text.should == "me"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# AuthnStatement
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 2.7.2
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe AuthnStatement do
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# LogoutRequest
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 3.7.1
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe LogoutRequest do
|
15
|
+
|
16
|
+
it "should extend RequestAbstract" do
|
17
|
+
AuthnRequest.new.should be_kind_of(RequestAbstract)
|
18
|
+
end
|
19
|
+
|
20
|
+
%w(NotOnOrAfter Reason BaseID/EncryptedID SessionIndex).each do |attr|
|
21
|
+
it "should not support optional attribute/element #{attr}"
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#to_xml" do
|
25
|
+
subject do
|
26
|
+
r = LogoutRequest.new
|
27
|
+
r.name_id = "test@example.com"
|
28
|
+
r.to_xml.root
|
29
|
+
end
|
30
|
+
|
31
|
+
it { should have(1).elements }
|
32
|
+
its(:name) { should == "LogoutRequest" }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# RequestAbstract
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 3.2.1
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe RequestAbstract do
|
15
|
+
|
16
|
+
it "should have a ID conforming to the xs:ID data type" do
|
17
|
+
subject.id.should match(/[A-Za-z0-9-]+/)
|
18
|
+
end
|
19
|
+
|
20
|
+
its(:version) { should == "2.0" }
|
21
|
+
|
22
|
+
describe "#issue_instant" do
|
23
|
+
it "should have an issue instant formated as %Y-%m-%dT%H:%M:%SZ" do
|
24
|
+
subject.issue_instant.should match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be set to now" do
|
28
|
+
t = double(Time)
|
29
|
+
t.should_receive(:now).and_return(Time.now)
|
30
|
+
RequestAbstract.new(t)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#issuer" do
|
35
|
+
it do
|
36
|
+
subject.issuer = 'test'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have an issuer element in the xml when issuer is set" do
|
40
|
+
subject.issuer = 'test'
|
41
|
+
subject.to_xml.should match_xpath('//saml:Issuer')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not have an issuer element in the xml when issuer is not set" do
|
45
|
+
subject.to_xml.should_not match_xpath('//saml:Issuer')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
%w(Destination Consent Signature Extensions).each do |attr|
|
50
|
+
it "should not support #{attr}"
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Response
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 3.3.3
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe Response do
|
15
|
+
|
16
|
+
it { should be_kind_of(StatusResponse) }
|
17
|
+
|
18
|
+
describe "#from_xml" do
|
19
|
+
|
20
|
+
it do
|
21
|
+
xml = Document.new(<<EOT).root
|
22
|
+
<sp:StatusResponse xmlns:sp='urn:oasis:names:tc:SAML:2.0:protocol' xmlns:s='urn:oasis:names:tc:SAML:2.0:assertion' ID="1" Version="2.0">
|
23
|
+
<sp:Status><sp:StatusCode Value="Jolly good"/></sp:Status>
|
24
|
+
<s:Assertion ID="1" Version="2.0" IssueInstant="right now"></s:Assertion>
|
25
|
+
</sp:StatusResponse>
|
26
|
+
EOT
|
27
|
+
r = Response.from_xml(xml)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# StatusResponse
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 3.2.2
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe StatusResponse do
|
15
|
+
|
16
|
+
#ID [Required]
|
17
|
+
#InResponseTo [Optional]
|
18
|
+
#Version [Required]
|
19
|
+
#IssueInstant [Required]
|
20
|
+
#Destination [Optional]
|
21
|
+
#Consent [Optional]
|
22
|
+
#<saml:Issuer> [Optional]
|
23
|
+
#<ds:Signature> [Optional]
|
24
|
+
#<Extensions> [Optional]
|
25
|
+
#<Status> [Required]
|
26
|
+
|
27
|
+
describe "#from_xml" do
|
28
|
+
|
29
|
+
context "Minimal valid XML" do
|
30
|
+
|
31
|
+
subject do
|
32
|
+
xml = Document.new(<<EOT)
|
33
|
+
<sp:StatusResponse xmlns:sp='urn:oasis:names:tc:SAML:2.0:protocol' ID="1" Version="2.0">
|
34
|
+
<sp:Status><sp:StatusCode Value="Jolly good"/></sp:Status>
|
35
|
+
</sp:StatusResponse>
|
36
|
+
EOT
|
37
|
+
StatusResponse.from_xml(xml.root)
|
38
|
+
end
|
39
|
+
|
40
|
+
its(:id) { should == "1" }
|
41
|
+
its(:version) { should == "2.0" }
|
42
|
+
its(:status) { subject.status_code.should == "Jolly good" }
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should fail when required fields are missing"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Status
|
2
|
+
#
|
3
|
+
# SAML v2.0 Core
|
4
|
+
#
|
5
|
+
# Section 3.2.2.1
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Core
|
14
|
+
describe Status do
|
15
|
+
it "should only allow the following top-level status codes"
|
16
|
+
# urn:oasis:names:tc:SAML:2.0:status:Success
|
17
|
+
# The request succeeded. Additional information MAY be returned in the <StatusMessage> and/or <StatusDetail> elements.
|
18
|
+
# urn:oasis:names:tc:SAML:2.0:status:Requester
|
19
|
+
# The request could not be performed due to an error on the part of the requester.
|
20
|
+
# urn:oasis:names:tc:SAML:2.0:status:Responder
|
21
|
+
# The request could not be performed due to an error on the part of the SAML responder or SAML authority.
|
22
|
+
# urn:oasis:names:tc:SAML:2.0:status:VersionMismatch
|
23
|
+
# The SAML responder could not process the request because the version of the request message was incorrect.
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Status
|
2
|
+
#
|
3
|
+
# SAML v2.0 Metadata
|
4
|
+
#
|
5
|
+
# Section 2.2.2
|
6
|
+
#
|
7
|
+
# http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
module SAML
|
13
|
+
module Metadata
|
14
|
+
describe Endpoint do
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|