libsaml 2.0.5

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.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +91 -0
  4. data/Rakefile +33 -0
  5. data/lib/saml.rb +142 -0
  6. data/lib/saml/artifact.rb +51 -0
  7. data/lib/saml/artifact_resolve.rb +10 -0
  8. data/lib/saml/artifact_response.rb +9 -0
  9. data/lib/saml/assertion.rb +67 -0
  10. data/lib/saml/authn_request.rb +34 -0
  11. data/lib/saml/base.rb +47 -0
  12. data/lib/saml/bindings/http_artifact.rb +44 -0
  13. data/lib/saml/bindings/http_post.rb +29 -0
  14. data/lib/saml/bindings/http_redirect.rb +100 -0
  15. data/lib/saml/bindings/soap.rb +31 -0
  16. data/lib/saml/complex_types/endpoint_type.rb +17 -0
  17. data/lib/saml/complex_types/indexed_endpoint_type.rb +15 -0
  18. data/lib/saml/complex_types/request_abstract_type.rb +57 -0
  19. data/lib/saml/complex_types/sso_descriptor_type.rb +48 -0
  20. data/lib/saml/complex_types/status_response_type.rb +29 -0
  21. data/lib/saml/config.rb +49 -0
  22. data/lib/saml/elements/attribute.rb +24 -0
  23. data/lib/saml/elements/attribute_statement.rb +26 -0
  24. data/lib/saml/elements/audience_restriction.rb +12 -0
  25. data/lib/saml/elements/authn_context.rb +13 -0
  26. data/lib/saml/elements/authn_statement.rb +25 -0
  27. data/lib/saml/elements/conditions.rb +24 -0
  28. data/lib/saml/elements/contact_person.rb +33 -0
  29. data/lib/saml/elements/entities_descriptor.rb +27 -0
  30. data/lib/saml/elements/entity_descriptor.rb +37 -0
  31. data/lib/saml/elements/idp_sso_descriptor.rb +23 -0
  32. data/lib/saml/elements/key_descriptor.rb +34 -0
  33. data/lib/saml/elements/key_descriptor/key_info.rb +30 -0
  34. data/lib/saml/elements/key_descriptor/key_info/x509_data.rb +34 -0
  35. data/lib/saml/elements/name_id.rb +14 -0
  36. data/lib/saml/elements/organization.rb +16 -0
  37. data/lib/saml/elements/requested_authn_context.rb +28 -0
  38. data/lib/saml/elements/signature.rb +33 -0
  39. data/lib/saml/elements/signature/canonicalization_method.rb +19 -0
  40. data/lib/saml/elements/signature/digest_method.rb +19 -0
  41. data/lib/saml/elements/signature/inclusive_namespaces.rb +20 -0
  42. data/lib/saml/elements/signature/key_info.rb +14 -0
  43. data/lib/saml/elements/signature/reference.rb +23 -0
  44. data/lib/saml/elements/signature/signature_method.rb +19 -0
  45. data/lib/saml/elements/signature/signed_info.rb +24 -0
  46. data/lib/saml/elements/signature/transform.rb +19 -0
  47. data/lib/saml/elements/signature/transforms.rb +21 -0
  48. data/lib/saml/elements/sp_sso_descriptor.rb +27 -0
  49. data/lib/saml/elements/status.rb +15 -0
  50. data/lib/saml/elements/status_code.rb +42 -0
  51. data/lib/saml/elements/sub_status_code.rb +14 -0
  52. data/lib/saml/elements/subject.rb +38 -0
  53. data/lib/saml/elements/subject_confirmation.rb +30 -0
  54. data/lib/saml/elements/subject_confirmation_data.rb +23 -0
  55. data/lib/saml/elements/subject_locality.rb +12 -0
  56. data/lib/saml/encoding.rb +35 -0
  57. data/lib/saml/logout_request.rb +10 -0
  58. data/lib/saml/logout_response.rb +11 -0
  59. data/lib/saml/provider.rb +85 -0
  60. data/lib/saml/provider_stores/file.rb +33 -0
  61. data/lib/saml/response.rb +21 -0
  62. data/lib/saml/util.rb +51 -0
  63. data/lib/saml/version.rb +3 -0
  64. data/lib/saml/xml_helpers.rb +34 -0
  65. data/lib/tasks/saml_tasks.rake +4 -0
  66. metadata +195 -0
