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.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +91 -0
- data/Rakefile +33 -0
- data/lib/saml.rb +142 -0
- data/lib/saml/artifact.rb +51 -0
- data/lib/saml/artifact_resolve.rb +10 -0
- data/lib/saml/artifact_response.rb +9 -0
- data/lib/saml/assertion.rb +67 -0
- data/lib/saml/authn_request.rb +34 -0
- data/lib/saml/base.rb +47 -0
- data/lib/saml/bindings/http_artifact.rb +44 -0
- data/lib/saml/bindings/http_post.rb +29 -0
- data/lib/saml/bindings/http_redirect.rb +100 -0
- data/lib/saml/bindings/soap.rb +31 -0
- data/lib/saml/complex_types/endpoint_type.rb +17 -0
- data/lib/saml/complex_types/indexed_endpoint_type.rb +15 -0
- data/lib/saml/complex_types/request_abstract_type.rb +57 -0
- data/lib/saml/complex_types/sso_descriptor_type.rb +48 -0
- data/lib/saml/complex_types/status_response_type.rb +29 -0
- data/lib/saml/config.rb +49 -0
- data/lib/saml/elements/attribute.rb +24 -0
- data/lib/saml/elements/attribute_statement.rb +26 -0
- data/lib/saml/elements/audience_restriction.rb +12 -0
- data/lib/saml/elements/authn_context.rb +13 -0
- data/lib/saml/elements/authn_statement.rb +25 -0
- data/lib/saml/elements/conditions.rb +24 -0
- data/lib/saml/elements/contact_person.rb +33 -0
- data/lib/saml/elements/entities_descriptor.rb +27 -0
- data/lib/saml/elements/entity_descriptor.rb +37 -0
- data/lib/saml/elements/idp_sso_descriptor.rb +23 -0
- data/lib/saml/elements/key_descriptor.rb +34 -0
- data/lib/saml/elements/key_descriptor/key_info.rb +30 -0
- data/lib/saml/elements/key_descriptor/key_info/x509_data.rb +34 -0
- data/lib/saml/elements/name_id.rb +14 -0
- data/lib/saml/elements/organization.rb +16 -0
- data/lib/saml/elements/requested_authn_context.rb +28 -0
- data/lib/saml/elements/signature.rb +33 -0
- data/lib/saml/elements/signature/canonicalization_method.rb +19 -0
- data/lib/saml/elements/signature/digest_method.rb +19 -0
- data/lib/saml/elements/signature/inclusive_namespaces.rb +20 -0
- data/lib/saml/elements/signature/key_info.rb +14 -0
- data/lib/saml/elements/signature/reference.rb +23 -0
- data/lib/saml/elements/signature/signature_method.rb +19 -0
- data/lib/saml/elements/signature/signed_info.rb +24 -0
- data/lib/saml/elements/signature/transform.rb +19 -0
- data/lib/saml/elements/signature/transforms.rb +21 -0
- data/lib/saml/elements/sp_sso_descriptor.rb +27 -0
- data/lib/saml/elements/status.rb +15 -0
- data/lib/saml/elements/status_code.rb +42 -0
- data/lib/saml/elements/sub_status_code.rb +14 -0
- data/lib/saml/elements/subject.rb +38 -0
- data/lib/saml/elements/subject_confirmation.rb +30 -0
- data/lib/saml/elements/subject_confirmation_data.rb +23 -0
- data/lib/saml/elements/subject_locality.rb +12 -0
- data/lib/saml/encoding.rb +35 -0
- data/lib/saml/logout_request.rb +10 -0
- data/lib/saml/logout_response.rb +11 -0
- data/lib/saml/provider.rb +85 -0
- data/lib/saml/provider_stores/file.rb +33 -0
- data/lib/saml/response.rb +21 -0
- data/lib/saml/util.rb +51 -0
- data/lib/saml/version.rb +3 -0
- data/lib/saml/xml_helpers.rb +34 -0
- data/lib/tasks/saml_tasks.rake +4 -0
- metadata +195 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NzdjMGJhZTcxYTc2MTUxMmNlMTdhNzEzNDlmOGI4ODEyZDQxMTBhNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTY3YjkxMDI3OTQyNjUyYTViZDc5MTAxZTBjYzM4ZjllOGVkYzM0Mg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDcwYjA1YTZmZDcyZGVhZmVmNDlhMjhmMWQ1ZDRiNGIzNzU0YzIzMTE2Y2U5
|
10
|
+
ZmUxYmUyYTBkNGVkN2ZhMTZlYjNjZjgzNjE2ZmZmOTIwMzIyNzA0MWQxMjdh
|
11
|
+
M2FkY2NjODEyYjdkMTIwNzY5NzVmYmI3MmJhZTIyMzdhZTM2MTE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODdjOTk5ZjJhZWZjMmFiN2M3NWFlYzA4N2Y3Njk2OWUxYTk3YzFmMGZjNTZj
|
14
|
+
Y2YwYzcwYzI2YWM0YzNhZjc4NzE4Y2UzYTRjZjBhMzZmNjQ4NjgzNWY4NDU2
|
15
|
+
Y2ZjODYxNWE4YTBkMDhmNjY5ZDJjZjQ1NGIzN2E2NzM4ZDJhNWY=
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 Digidentity
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
{<img src="https://travis-ci.org/digidentity/libsaml.png?branch=master" alt="Build Status" />}[https://travis-ci.org/digidentity/libsaml]
|
2
|
+
= libsaml
|
3
|
+
Libsaml is a Ruby gem to easily create SAML 2.0 messages. This gem was written because other SAML gems were missing functionality such as XML signing.
|
4
|
+
|
5
|
+
Libsaml's features include:
|
6
|
+
- Bindings: HTTP-Post, HTTP-Redirect, HTTP-Artifact, SOAP
|
7
|
+
- XML signing and verification
|
8
|
+
- Pluggable backend for providers (FileStore backend included)
|
9
|
+
|
10
|
+
Copyright Digidentity BV, released under the MIT license. This gem was written by Benoist Claassen.
|
11
|
+
|
12
|
+
= Installation
|
13
|
+
|
14
|
+
Place in your Gemfile:
|
15
|
+
gem 'libsaml', require: 'saml'
|
16
|
+
|
17
|
+
= Usage
|
18
|
+
Below follows how to configure the SAML gem in a service provider.
|
19
|
+
|
20
|
+
Store the private key in:
|
21
|
+
config/ssl/key.pem
|
22
|
+
|
23
|
+
Store the public key of the identity provider in:
|
24
|
+
config/ssl/trust-federate.cert
|
25
|
+
|
26
|
+
Add the Identity Provider web container configuration file to config/metadata/service_provider.xml.
|
27
|
+
This contains an encoded version of the public key, generate this in the ruby console by typing:
|
28
|
+
irb
|
29
|
+
require 'openssl'
|
30
|
+
require 'base64'
|
31
|
+
pem = File.open("config/ssl/trust-federate.cert").read
|
32
|
+
cert = OpenSSL::X509::Certificate.new(pem)
|
33
|
+
output = Base64.encode64(cert.to_der).gsub("\n", "")
|
34
|
+
|
35
|
+
Add the Service Provider configuration file to config/metadata/service_provider.xml:
|
36
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
37
|
+
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" ID="_052c51476c9560a429e1171e8c9528b96b69fb57" entityID="my:very:original:entityid">
|
38
|
+
<md:SPSSODescriptor>
|
39
|
+
<md:KeyDescriptor use="signing">
|
40
|
+
<ds:KeyInfo>
|
41
|
+
<ds:X509Data>
|
42
|
+
<ds:X509Certificate>SAME_KEY_AS_GENERATED_IN_THE_CONSOLE_BEFORE</ds:X509Certificate>
|
43
|
+
</ds:X509Data>
|
44
|
+
</ds:KeyInfo>
|
45
|
+
</md:KeyDescriptor>
|
46
|
+
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Post" index="0" Location="http://localhost:3000/saml/receive_response" isDefault="true"/>
|
47
|
+
</md:SPSSODescriptor>
|
48
|
+
</md:EntityDescriptor>
|
49
|
+
|
50
|
+
Set up an intializer in config/initializers/saml_config.rb:
|
51
|
+
Saml.setup do |config|
|
52
|
+
config.entity_id = "my:very:original:entityid"
|
53
|
+
config.provider_store = Saml::ProviderStore::File.new("config/metadata", "config/ssl/key.pem")
|
54
|
+
# config.provider_store = SamlProvider
|
55
|
+
end
|
56
|
+
|
57
|
+
By default this will use a SamlProvider model that uses the filestore, if you want a database driven model comment out the #provider_store function in the initializer and make a model that defines #find_by_entity_id:
|
58
|
+
class SamlProvider < ActiveRecord::Base
|
59
|
+
include Saml::Provider
|
60
|
+
|
61
|
+
def self.find_by_entity_id(entity_id)
|
62
|
+
where(entity_id: entity_id).first!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
Now you can make a SAML controller in app/controllers/saml_controller.rb:
|
68
|
+
class SamlController < ApplicationController
|
69
|
+
def request_authentication
|
70
|
+
provider = Saml.provider("my:very:original:entityid")
|
71
|
+
destination = provider.single_sign_on_service_url(Saml::ProtocolBindings::HTTP_POST)
|
72
|
+
|
73
|
+
authn_request = Saml::AuthnRequest.new(:destination => destination)
|
74
|
+
|
75
|
+
@saml_attributes = Saml::Bindings::HTTPPost.create_form_attributes(authn_request)
|
76
|
+
|
77
|
+
render text: @saml_attributes.to_yaml
|
78
|
+
end
|
79
|
+
|
80
|
+
def receive_response
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Don't forget to define the routes in config/routes.rb:
|
85
|
+
get "/saml/request_authentication" => "saml#request_authentication"
|
86
|
+
get "/saml/receive_response" => "saml#receive_response"
|
87
|
+
|
88
|
+
= Contributing
|
89
|
+
- Fork the project
|
90
|
+
- Contribute your changes. Please make sure your changes are properly documented and covered by tests.
|
91
|
+
- Send a pull request
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'Saml'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
require "rspec/core/rake_task"
|
24
|
+
|
25
|
+
RSpec::Core::RakeTask.new(:core) do |spec|
|
26
|
+
spec.rspec_opts = ['--backtrace']
|
27
|
+
end
|
28
|
+
|
29
|
+
task :default => [:core]
|
30
|
+
|
31
|
+
|
32
|
+
Bundler::GemHelper.install_tasks
|
33
|
+
|
data/lib/saml.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'active_model'
|
3
|
+
require 'saml/base'
|
4
|
+
require 'saml/xml_helpers'
|
5
|
+
require 'saml/encoding'
|
6
|
+
require 'saml/util'
|
7
|
+
require 'xmldsig'
|
8
|
+
require 'httpi'
|
9
|
+
|
10
|
+
module Saml
|
11
|
+
MD_NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:metadata'
|
12
|
+
SAML_NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:assertion'
|
13
|
+
SAMLP_NAMESPACE = 'urn:oasis:names:tc:SAML:2.0:protocol'
|
14
|
+
XML_DSIG_NAMESPACE = 'http://www.w3.org/2000/09/xmldsig#'
|
15
|
+
SAML_VERSION = '2.0'
|
16
|
+
|
17
|
+
module Errors
|
18
|
+
class SamlError < StandardError;
|
19
|
+
end
|
20
|
+
|
21
|
+
class SignatureInvalid < SamlError;
|
22
|
+
end
|
23
|
+
class InvalidProvider < SamlError;
|
24
|
+
end
|
25
|
+
class UnparseableMessage < SamlError;
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module TopLevelCodes
|
30
|
+
SUCCESS = 'urn:oasis:names:tc:SAML:2.0:status:Success'
|
31
|
+
REQUESTER = 'urn:oasis:names:tc:SAML:2.0:status:Requester'
|
32
|
+
RESPONDER = 'urn:oasis:names:tc:SAML:2.0:status:Responder'
|
33
|
+
VERSION_MISMATCH = 'urn:oasis:names:tc:SAML:2.0:status:VersionMismatch'
|
34
|
+
|
35
|
+
ALL = [SUCCESS, REQUESTER, RESPONDER, VERSION_MISMATCH]
|
36
|
+
end
|
37
|
+
|
38
|
+
module SubStatusCodes
|
39
|
+
AUTHN_FAILED = 'urn:oasis:names:tc:SAML:2.0:status:AuthnFailed'
|
40
|
+
NO_AUTHN_CONTEXT = 'urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext'
|
41
|
+
PARTIAL_LOGOUT = 'urn:oasis:names:tc:SAML:2.0:status:PartialLogout'
|
42
|
+
REQUEST_DENIED = 'urn:oasis:names:tc:SAML:2.0:status:RequestDenied'
|
43
|
+
|
44
|
+
ALL = [AUTHN_FAILED, NO_AUTHN_CONTEXT, PARTIAL_LOGOUT, REQUEST_DENIED]
|
45
|
+
end
|
46
|
+
|
47
|
+
module Bindings
|
48
|
+
require 'saml/bindings/http_artifact'
|
49
|
+
require 'saml/bindings/http_redirect'
|
50
|
+
require 'saml/bindings/http_post'
|
51
|
+
require 'saml/bindings/soap'
|
52
|
+
end
|
53
|
+
|
54
|
+
module ClassRefs
|
55
|
+
PASSWORD_PROTECTED = 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
56
|
+
MOBILE_TWO_FACTOR_CONTRACT = 'urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorContract'
|
57
|
+
MOBILE_SMARTCARD_PKI = 'urn:oasis:names:tc:SAML:2.0:ac:classes:SmartcardPKI'
|
58
|
+
|
59
|
+
ALL_CLASS_REFS = [PASSWORD_PROTECTED,
|
60
|
+
MOBILE_TWO_FACTOR_CONTRACT,
|
61
|
+
MOBILE_SMARTCARD_PKI]
|
62
|
+
ORDERED_CLASS_REFS = ALL_CLASS_REFS
|
63
|
+
end
|
64
|
+
|
65
|
+
module ComplexTypes
|
66
|
+
require 'saml/complex_types/request_abstract_type'
|
67
|
+
require 'saml/complex_types/status_response_type'
|
68
|
+
require 'saml/complex_types/endpoint_type'
|
69
|
+
require 'saml/complex_types/indexed_endpoint_type'
|
70
|
+
require 'saml/complex_types/sso_descriptor_type'
|
71
|
+
end
|
72
|
+
|
73
|
+
module Elements
|
74
|
+
require 'saml/elements/signature'
|
75
|
+
require 'saml/elements/subject_locality'
|
76
|
+
require 'saml/elements/authn_context'
|
77
|
+
require 'saml/elements/audience_restriction'
|
78
|
+
require 'saml/elements/sub_status_code'
|
79
|
+
require 'saml/elements/status_code'
|
80
|
+
require 'saml/elements/status'
|
81
|
+
require 'saml/elements/subject_confirmation_data'
|
82
|
+
require 'saml/elements/subject_confirmation'
|
83
|
+
require 'saml/elements/attribute'
|
84
|
+
require 'saml/elements/attribute_statement'
|
85
|
+
require 'saml/elements/name_id'
|
86
|
+
require 'saml/elements/subject'
|
87
|
+
require 'saml/elements/conditions'
|
88
|
+
require 'saml/elements/authn_statement'
|
89
|
+
require 'saml/elements/requested_authn_context'
|
90
|
+
require 'saml/elements/key_descriptor'
|
91
|
+
require 'saml/elements/organization'
|
92
|
+
require 'saml/elements/contact_person'
|
93
|
+
require 'saml/elements/idp_sso_descriptor'
|
94
|
+
require 'saml/elements/sp_sso_descriptor'
|
95
|
+
require 'saml/elements/entity_descriptor'
|
96
|
+
require 'saml/elements/entities_descriptor'
|
97
|
+
end
|
98
|
+
|
99
|
+
require 'saml/assertion'
|
100
|
+
require 'saml/authn_request'
|
101
|
+
require 'saml/artifact'
|
102
|
+
require 'saml/response'
|
103
|
+
require 'saml/artifact_resolve'
|
104
|
+
require 'saml/artifact_response'
|
105
|
+
require 'saml/logout_request'
|
106
|
+
require 'saml/logout_response'
|
107
|
+
require 'saml/provider'
|
108
|
+
|
109
|
+
module ProviderStores
|
110
|
+
require 'saml/provider_stores/file'
|
111
|
+
end
|
112
|
+
|
113
|
+
module ProtocolBinding
|
114
|
+
HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'
|
115
|
+
HTTP_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
|
116
|
+
HTTP_REDIRECT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
117
|
+
SOAP = 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP'
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.setup
|
121
|
+
yield Saml::Config
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.generate_id
|
125
|
+
"_#{::SecureRandom.hex(20)}"
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.provider(entity_id)
|
129
|
+
Saml::Config.provider_store.find_by_entity_id(entity_id) || raise(Saml::Errors::InvalidProvider.new)
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.parse_message(message, type)
|
133
|
+
if %w(authn_request response logout_request logout_response artifact_resolve artifact_response).include?(type.to_s)
|
134
|
+
klass = "Saml::#{type.to_s.camelize}".constantize
|
135
|
+
klass.parse(message, single: true)
|
136
|
+
else
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
require 'saml/config'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Saml
|
2
|
+
class Artifact
|
3
|
+
include ::HappyMapper
|
4
|
+
|
5
|
+
TYPE_CODE = "\000\004"
|
6
|
+
END_POINT_INDEX = "\000\000"
|
7
|
+
|
8
|
+
tag "Artifact"
|
9
|
+
namespace 'samlp'
|
10
|
+
|
11
|
+
content :artifact, String
|
12
|
+
|
13
|
+
def initialize(artifact = nil)
|
14
|
+
if artifact
|
15
|
+
@artifact = artifact
|
16
|
+
else
|
17
|
+
source_id = ::Digest::SHA1.digest(Saml::Config.entity_id)
|
18
|
+
message_handle = ::SecureRandom.random_bytes(20)
|
19
|
+
@type_code = TYPE_CODE
|
20
|
+
@endpoint_index = END_POINT_INDEX
|
21
|
+
@artifact = Saml::Encoding.encode_64 [@type_code, @endpoint_index, source_id, message_handle].join
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def type_code
|
26
|
+
decoded_value[0, 2]
|
27
|
+
end
|
28
|
+
|
29
|
+
def endpoint_index
|
30
|
+
decoded_value[2, 2]
|
31
|
+
end
|
32
|
+
|
33
|
+
def source_id
|
34
|
+
decoded_value[4, 20]
|
35
|
+
end
|
36
|
+
|
37
|
+
def message_handle
|
38
|
+
decoded_value[24, 20]
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
artifact
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def decoded_value
|
48
|
+
::Base64.decode64(artifact)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Saml
|
2
|
+
class Assertion
|
3
|
+
include Saml::Base
|
4
|
+
include Saml::XMLHelpers
|
5
|
+
|
6
|
+
register_namespace 'samlp', Saml::SAMLP_NAMESPACE
|
7
|
+
register_namespace 'saml', Saml::SAML_NAMESPACE
|
8
|
+
|
9
|
+
tag "Assertion"
|
10
|
+
namespace 'saml'
|
11
|
+
|
12
|
+
attribute :_id, String, :tag => 'ID'
|
13
|
+
attribute :version, String, :tag => "Version"
|
14
|
+
attribute :issue_instant, Time, :tag => "IssueInstant", :on_save => lambda { |val| val.utc.xmlschema }
|
15
|
+
|
16
|
+
element :issuer, String, :namespace => 'saml', :tag => "Issuer"
|
17
|
+
|
18
|
+
has_one :signature, Saml::Elements::Signature
|
19
|
+
has_one :subject, Saml::Elements::Subject
|
20
|
+
has_one :conditions, Saml::Elements::Conditions
|
21
|
+
has_many :authn_statement, Saml::Elements::AuthnStatement
|
22
|
+
has_one :attribute_statement, Saml::Elements::AttributeStatement
|
23
|
+
|
24
|
+
validates :_id, :version, :issue_instant, :issuer, :presence => true
|
25
|
+
|
26
|
+
validates :version, inclusion: %w(2.0)
|
27
|
+
validate :check_issue_instant, :if => "issue_instant.present?"
|
28
|
+
|
29
|
+
def initialize(*args)
|
30
|
+
options = args.extract_options!
|
31
|
+
@subject = Saml::Elements::Subject.new(:name_id => options.delete(:name_id),
|
32
|
+
:name_id_format => options.delete(:name_id_format),
|
33
|
+
:recipient => options.delete(:recipient),
|
34
|
+
:in_response_to => options.delete(:in_response_to))
|
35
|
+
@conditions = Saml::Elements::Conditions.new(:audience => options.delete(:audience))
|
36
|
+
@authn_statement = Saml::Elements::AuthnStatement.new(:authn_instant => Time.now,
|
37
|
+
:address => options.delete(:address),
|
38
|
+
:authn_context_class_ref => options.delete(:authn_context_class_ref),
|
39
|
+
:session_index => options.delete(:session_index))
|
40
|
+
super(*(args << options))
|
41
|
+
@_id ||= Saml.generate_id
|
42
|
+
@issue_instant ||= Time.now
|
43
|
+
@issuer ||= Saml::Config.entity_id
|
44
|
+
@version ||= Saml::SAML_VERSION
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_attribute(key, value)
|
48
|
+
self.attribute_statement ||= Saml::Elements::AttributeStatement.new
|
49
|
+
self.attribute_statement.attribute ||= []
|
50
|
+
self.attribute_statement.attribute << Saml::Elements::Attribute.new(name: key, attribute_value: value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def fetch_attribute(key)
|
54
|
+
return unless self.attribute_statement
|
55
|
+
return unless self.attribute_statement.attribute
|
56
|
+
attribute_statement.fetch_attribute(key)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def check_issue_instant
|
62
|
+
errors.add(:issue_instant, :too_old) if issue_instant < Time.now - Saml::Config.max_issue_instant_offset.minutes
|
63
|
+
errors.add(:issue_instant, :too_new) if issue_instant > Time.now + Saml::Config.max_issue_instant_offset.minutes
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|