saml 0.1
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.
- 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
|