ciam-es 0.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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/Gemfile +4 -0
- data/README.md +127 -0
- data/ciam-es.gemspec +23 -0
- data/lib/ciam-es.rb +14 -0
- data/lib/ciam/ruby-saml/authrequest.rb +206 -0
- data/lib/ciam/ruby-saml/coding.rb +34 -0
- data/lib/ciam/ruby-saml/error_handling.rb +27 -0
- data/lib/ciam/ruby-saml/logging.rb +26 -0
- data/lib/ciam/ruby-saml/logout_request.rb +126 -0
- data/lib/ciam/ruby-saml/logout_response.rb +132 -0
- data/lib/ciam/ruby-saml/metadata.rb +509 -0
- data/lib/ciam/ruby-saml/request.rb +81 -0
- data/lib/ciam/ruby-saml/response.rb +683 -0
- data/lib/ciam/ruby-saml/settings.rb +89 -0
- data/lib/ciam/ruby-saml/utils.rb +225 -0
- data/lib/ciam/ruby-saml/validation_error.rb +7 -0
- data/lib/ciam/ruby-saml/version.rb +5 -0
- data/lib/ciam/xml_security.rb +166 -0
- data/lib/ciam/xml_security_new.rb +373 -0
- data/lib/schemas/saml20assertion_schema.xsd +283 -0
- data/lib/schemas/saml20protocol_schema.xsd +302 -0
- data/lib/schemas/xenc_schema.xsd +146 -0
- data/lib/schemas/xmldsig_schema.xsd +318 -0
- data/test/certificates/certificate1 +12 -0
- data/test/logoutrequest_test.rb +98 -0
- data/test/request_test.rb +53 -0
- data/test/response_test.rb +219 -0
- data/test/responses/adfs_response_sha1.xml +46 -0
- data/test/responses/adfs_response_sha256.xml +46 -0
- data/test/responses/adfs_response_sha384.xml +46 -0
- data/test/responses/adfs_response_sha512.xml +46 -0
- data/test/responses/no_signature_ns.xml +48 -0
- data/test/responses/open_saml_response.xml +56 -0
- data/test/responses/response1.xml.base64 +1 -0
- data/test/responses/response2.xml.base64 +79 -0
- data/test/responses/response3.xml.base64 +66 -0
- data/test/responses/response4.xml.base64 +93 -0
- data/test/responses/response5.xml.base64 +102 -0
- data/test/responses/response_with_ampersands.xml +139 -0
- data/test/responses/response_with_ampersands.xml.base64 +93 -0
- data/test/responses/simple_saml_php.xml +71 -0
- data/test/responses/wrapped_response_2.xml.base64 +150 -0
- data/test/settings_test.rb +43 -0
- data/test/test_helper.rb +65 -0
- data/test/xml_security_test.rb +123 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4e95196cb69850d66b4ad960fcf279885cb600448b39548e22b627998da49363
|
4
|
+
data.tar.gz: 53895057eaafde1db9a846ca1f885219348bdeb0dcaffffb29c39c74e78bd20c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 12312ab615271d5e7213a49528de7a286ffd3a103bdd7cf4ff810c2f146fe5bd7fba0bb10df24a37a7c9d3c74be0c875d43fdaaa3e05bead86c1366545278918
|
7
|
+
data.tar.gz: 2f46ce928a88d79369d7b22d8ef29f4490b0a6a8c600c2927b511e539d8b62a189c3c81ff56a3276b965d907d2f0ea78890c28594c9a71a98c092fd6a5749f85
|
data/.document
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# SPID Euro Servizi
|
2
|
+
|
3
|
+
La libreria è un fork della libreria Ruby SAML e serve per l'integrazione di un client (Service Provider) con l'autenticazione CIAM del Comune di Milano
|
4
|
+
Utilizza lo standard SAML 2
|
5
|
+
|
6
|
+
|
7
|
+
<!-- ## Fase iniziale
|
8
|
+
|
9
|
+
Azione di partenza in cui viene creata la request da inviare all'idp e viene fatto un redirect all'identity provider.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
def init
|
13
|
+
#creo un istanza di Spid::Saml::Authrequest
|
14
|
+
saml_settings = get_saml_settings
|
15
|
+
#create an instance of Spid::Saml::Authrequest
|
16
|
+
request = Spid::Saml::Authrequest.new(saml_settings)
|
17
|
+
auth_request = request.create
|
18
|
+
# Based on the IdP metadata, select the appropriate binding
|
19
|
+
# and return the action to perform to the controller
|
20
|
+
meta = Spid::Saml::Metadata.new(saml_settings)
|
21
|
+
signature = get_signature(auth_request.uuid,auth_request.request,"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
|
22
|
+
sso_request = meta.create_sso_request( auth_request.request, { :RelayState => request.uuid,
|
23
|
+
:SigAlg => "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
24
|
+
:Signature => signature } )
|
25
|
+
redirect_to sso_request
|
26
|
+
end
|
27
|
+
|
28
|
+
```
|
29
|
+
## Generazione della firma
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
def get_signature(relayState, request, sigAlg)
|
33
|
+
#url encode relayState
|
34
|
+
relayState_encoded = escape(relayState)
|
35
|
+
#deflate e base64 della samlrequest
|
36
|
+
deflate_request_B64 = encode(deflate(request))
|
37
|
+
#url encode della samlrequest
|
38
|
+
deflate_request_B64_encoded = escape(deflate_request_B64)
|
39
|
+
#url encode della sigAlg
|
40
|
+
sigAlg_encoded = escape(sigAlg)
|
41
|
+
querystring="SAMLRequest=#{deflate_request_B64_encoded}&RelayState=#{relayState_encoded}&SigAlg=#{sigAlg_encoded}"
|
42
|
+
#puts "**QUERYSTRING** = "+querystring
|
43
|
+
digest = OpenSSL::Digest::SHA256.new(querystring.strip) #sha2 a 256
|
44
|
+
chiave_privata = xxxxxx #path della chiave privata con cui firmare
|
45
|
+
pk = OpenSSL::PKey::RSA.new File.read(chiave_privata) #chiave privata
|
46
|
+
qssigned = pk.sign(digest,querystring.strip)
|
47
|
+
Base64.encode64(qssigned).gsub(/\n/, "")
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
|
52
|
+
Questo metodo è l'endpoint impostato a livello di metadata del service provider come 'assertion consumer', riceve la response saml con i dati di registrazione fatta su SPID dagli utenti.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
def assertion_consumer
|
56
|
+
#id dell' idp che manda response (es: 'infocert','poste')
|
57
|
+
provider_id = @request.params['ProviderID']
|
58
|
+
#response saml inviata dall'idp
|
59
|
+
saml_response = @request.params['SAMLResponse']
|
60
|
+
if !saml_response.nil?
|
61
|
+
#assegno i settaggi
|
62
|
+
settings = get_saml_settings
|
63
|
+
#creo un oggetto response
|
64
|
+
response = Spid::Saml::Response.new(saml_response)
|
65
|
+
#assegno alla response i settaggi
|
66
|
+
response.settings = settings
|
67
|
+
#estraggo dal Base64 l'xml
|
68
|
+
saml_response_dec = Base64.decode64(saml_response)
|
69
|
+
#puts "**SAML RESPONSE DECODIFICATA: #{saml_response_dec}"
|
70
|
+
|
71
|
+
#validation of response
|
72
|
+
if response.is_valid?
|
73
|
+
attributi_utente = response.attributes
|
74
|
+
...
|
75
|
+
else
|
76
|
+
#autenticazione fallita!
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Questo metodo va a impostare le varie configurazioni che servono per connettersi ad un idp. ( NB: nel caso di SPID ci sono vari idp (Poste, TIM, Info Cert) )
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
def get_saml_settings
|
86
|
+
settings = Spid::Saml::Settings.new
|
87
|
+
settings.assertion_consumer_service_url #= ...String, url dell' assertion consumer al quale arriva la response dell' idp.
|
88
|
+
settings.issuer #= ...String, host del service provider o url dei metadata.
|
89
|
+
settings.sp_cert #= ...String, path del certificato pubblico in formato pem.
|
90
|
+
settings.sp_private_key #= ...String, path della chiave privata in formato pem.
|
91
|
+
settings.single_logout_service_url #= ...String, url del servizio di logout dell'idp.
|
92
|
+
settings.sp_name_qualifier #= ...String, nome qualificato del service provider o url dei metadata.
|
93
|
+
settings.idp_name_qualifier #= ...String, nome qualificato dell' identity provider o url dei metadata dell' idp.
|
94
|
+
settings.name_identifier_format #= ...Array, formato di nomi ( impostare: ["urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] ).
|
95
|
+
settings.destination_service_url #= ...String, url del servizio per l'identity provider, usato come proxy per il sso.
|
96
|
+
settings.single_logout_destination #= ...String, url di destinazione per la request logout.
|
97
|
+
settings.authn_context #= ...Array, tipi di autorizzazioni permesse (impostare: ["urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard",
|
98
|
+
"urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"]).
|
99
|
+
settings.requester_identificator #= ...Array con id dei richiedenti (non usato).
|
100
|
+
settings.skip_validation #= ...Bool, imposta se evitare la validazione della response o delle asserzioni (false).
|
101
|
+
settings.idp_sso_target_url #= ...String, url target del sso dell' identity provider.
|
102
|
+
settings.idp_metadata #= ...String, url dei metadata dell' idp.
|
103
|
+
settings.requested_attribute #= ...Array, contiene i nomi dei campi richiesti dal servizio nei metadata.
|
104
|
+
settings.metadata_signed #= ...String, imposta se firmare i metadata.
|
105
|
+
settings.organization #= ...Hash, contiene nome breve (org_name), nome esteso (org_display_name) e url (org_url)
|
106
|
+
dell' organizzazione fornitore di servizi.
|
107
|
+
settings
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
## Service Provider Metadata
|
114
|
+
|
115
|
+
Per una relazione sicura con l'idp, il Service Provider deve fornire i metadata in formato xml.
|
116
|
+
La classe Spid::Saml::Metadata legge i settaggi e fornisce l'xml richiesto dagli idp.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
def sp_metadata
|
120
|
+
settings = get_saml_settings
|
121
|
+
meta = Spid::Saml::Metadata.new
|
122
|
+
|
123
|
+
@response.headers['Content-Type'] = 'application/samlmetadata+xml'
|
124
|
+
$out << meta.generate(settings)
|
125
|
+
end
|
126
|
+
``` -->
|
127
|
+
|
data/ciam-es.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'ciam-es'
|
5
|
+
s.version = '0.0.1'
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Fabiano Pavan"]
|
9
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
10
|
+
s.description = %q{SAML toolkit for Ruby programs to integrate with CIAM Milano }
|
11
|
+
s.email = %q{fabiano.pavan@soluzionipa.it}
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.homepage = %q{https://github.com/EuroServizi/ciam-es}
|
14
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.summary = %q{SAML Ruby Tookit CIAM}
|
17
|
+
s.license = "MIT"
|
18
|
+
|
19
|
+
s.add_runtime_dependency("canonix", ["0.1.1"])
|
20
|
+
s.add_runtime_dependency("uuid", ["~> 2.3"])
|
21
|
+
s.add_runtime_dependency("nokogiri", '>= 1.6.7.2')
|
22
|
+
s.add_runtime_dependency("addressable", ["2.7.0"])
|
23
|
+
end
|
data/lib/ciam-es.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'ciam/xml_security'
|
2
|
+
require 'ciam/ruby-saml/utils'
|
3
|
+
require 'ciam/ruby-saml/logging'
|
4
|
+
require 'ciam/ruby-saml/coding'
|
5
|
+
require 'ciam/ruby-saml/request'
|
6
|
+
require 'ciam/ruby-saml/authrequest'
|
7
|
+
require 'ciam/ruby-saml/logout_request'
|
8
|
+
require 'ciam/ruby-saml/logout_response'
|
9
|
+
require 'ciam/ruby-saml/response'
|
10
|
+
require 'ciam/ruby-saml/settings'
|
11
|
+
require 'ciam/ruby-saml/error_handling'
|
12
|
+
require 'ciam/ruby-saml/validation_error'
|
13
|
+
require 'ciam/ruby-saml/metadata'
|
14
|
+
require 'ciam/ruby-saml/version'
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "uuid"
|
3
|
+
require "zlib"
|
4
|
+
require "cgi"
|
5
|
+
require "rexml/document"
|
6
|
+
require "rexml/xpath"
|
7
|
+
require "rubygems"
|
8
|
+
require "addressable/uri"
|
9
|
+
|
10
|
+
module Ciam::Saml
|
11
|
+
include REXML
|
12
|
+
class Authrequest
|
13
|
+
# a few symbols for SAML class names
|
14
|
+
HTTP_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
15
|
+
HTTP_GET = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
16
|
+
|
17
|
+
attr_accessor :uuid, :request, :issue_instant
|
18
|
+
|
19
|
+
def initialize( settings )
|
20
|
+
@settings = settings
|
21
|
+
@request_params = Hash.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def create(params = {})
|
25
|
+
uuid = "_" + UUID.new.generate
|
26
|
+
self.uuid = uuid
|
27
|
+
time = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
28
|
+
self.issue_instant = time
|
29
|
+
# Create AuthnRequest root element using REXML
|
30
|
+
request_doc = Ciam::XMLSecurityNew::Document.new
|
31
|
+
request_doc.context[:attribute_quote] = :quote
|
32
|
+
root = request_doc.add_element "saml2p:AuthnRequest", { "xmlns:saml2p" => "urn:oasis:names:tc:SAML:2.0:protocol",
|
33
|
+
"xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion"
|
34
|
+
}
|
35
|
+
root.attributes['ID'] = uuid
|
36
|
+
root.attributes['IssueInstant'] = time
|
37
|
+
root.attributes['Version'] = "2.0"
|
38
|
+
#root.attributes['ProtocolBinding'] = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
39
|
+
root.attributes['AttributeConsumingServiceIndex'] = @settings.assertion_consumer_service_index
|
40
|
+
root.attributes['ForceAuthn'] = "true"
|
41
|
+
#root.attributes['IsPassive'] = "false"
|
42
|
+
#usato AssertionConsumerServiceURL e ProtocolBinding in alternativa, pag 8 regole tecniche
|
43
|
+
root.attributes['AssertionConsumerServiceIndex'] = @settings.attribute_consuming_service_index
|
44
|
+
|
45
|
+
#Tolto, utilizzo AssertionConsumerServiceIndex
|
46
|
+
# # Conditionally defined elements based on settings
|
47
|
+
# if @settings.assertion_consumer_service_url != nil
|
48
|
+
# root.attributes["AssertionConsumerServiceURL"] = @settings.assertion_consumer_service_url
|
49
|
+
# end
|
50
|
+
|
51
|
+
if @settings.destination_service_url != nil
|
52
|
+
root.attributes["Destination"] = @settings.destination_service_url
|
53
|
+
end
|
54
|
+
|
55
|
+
unless @settings.issuer.blank?
|
56
|
+
issuer = root.add_element "saml:Issuer"
|
57
|
+
issuer.attributes['NameQualifier'] = @settings.issuer #non metto @settings.sp_name_qualifier, questo valore deve essere uguale al
|
58
|
+
#entityID dei metadata che usa @settings.issuer
|
59
|
+
issuer.attributes['Format'] = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity"
|
60
|
+
issuer.text = @settings.issuer
|
61
|
+
end
|
62
|
+
|
63
|
+
#opzionale
|
64
|
+
unless @settings.sp_name_qualifier.blank?
|
65
|
+
subject = root.add_element "saml:Subject"
|
66
|
+
name_id = subject.add_element "saml:NameID"
|
67
|
+
name_id.attributes['Format'] = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
68
|
+
name_id.attributes['NameQualifier'] = @settings.sp_name_qualifier
|
69
|
+
name_id.text = @settings.sp_name_identifier
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
if @settings.name_identifier_format != nil
|
75
|
+
root.add_element "saml2p:NameIDPolicy", {
|
76
|
+
# Might want to make AllowCreate a setting?
|
77
|
+
#{}"AllowCreate" => "true",
|
78
|
+
"Format" => @settings.name_identifier_format[0]
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
# BUG fix here -- if an authn_context is defined, add the tags with an "exact"
|
83
|
+
# match required for authentication to succeed. If this is not defined,
|
84
|
+
# the IdP will choose default rules for authentication. (Shibboleth IdP)
|
85
|
+
if @settings.authn_context != nil
|
86
|
+
requested_context = root.add_element "saml2p:RequestedAuthnContext", {
|
87
|
+
"Comparison" => "minimum"
|
88
|
+
}
|
89
|
+
context_class = []
|
90
|
+
@settings.authn_context.each_with_index{ |context, index|
|
91
|
+
context_class[index] = requested_context.add_element "saml:AuthnContextClassRef"
|
92
|
+
context_class[index].text = context
|
93
|
+
}
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
if @settings.requester_identificator != nil
|
98
|
+
requester_identificator = root.add_element "saml2p:Scoping", {
|
99
|
+
"ProxyCount" => "0"
|
100
|
+
}
|
101
|
+
identificators = []
|
102
|
+
@settings.requester_identificator.each_with_index{ |requester, index|
|
103
|
+
identificators[index] = requester_identificator.add_element "saml2p:RequesterID"
|
104
|
+
identificators[index].text = requester
|
105
|
+
}
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
request_doc << REXML::XMLDecl.new("1.0", "UTF-8")
|
110
|
+
|
111
|
+
#LA FIRMA VA MESSA SOLO NEL CASO CON HTTP POST
|
112
|
+
# cert = @settings.get_sp_cert
|
113
|
+
# # embed signature
|
114
|
+
# if @settings.metadata_signed && @settings.sp_private_key && @settings.sp_cert
|
115
|
+
# private_key = @settings.get_sp_key
|
116
|
+
# request_doc.sign_document(private_key, cert)
|
117
|
+
# end
|
118
|
+
|
119
|
+
# stampo come stringa semplice i metadata per non avere problemi con validazione firma
|
120
|
+
#ret = request_doc.to_s
|
121
|
+
|
122
|
+
@request = request_doc.to_s
|
123
|
+
|
124
|
+
#Logging.debug "Created AuthnRequest: #{@request}"
|
125
|
+
|
126
|
+
return self
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
# get the IdP metadata, and select the appropriate SSO binding
|
131
|
+
# that we can support. Currently this is HTTP-Redirect and HTTP-POST
|
132
|
+
# but more could be added in the future
|
133
|
+
def binding_select
|
134
|
+
# first check if we're still using the old hard coded method for
|
135
|
+
# backwards compatability
|
136
|
+
if @settings.idp_metadata == nil && @settings.idp_sso_target_url != nil
|
137
|
+
@URL = @settings.idp_sso_target_url
|
138
|
+
return "GET", content_get
|
139
|
+
end
|
140
|
+
# grab the metadata
|
141
|
+
metadata = Metadata::new
|
142
|
+
meta_doc = metadata.get_idp_metadata(@settings)
|
143
|
+
|
144
|
+
# first try POST
|
145
|
+
sso_element = REXML::XPath.first(meta_doc,
|
146
|
+
"/EntityDescriptor/IDPSSODescriptor/SingleSignOnService[@Binding='#{HTTP_POST}']")
|
147
|
+
if sso_element
|
148
|
+
@URL = sso_element.attributes["Location"]
|
149
|
+
#Logging.debug "binding_select: POST to #{@URL}"
|
150
|
+
return "POST", content_post
|
151
|
+
end
|
152
|
+
|
153
|
+
# next try GET
|
154
|
+
sso_element = REXML::XPath.first(meta_doc,
|
155
|
+
"/EntityDescriptor/IDPSSODescriptor/SingleSignOnService[@Binding='#{HTTP_GET}']")
|
156
|
+
if sso_element
|
157
|
+
@URL = sso_element.attributes["Location"]
|
158
|
+
Logging.debug "binding_select: GET from #{@URL}"
|
159
|
+
return "GET", content_get
|
160
|
+
end
|
161
|
+
# other types we might want to add in the future: SOAP, Artifact
|
162
|
+
end
|
163
|
+
|
164
|
+
# construct the the parameter list on the URL and return
|
165
|
+
def content_get
|
166
|
+
# compress GET requests to try and stay under that 8KB request limit
|
167
|
+
deflated_request = Zlib::Deflate.deflate(@request, 9)[2..-5]
|
168
|
+
# strict_encode64() isn't available? sub out the newlines
|
169
|
+
@request_params["SAMLRequest"] = Base64.encode64(deflated_request).gsub(/\n/, "")
|
170
|
+
|
171
|
+
Logging.debug "SAMLRequest=#{@request_params["SAMLRequest"]}"
|
172
|
+
uri = Addressable::URI.parse(@URL)
|
173
|
+
if uri.query_values == nil
|
174
|
+
uri.query_values = @request_params
|
175
|
+
else
|
176
|
+
# solution to stevenwilkin's parameter merge
|
177
|
+
uri.query_values = @request_params.merge(uri.query_values)
|
178
|
+
end
|
179
|
+
url = uri.to_s
|
180
|
+
#Logging.debug "Sending to URL #{url}"
|
181
|
+
return url
|
182
|
+
end
|
183
|
+
# construct an HTML form (POST) and return the content
|
184
|
+
def content_post
|
185
|
+
# POST requests seem to bomb out when they're deflated
|
186
|
+
# and they probably don't need to be compressed anyway
|
187
|
+
@request_params["SAMLRequest"] = Base64.encode64(@request).gsub(/\n/, "")
|
188
|
+
|
189
|
+
#Logging.debug "SAMLRequest=#{@request_params["SAMLRequest"]}"
|
190
|
+
# kind of a cheesy method of building an HTML, form since we can't rely on Rails too much,
|
191
|
+
# and REXML doesn't work well with quote characters
|
192
|
+
str = "<html><body onLoad=\"document.getElementById('form').submit();\">\n"
|
193
|
+
str += "<form id='form' name='form' method='POST' action=\"#{@URL}\">\n"
|
194
|
+
# we could change this in the future to associate a temp auth session ID
|
195
|
+
str += "<input name='RelayState' value='ruby-saml' type='hidden' />\n"
|
196
|
+
@request_params.each_pair do |key, value|
|
197
|
+
str += "<input name=\"#{key}\" value=\"#{value}\" type='hidden' />\n"
|
198
|
+
#str += "<input name=\"#{key}\" value=\"#{CGI.escape(value)}\" type='hidden' />\n"
|
199
|
+
end
|
200
|
+
str += "</form></body></html>\n"
|
201
|
+
|
202
|
+
#Logging.debug "Created form:\n#{str}"
|
203
|
+
return str
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require 'zlib'
|
3
|
+
|
4
|
+
module Ciam
|
5
|
+
module Saml
|
6
|
+
module Coding
|
7
|
+
def decode(encoded)
|
8
|
+
Base64.decode64(encoded)
|
9
|
+
end
|
10
|
+
|
11
|
+
def encode(encoded)
|
12
|
+
Base64.encode64(encoded).gsub(/\n/, "")
|
13
|
+
end
|
14
|
+
|
15
|
+
def escape(unescaped)
|
16
|
+
CGI.escape(unescaped)
|
17
|
+
end
|
18
|
+
|
19
|
+
def unescape(escaped)
|
20
|
+
CGI.unescape(escaped)
|
21
|
+
end
|
22
|
+
|
23
|
+
def inflate(deflated)
|
24
|
+
zlib = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
25
|
+
zlib.inflate(deflated)
|
26
|
+
end
|
27
|
+
|
28
|
+
def deflate(inflated)
|
29
|
+
Zlib::Deflate.deflate(inflated, 9)[2..-5]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "ciam/ruby-saml/validation_error"
|
2
|
+
|
3
|
+
module Ciam
|
4
|
+
module Saml
|
5
|
+
module ErrorHandling
|
6
|
+
attr_accessor :errors
|
7
|
+
|
8
|
+
# Append the cause to the errors array, and based on the value of soft, return false or raise
|
9
|
+
# an exception. soft_override is provided as a means of overriding the object's notion of
|
10
|
+
# soft for just this invocation.
|
11
|
+
def append_error(error_msg, soft_override = nil)
|
12
|
+
@errors << error_msg
|
13
|
+
|
14
|
+
unless soft_override.nil? ? soft : soft_override
|
15
|
+
raise ValidationError.new(error_msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Reset the errors array
|
22
|
+
def reset_errors!
|
23
|
+
@errors = []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|