@@ -21,21 +21,50 @@ class Metadata
2121 #
2222 def generate ( settings , pretty_print = false , valid_until = nil , cache_duration = nil )
2323 meta_doc = XMLSecurity ::Document . new
24+ add_xml_declaration ( meta_doc )
25+ root = add_root_element ( meta_doc , settings , valid_until , cache_duration )
26+ sp_sso = add_sp_sso_element ( root , settings )
27+ add_sp_certificates ( sp_sso , settings )
28+ add_sp_service_elements ( sp_sso , settings )
29+ add_extras ( root , settings )
30+ embed_signature ( meta_doc , settings )
31+ output_xml ( meta_doc , pretty_print )
32+ end
33+
34+ protected
35+
36+ def add_xml_declaration ( meta_doc )
37+ meta_doc << REXML ::XMLDecl . new ( '1.0' , 'UTF-8' )
38+ end
39+
40+ def add_root_element ( meta_doc , settings , valid_until , cache_duration )
2441 namespaces = {
2542 "xmlns:md" => "urn:oasis:names:tc:SAML:2.0:metadata"
2643 }
44+
2745 if settings . attribute_consuming_service . configured?
2846 namespaces [ "xmlns:saml" ] = "urn:oasis:names:tc:SAML:2.0:assertion"
2947 end
30- root = meta_doc . add_element "md:EntityDescriptor" , namespaces
31- sp_sso = root . add_element "md:SPSSODescriptor" , {
48+
49+ root = meta_doc . add_element ( "md:EntityDescriptor" , namespaces )
50+ root . attributes [ "ID" ] = OneLogin ::RubySaml ::Utils . uuid
51+ root . attributes [ "entityID" ] = settings . sp_entity_id if settings . sp_entity_id
52+ root . attributes [ "validUntil" ] = valid_until . strftime ( '%Y-%m-%dT%H:%M:%S%z' ) if valid_until
53+ root . attributes [ "cacheDuration" ] = "PT" + cache_duration . to_s + "S" if cache_duration
54+ root
55+ end
56+
57+ def add_sp_sso_element ( root , settings )
58+ root . add_element "md:SPSSODescriptor" , {
3259 "protocolSupportEnumeration" => "urn:oasis:names:tc:SAML:2.0:protocol" ,
3360 "AuthnRequestsSigned" => settings . security [ :authn_requests_signed ] ,
3461 "WantAssertionsSigned" => settings . security [ :want_assertions_signed ] ,
3562 }
63+ end
3664
37- # Add KeyDescriptor if messages will be signed / encrypted
38- # with SP certificate, and new SP certificate if any
65+ # Add KeyDescriptor if messages will be signed / encrypted
66+ # with SP certificate, and new SP certificate if any
67+ def add_sp_certificates ( sp_sso , settings )
3968 cert = settings . get_sp_cert
4069 cert_new = settings . get_sp_cert_new
4170
@@ -58,27 +87,23 @@ def generate(settings, pretty_print=false, valid_until=nil, cache_duration=nil)
5887 end
5988 end
6089
61- root . attributes [ "ID" ] = OneLogin ::RubySaml ::Utils . uuid
62- if settings . sp_entity_id
63- root . attributes [ "entityID" ] = settings . sp_entity_id
64- end
65- if valid_until
66- root . attributes [ "validUntil" ] = valid_until . strftime ( '%Y-%m-%dT%H:%M:%S%z' )
67- end
68- if cache_duration
69- root . attributes [ "cacheDuration" ] = "PT" + cache_duration . to_s + "S"
70- end
90+ sp_sso
91+ end
92+
93+ def add_sp_service_elements ( sp_sso , settings )
7194 if settings . single_logout_service_url
7295 sp_sso . add_element "md:SingleLogoutService" , {
7396 "Binding" => settings . single_logout_service_binding ,
7497 "Location" => settings . single_logout_service_url ,
7598 "ResponseLocation" => settings . single_logout_service_url
7699 }
77100 end
101+
78102 if settings . name_identifier_format
79103 nameid = sp_sso . add_element "md:NameIDFormat"
80104 nameid . text = settings . name_identifier_format
81105 end
106+
82107 if settings . assertion_consumer_service_url
83108 sp_sso . add_element "md:AssertionConsumerService" , {
84109 "Binding" => settings . assertion_consumer_service_binding ,
@@ -117,23 +142,35 @@ def generate(settings, pretty_print=false, valid_until=nil, cache_duration=nil)
117142 # <md:RoleDescriptor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:query="urn:oasis:names:tc:SAML:metadata:ext:query" xsi:type="query:AttributeQueryDescriptorType" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
118143 # <md:XACMLAuthzDecisionQueryDescriptor WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
119144
120- meta_doc << REXML ::XMLDecl . new ( "1.0" , "UTF-8" )
145+ sp_sso
146+ end
121147
122- # embed signature
123- if settings . security [ :metadata_signed ] && settings . private_key && settings . certificate
124- private_key = settings . get_sp_key
125- meta_doc . sign_document ( private_key , cert , settings . security [ :signature_method ] , settings . security [ :digest_method ] )
126- end
148+ # can be overridden in subclass
149+ def add_extras ( root , _settings )
150+ root
151+ end
152+
153+ def embed_signature ( meta_doc , settings )
154+ return unless settings . security [ :metadata_signed ]
155+
156+ private_key = settings . get_sp_key
157+ cert = settings . get_sp_cert
158+ return unless private_key && cert
159+
160+ meta_doc . sign_document ( private_key , cert , settings . security [ :signature_method ] , settings . security [ :digest_method ] )
161+ end
162+
163+ def output_xml ( meta_doc , pretty_print )
164+ ret = ''
127165
128- ret = ""
129166 # pretty print the XML so IdP administrators can easily see what the SP supports
130167 if pretty_print
131168 meta_doc . write ( ret , 1 )
132169 else
133170 ret = meta_doc . to_s
134171 end
135172
136- return ret
173+ ret
137174 end
138175 end
139176 end
0 commit comments