@@ -0,0 +1,12 @@
1
+ module Saml
2
+ module Elements
3
+ class SubjectLocality
4
+ include Saml::Base
5
+
6
+ tag "SubjectLocality"
7
+ namespace 'saml'
8
+
9
+ attribute :address, String, :tag => "Address"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,35 @@
1
+ require 'zlib'
2
+ require 'base64'
3
+
4
+ module Saml
5
+ class Encoding
6
+
7
+ def self.encode_64 string
8
+ Base64.encode64(string).chomp
9
+ end
10
+
11
+ def self.decode_64 base64_string
12
+ Base64.decode64 base64_string
13
+ end
14
+
15
+ def self.encode_gzip string
16
+ Zlib::Deflate.deflate(string, 9)[2..-5]
17
+ end
18
+
19
+ def self.decode_gzip gzip_binary_string
20
+ # Adding a - sign to MAX_WBITS makes zlib ignore the zlib headers
21
+ inflate(gzip_binary_string, -Zlib::MAX_WBITS)
22
+ rescue ::Zlib::DataError
23
+ inflate(gzip_binary_string) rescue nil
24
+ end
25
+
26
+ def self.inflate gzip_binary_string, max_bits=nil
27
+ zstream = Zlib::Inflate.new(max_bits)
28
+ begin
29
+ zstream.inflate(gzip_binary_string)
30
+ ensure
31
+ zstream.close
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+ module Saml
2
+ class LogoutRequest
3
+ include Saml::ComplexTypes::RequestAbstractType
4
+
5
+ tag "LogoutRequest"
6
+ element :name_id, String, :tag => "NameID", :namespace => 'saml'
7
+
8
+ validates :name_id, :presence => true
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Saml
2
+ class LogoutResponse
3
+ include Saml::ComplexTypes::StatusResponseType
4
+
5
+ tag "LogoutResponse"
6
+
7
+ def partial_logout?
8
+ !success? && status.status_code.partial_logout?
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,85 @@
1
+ module Saml
2
+ module Provider
3
+ extend ActiveSupport::Concern
4
+
5
+ def assertion_consumer_service_url(index = nil)
6
+ find_indexed_service(descriptor.assertion_consumer_services, index)
7
+ end
8
+
9
+ def artifact_resolution_service_url(index = nil)
10
+ find_indexed_service(descriptor.artifact_resolution_services, index)
11
+ end
12
+
13
+ def entity_descriptor
14
+ @entity_descriptor
15
+ end
16
+
17
+ def entity_id
18
+ entity_descriptor.entity_id
19
+ end
20
+
21
+ def certificate(use = "signing")
22
+ key_descriptor = descriptor.key_descriptors.find { |key| key.use == use || key.use == "" }
23
+ key_descriptor.certificate if key_descriptor
24
+ end
25
+
26
+ def private_key
27
+ @private_key
28
+ end
29
+
30
+ def sign(signature_algorithm, data)
31
+ private_key.sign(digest_method(signature_algorithm).new, data)
32
+ end
33
+
34
+ def single_sign_on_service_url(binding)
35
+ find_binding_service(descriptor.single_sign_on_services, binding)
36
+ end
37
+
38
+ def single_logout_service_url(binding)
39
+ find_binding_service(descriptor.single_logout_services, binding)
40
+ end
41
+
42
+ def type
43
+ descriptor.is_a?(Saml::Elements::SPSSODescriptor) ? "service_provider" : "identity_provider"
44
+ end
45
+
46
+ def verify(signature_algorithm, signature, data)
47
+ certificate.public_key.verify(digest_method(signature_algorithm).new, signature, data) rescue nil
48
+ end
49
+
50
+ def authn_requests_signed?
51
+ descriptor.authn_requests_signed
52
+ end
53
+
54
+ private
55
+
56
+ def digest_method(signature_algorithm)
57
+ digest = signature_algorithm && signature_algorithm =~ /sha(.*?)$/i && $1.to_i
58
+ case digest
59
+ when 256 then
60
+ OpenSSL::Digest::SHA256
61
+ else
62
+ OpenSSL::Digest::SHA1
63
+ end
64
+ end
65
+
66
+ # @return [Saml::ComplexTypes::SSODescriptorType]
67
+ def descriptor
68
+ entity_descriptor.sp_sso_descriptor || entity_descriptor.idp_sso_descriptor
69
+ end
70
+
71
+ def find_indexed_service(service_list, index)
72
+ service = if index
73
+ service_list.find { |service| service.index == index }
74
+ else
75
+ service_list.find { |service| service.is_default }
76
+ end
77
+ service.location if service
78
+ end
79
+
80
+ def find_binding_service(service_list, binding)
81
+ service = service_list.find { |service| service.binding == binding }
82
+ service.location if service
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,33 @@
1
+ module Saml
2
+ module ProviderStores
3
+ class File
4
+ class Provider
5
+ include Saml::Provider
6
+ attr_accessor :entity_descriptor, :private_key, :type
7
+
8
+ def initialize(entity_descriptor, private_key, type)
9
+ @entity_descriptor = entity_descriptor
10
+ @private_key = private_key
11
+ @type = type
12
+ end
13
+ end
14
+
15
+ attr_accessor :providers
16
+
17
+ def initialize(metadata_dir = "config/metadata", key_file = "config/ssl/key.pem")
18
+ self.providers = []
19
+ Dir[::File.join(metadata_dir, "*.xml")].each do |file|
20
+ entity_descriptor = Saml::Elements::EntityDescriptor.parse(::File.read(file), single: true)
21
+ private_key = OpenSSL::PKey::RSA.new(::File.read(key_file))
22
+ type = entity_descriptor.sp_sso_descriptor.present? ? "service_provider" : "identity_provider"
23
+
24
+ self.providers << Provider.new(entity_descriptor, private_key, type)
25
+ end
26
+ end
27
+
28
+ def find_by_entity_id(entity_id)
29
+ self.providers.find { |provider| provider.entity_id == entity_id }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module Saml
2
+ class Response
3
+ include Saml::ComplexTypes::StatusResponseType
4
+
5
+ tag "Response"
6
+ has_one :assertion, Saml::Assertion, :tag => "Assertion"
7
+ has_many :assertions, Saml::Assertion, :tag => "Assertion"
8
+
9
+ def authn_failed?
10
+ !success? && status.status_code.authn_failed?
11
+ end
12
+
13
+ def request_denied?
14
+ !success? && status.status_code.request_denied?
15
+ end
16
+
17
+ def no_authn_context?
18
+ !success? && status.status_code.no_authn_context?
19
+ end
20
+ end
21
+ end
data/lib/saml/util.rb ADDED
@@ -0,0 +1,51 @@
1
+ module Saml
2
+ class Util
3
+ class << self
4
+ def parse_params(url)
5
+ query = URI.parse(url).query
6
+ return {} unless query
7
+
8
+ params = {}
9
+ query.split(/[&;]/).each do |pairs|
10
+ key, value = pairs.split('=',2)
11
+ params[key] = value
12
+ end
13
+
14
+ params
15
+ end
16
+
17
+ def post(location, message)
18
+ request = HTTPI::Request.new
19
+
20
+ request.url = location
21
+ request.headers['Content-Type'] = 'text/xml'
22
+ request.body = message
23
+ request.auth.ssl.cert_file = Saml::Config.ssl_certificate_file
24
+ request.auth.ssl.cert_key_file = Saml::Config.ssl_private_key_file
25
+
26
+ HTTPI.post request
27
+ end
28
+
29
+ def sign_xml(message, format = :xml)
30
+ message.add_signature
31
+
32
+ document = Xmldsig::SignedDocument.new(message.send("to_#{format}"))
33
+ document.sign do |data, signature_algorithm|
34
+ message.provider.sign(signature_algorithm, data)
35
+ end
36
+ end
37
+
38
+ def verify_xml(message, raw_body)
39
+ document = Xmldsig::SignedDocument.new(raw_body)
40
+
41
+ signature_valid = document.validate do |signature, data, signature_algorithm|
42
+ message.provider.verify(signature_algorithm, signature, data)
43
+ end
44
+
45
+ raise Saml::Errors::SignatureInvalid.new unless signature_valid
46
+
47
+ message.class.parse(document.signed_nodes.first.to_xml, single: true)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module Saml
2
+ VERSION = "2.0.5"
3
+ end
@@ -0,0 +1,34 @@
1
+ module Saml
2
+ module XMLHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ def to_xml(builder = nil, default_namespace = nil, instruct = true)
6
+ write_xml = builder.nil? ? true : false
7
+ builder ||= Nokogiri::XML::Builder.new
8
+ builder.doc.encoding = "UTF-8"
9
+ result = super(builder, default_namespace)
10
+ if write_xml
11
+ instruct ? result.to_xml : result.doc.root
12
+ else
13
+ result
14
+ end
15
+
16
+ end
17
+
18
+ def to_soap
19
+ builder = Nokogiri::XML::Builder.new
20
+ body = self.to_xml(builder)
21
+
22
+ builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8")
23
+ builder.Envelope(:'xmlns:soapenv' => "http://schemas.xmlsoap.org/soap/envelope/",
24
+ :'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema",
25
+ :'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance") do |xml|
26
+ builder.parent.namespace = builder.parent.namespace_definitions.find { |n| n.prefix == 'soapenv' }
27
+ builder.Body do
28
+ builder.parent.add_child body.doc.root
29
+ end
30
+ end
31
+ builder.to_xml
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :saml do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,195 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: libsaml
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Benoist Claassen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri-happymapper
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.5.7
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.7
55
+ - !ruby/object:Gem::Dependency
56
+ name: xmldsig
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: curb
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: httpi
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Libsaml makes the creation of SAML 2.0 messages easy. The object structure
98
+ is modeled after the SAML Core 2.0 specification from OASIS. Supported bindings
99
+ are HTTP-Post, HTTP-Redirect, HTTP-Artifact and SOAP. Features include XML signing,
100
+ XML verification and a pluggable backend for providers (FileStore backend included).
101
+ email:
102
+ - bclaassen@digidentity.eu
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - lib/saml/artifact.rb
108
+ - lib/saml/artifact_resolve.rb
109
+ - lib/saml/artifact_response.rb
110
+ - lib/saml/assertion.rb
111
+ - lib/saml/authn_request.rb
112
+ - lib/saml/base.rb
113
+ - lib/saml/bindings/http_artifact.rb
114
+ - lib/saml/bindings/http_post.rb
115
+ - lib/saml/bindings/http_redirect.rb
116
+ - lib/saml/bindings/soap.rb
117
+ - lib/saml/complex_types/endpoint_type.rb
118
+ - lib/saml/complex_types/indexed_endpoint_type.rb
119
+ - lib/saml/complex_types/request_abstract_type.rb
120
+ - lib/saml/complex_types/sso_descriptor_type.rb
121
+ - lib/saml/complex_types/status_response_type.rb
122
+ - lib/saml/config.rb
123
+ - lib/saml/elements/attribute.rb
124
+ - lib/saml/elements/attribute_statement.rb
125
+ - lib/saml/elements/audience_restriction.rb
126
+ - lib/saml/elements/authn_context.rb
127
+ - lib/saml/elements/authn_statement.rb
128
+ - lib/saml/elements/conditions.rb
129
+ - lib/saml/elements/contact_person.rb
130
+ - lib/saml/elements/entities_descriptor.rb
131
+ - lib/saml/elements/entity_descriptor.rb
132
+ - lib/saml/elements/idp_sso_descriptor.rb
133
+ - lib/saml/elements/key_descriptor/key_info/x509_data.rb
134
+ - lib/saml/elements/key_descriptor/key_info.rb
135
+ - lib/saml/elements/key_descriptor.rb
136
+ - lib/saml/elements/name_id.rb
137
+ - lib/saml/elements/organization.rb
138
+ - lib/saml/elements/requested_authn_context.rb
139
+ - lib/saml/elements/signature/canonicalization_method.rb
140
+ - lib/saml/elements/signature/digest_method.rb
141
+ - lib/saml/elements/signature/inclusive_namespaces.rb
142
+ - lib/saml/elements/signature/key_info.rb
143
+ - lib/saml/elements/signature/reference.rb
144
+ - lib/saml/elements/signature/signature_method.rb
145
+ - lib/saml/elements/signature/signed_info.rb
146
+ - lib/saml/elements/signature/transform.rb
147
+ - lib/saml/elements/signature/transforms.rb
148
+ - lib/saml/elements/signature.rb
149
+ - lib/saml/elements/sp_sso_descriptor.rb
150
+ - lib/saml/elements/status.rb
151
+ - lib/saml/elements/status_code.rb
152
+ - lib/saml/elements/sub_status_code.rb
153
+ - lib/saml/elements/subject.rb
154
+ - lib/saml/elements/subject_confirmation.rb
155
+ - lib/saml/elements/subject_confirmation_data.rb
156
+ - lib/saml/elements/subject_locality.rb
157
+ - lib/saml/encoding.rb
158
+ - lib/saml/logout_request.rb
159
+ - lib/saml/logout_response.rb
160
+ - lib/saml/provider.rb
161
+ - lib/saml/provider_stores/file.rb
162
+ - lib/saml/response.rb
163
+ - lib/saml/util.rb
164
+ - lib/saml/version.rb
165
+ - lib/saml/xml_helpers.rb
166
+ - lib/saml.rb
167
+ - lib/tasks/saml_tasks.rake
168
+ - MIT-LICENSE
169
+ - Rakefile
170
+ - README.rdoc
171
+ homepage: https://www.digidentity.eu
172
+ licenses:
173
+ - MIT
174
+ metadata: {}
175
+ post_install_message:
176
+ rdoc_options: []
177
+ require_paths:
178
+ - lib
179
+ required_ruby_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ! '>='
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ requirements: []
190
+ rubyforge_project:
191
+ rubygems_version: 2.0.6
192
+ signing_key:
193
+ specification_version: 4
194
+ summary: A gem to easily create SAML 2.0 messages.
195
+ test_files: []