shibkit-meta_meta 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +21 -0
  4. data/Gemfile.lock +52 -0
  5. data/Icon.png +0 -0
  6. data/LICENSE.txt +177 -0
  7. data/README.md +789 -0
  8. data/Rakefile +38 -0
  9. data/VERSION +1 -0
  10. data/examples/biggest_entity_id.rb +4 -0
  11. data/lib/shibkit/meta_meta.rb +600 -0
  12. data/lib/shibkit/meta_meta/attribute.rb +73 -0
  13. data/lib/shibkit/meta_meta/config.rb +463 -0
  14. data/lib/shibkit/meta_meta/contact.rb +85 -0
  15. data/lib/shibkit/meta_meta/data/default_metadata/example_federation_metadata.xml +168 -0
  16. data/lib/shibkit/meta_meta/data/default_metadata/local_metadata.xml +66 -0
  17. data/lib/shibkit/meta_meta/data/default_metadata/uncommon_federation_metadata.xml +115 -0
  18. data/lib/shibkit/meta_meta/data/default_metadata_cache.yml +166 -0
  19. data/lib/shibkit/meta_meta/data/dev_sources.yml +86 -0
  20. data/lib/shibkit/meta_meta/data/real_sources.yml +163 -0
  21. data/lib/shibkit/meta_meta/entity.rb +219 -0
  22. data/lib/shibkit/meta_meta/federation.rb +161 -0
  23. data/lib/shibkit/meta_meta/idp.rb +81 -0
  24. data/lib/shibkit/meta_meta/logo.rb +216 -0
  25. data/lib/shibkit/meta_meta/metadata_item.rb +244 -0
  26. data/lib/shibkit/meta_meta/mixin/cached_downloads.rb +127 -0
  27. data/lib/shibkit/meta_meta/mixin/xpath_chores.rb +111 -0
  28. data/lib/shibkit/meta_meta/organisation.rb +73 -0
  29. data/lib/shibkit/meta_meta/provider.rb +195 -0
  30. data/lib/shibkit/meta_meta/provisioning/base.rb +33 -0
  31. data/lib/shibkit/meta_meta/requested_attribute.rb +29 -0
  32. data/lib/shibkit/meta_meta/service.rb +94 -0
  33. data/lib/shibkit/meta_meta/source.rb +558 -0
  34. data/lib/shibkit/meta_meta/sp.rb +79 -0
  35. data/shibkit-meta_meta.gemspec +154 -0
  36. data/spec/meta_meta/attribute/token +0 -0
  37. data/spec/meta_meta/config/autoloading_and_refreshing_spec.rb +72 -0
  38. data/spec/meta_meta/config/code_nspec.rb +13 -0
  39. data/spec/meta_meta/config/configuration_spec.rb +30 -0
  40. data/spec/meta_meta/config/creation_spec.rb +43 -0
  41. data/spec/meta_meta/config/downloading_and_caching_settings_spec.rb +216 -0
  42. data/spec/meta_meta/config/env_platform_settings.rb +129 -0
  43. data/spec/meta_meta/config/filtering_settings_spec.rb +123 -0
  44. data/spec/meta_meta/config/init.rb +8 -0
  45. data/spec/meta_meta/config/logger_settings_spec.rb +91 -0
  46. data/spec/meta_meta/config/smartcache_settings_spec.rb +110 -0
  47. data/spec/meta_meta/config/source_file_settings_spec.rb +99 -0
  48. data/spec/meta_meta/config/tagging_settings_spec.rb +81 -0
  49. data/spec/meta_meta/config/working_directory_settings_spec.rb +106 -0
  50. data/spec/meta_meta/config/xml_processing_settings_spec.rb +75 -0
  51. data/spec/meta_meta/contact/contact_oldspec.rb +0 -0
  52. data/spec/meta_meta/entity/entity_oldspec.rb +53 -0
  53. data/spec/meta_meta/federation/federation_oldspec.rb +0 -0
  54. data/spec/meta_meta/idp/token +0 -0
  55. data/spec/meta_meta/logo/token +0 -0
  56. data/spec/meta_meta/meta_meta/cache_example.yaml +141284 -0
  57. data/spec/meta_meta/meta_meta/meta_meta_spec.rb +269 -0
  58. data/spec/meta_meta/meta_meta/saved_sources.yaml +46 -0
  59. data/spec/meta_meta/metadata_item/token +0 -0
  60. data/spec/meta_meta/organisation/organisation_oldspec.rb +0 -0
  61. data/spec/meta_meta/provider/token +0 -0
  62. data/spec/meta_meta/requested_attribute/token +0 -0
  63. data/spec/meta_meta/service/token +0 -0
  64. data/spec/meta_meta/source/application_extras_spec.rb +234 -0
  65. data/spec/meta_meta/source/conversion_spec.rb +75 -0
  66. data/spec/meta_meta/source/creation_spec.rb +0 -0
  67. data/spec/meta_meta/source/downloads_and_caching_spec.rb +0 -0
  68. data/spec/meta_meta/source/federation_information_spec.rb +11 -0
  69. data/spec/meta_meta/source/fixtures.rb +24 -0
  70. data/spec/meta_meta/source/init.rb +1 -0
  71. data/spec/meta_meta/source/loading_and_saving_spec.rb +0 -0
  72. data/spec/meta_meta/source/metadata_details_spec.rb +0 -0
  73. data/spec/meta_meta/source/metadata_integrity_spec.rb +0 -0
  74. data/spec/meta_meta/source/selection_spec.rb +0 -0
  75. data/spec/meta_meta/source/source_oldspec.rb +353 -0
  76. data/spec/meta_meta/source/xml_parsing_spec.rb +0 -0
  77. data/spec/meta_meta/sp/token +0 -0
  78. data/spec/meta_meta/template +2 -0
  79. data/spec/moi/config_spec.rb +0 -0
  80. data/spec/spec.opts +1 -0
  81. data/spec/spec_helper.rb +25 -0
  82. data/spec/support/supply_xml.rb +0 -0
  83. metadata +320 -0
@@ -0,0 +1,244 @@
1
+ ## @author Pete Birkinshaw (<pete@digitalidentitylabs.com>)
2
+ ## Copyright: Copyright (c) 2011 Digital Identity Ltd.
3
+ ## License: Apache License, Version 2.0
4
+
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ##
17
+
18
+ module Shibkit
19
+ class MetaMeta
20
+
21
+ ## Base class for all MetaMeta metadata classes
22
+ class MetadataItem
23
+
24
+ require 'nokogiri'
25
+ require 'digest/sha1'
26
+
27
+ ## A few simple utility functions for slurping data from XML
28
+ require 'shibkit/meta_meta/mixin/xpath_chores'
29
+ include Shibkit::MetaMeta::Mixin::XPathChores
30
+
31
+
32
+ ## Element and attribute used to select XML for new objects
33
+ ROOT_ELEMENT = 'SomeThingThatIsntThere'
34
+ TARGET_ATTR = 'ID'
35
+ REQUIRED_QUACKS = [:bananas]
36
+
37
+ ## Additional namespaces that Nokogiri needs to know about
38
+ NAMESPACES = {
39
+ 'ukfedlabel' => 'http://ukfederation.org.uk/2006/11/label',
40
+ 'elab' => 'http://eduserv.org.uk/labels',
41
+ 'wayf' => 'http://sdss.ac.uk/2006/06/WAYF',
42
+ 'mdui' => 'urn:oasis:names:tc:SAML:metadata:ui',
43
+ 'saml' => 'urn:oasis:names:tc:SAML:2.0:assertion',
44
+ 'shibmd' => 'urn:mace:shibboleth:metadata:1.0'
45
+ }
46
+
47
+ attr_reader :read_at
48
+
49
+ ## New object takes XML (as libXML object or text)
50
+ def initialize(xml=nil, target=nil, options={}, &block)
51
+
52
+ @read_at = Time.new
53
+ @noko = nil
54
+ @source_xml = nil
55
+
56
+ ## Use XML to build object
57
+ from_xml(xml) if xml
58
+
59
+ ## Use block for further configuration or manual creation
60
+ self.instance_eval(&block) if block
61
+
62
+ end
63
+
64
+ ## Make sure the object is suitable. Return nil if bad, object if good
65
+ def filter
66
+
67
+ ## Make sure this object quacks like the suitable variety of duck
68
+ self.class::REQUIRED_QUACKS.each do |method|
69
+
70
+ return nil unless self.respond_to? method
71
+ return nil unless self.send(method)
72
+
73
+ end
74
+
75
+ return self
76
+
77
+ end
78
+
79
+ def hashed_id
80
+
81
+ return Digest::SHA1.hexdigest uri || url || to_s
82
+
83
+ end
84
+
85
+ def to_hash
86
+
87
+ raise "Not Implemented!"
88
+
89
+ return {}
90
+
91
+ end
92
+
93
+ def to_rdf
94
+
95
+ raise "Not Implemented!"
96
+
97
+ return
98
+
99
+ end
100
+
101
+ def to_xml
102
+
103
+ raise "Not Implemented!"
104
+
105
+ return
106
+
107
+ end
108
+
109
+ def source_xml
110
+
111
+ return @source_xml
112
+
113
+ end
114
+
115
+ def parsed_xml
116
+
117
+ prepare_xml(@noko) if @noko.kind_of? String
118
+
119
+ return @noko
120
+
121
+ end
122
+
123
+ def purge_xml(cascade=true)
124
+
125
+ @noko = nil
126
+ @source_xml = nil
127
+
128
+ cascade_method(:purge_xml, true) if cascade
129
+
130
+ end
131
+
132
+ def textify_xml(cascade=true)
133
+
134
+ @noko = @noko.to_s
135
+
136
+ cascade_method(:textify_xml, true) if cascade
137
+
138
+ end
139
+
140
+ def from_xml(xml, target=nil, options={})
141
+
142
+ prepare_xml(xml)
143
+ select_xml(target, options)
144
+ parse_xml
145
+ purge_xml if ::Shibkit::MetaMeta.config.purge_xml?
146
+
147
+ end
148
+
149
+ private
150
+
151
+ def cascade_method(method_name, *params)
152
+
153
+ method_name = method_name.to_sym
154
+
155
+ self.instance_variables.each do |attr_name|
156
+
157
+ obj = instance_variable_get attr_name.to_sym
158
+
159
+ values = obj.values if obj.respond_to? :values
160
+ values ||= [obj].flatten
161
+
162
+ values.each do |value|
163
+
164
+ if value.respond_to? method_name
165
+
166
+ value.send method_name, *params
167
+
168
+ end
169
+
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+
176
+ ## Logging
177
+ def log
178
+
179
+ return ::Shibkit::MetaMeta.config.logger
180
+
181
+ end
182
+
183
+ ## Make sure we have consistent Nokogiri document whether string or Nokogiri passed
184
+ def prepare_xml(xml)
185
+
186
+ if xml.kind_of? String
187
+
188
+ ## Parse the entire file as an XML document
189
+ doc = Nokogiri::XML.parse(xml) do |config|
190
+ #config.strict.noent.dtdvalid
191
+ config.default_xml.nonet
192
+ end
193
+
194
+ @noko = doc.root
195
+
196
+ ## Add exotic namespaces to make sure we can deal with all metadata
197
+ NAMESPACES.each_pair { |label, uri| @noko.add_namespace_definition(label,uri) }
198
+
199
+ @source_xml = xml if ::Shibkit::MetaMeta.config.remember_source_xml?
200
+
201
+ end
202
+
203
+ @noko ||= xml
204
+
205
+ ## Make sure we get an element object...
206
+ @noko = @noko.at('/') if @noko.kind_of? Nokogiri::XML::NodeSet
207
+ @noko = @noko.root if @noko.kind_of? Nokogiri::XML::Document
208
+
209
+ raise "Unsuitable data!" unless @noko and @noko.respond_to? 'name'
210
+
211
+ end
212
+
213
+ ## If a target is specified select first matching node, otherwise just grab first node of type
214
+ def select_xml(target=nil, options={})
215
+
216
+ unless @noko.name == self.class::ROOT_ELEMENT ## and check for target too
217
+
218
+ if target and TARGET_ATTR
219
+ selector = "xmlns:#{self.class::ROOT_ELEMENT}[@#{self.class::TARGET_ATTR}='#{target}'][1]"
220
+ @noko = @noko.xpath(selector)[0]
221
+ else
222
+ selector = "xmlns:#{self.class::ROOT_ELEMENT}[1]"
223
+ @noko = @noko.xpath(selector)[0]
224
+ end
225
+
226
+ raise "No suitable XML was selected: using #{selector}" unless @noko and
227
+ @noko.kind_of?(Nokogiri::XML::Element) and @noko.name
228
+
229
+ end
230
+
231
+ end
232
+
233
+ ## Process XML to define object attributes
234
+ def parse_xml
235
+
236
+ raise "parse_xml method has not been implemented in this class"
237
+
238
+ end
239
+
240
+
241
+
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,127 @@
1
+ ## @author Pete Birkinshaw (<pete@digitalidentitylabs.com>)
2
+ ## Copyright: Copyright (c) 2011 Digital Identity Ltd.
3
+ ## License: Apache License, Version 2.0
4
+
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ##
17
+
18
+ module Shibkit
19
+ class MetaMeta
20
+
21
+ module Mixin
22
+
23
+ ## A few simple utility functions for slurping data from XML
24
+ ##
25
+ module CachedDownloads
26
+
27
+ require 'rest_client'
28
+ require 'restclient/components'
29
+ require 'rack/cache'
30
+ require 'rack/commonlogger'
31
+ require 'rbconfig'
32
+ require 'tempfile'
33
+ require 'addressable/uri'
34
+ require 'fileutils'
35
+
36
+
37
+ ## Automatically add class methods to the including class
38
+ def self.included(receiver)
39
+
40
+ receiver.extend(CDClassMethods)
41
+
42
+ end
43
+
44
+ ## Copy a filesystem file into the working directory (slower but safer)
45
+ def fetch_local(filename)
46
+
47
+ return unless filename
48
+
49
+ file_path = ::File.expand_path(filename)
50
+ raise "Can't access file #{file_path}!" unless ::File.exists?(file_path) and
51
+ ::File.readable?(file_path)
52
+
53
+ file = Tempfile.new(Time.new.to_i.to_s)
54
+ open(file_path, 'w') { |f| f << http_response.to_s }
55
+
56
+ return file
57
+
58
+ end
59
+
60
+ ## Copy a remote file into the working directory, also caching it for next update
61
+ def fetch_remote(url)
62
+
63
+ self.class.init_caches
64
+
65
+ http_response = RestClient.get(url)
66
+
67
+ file = Tempfile.new(Time.new.to_i.to_s)
68
+ open(file.path, 'w') { |f| f << http_response.to_s }
69
+
70
+ return file
71
+
72
+ end
73
+
74
+ ## Class methods to mixin to including class
75
+ module CDClassMethods
76
+
77
+ ##
78
+ ## Class Methods
79
+ ##
80
+
81
+ public
82
+
83
+ ## Create the web cache
84
+ def init_caches
85
+
86
+ @initialised_caches ||= false
87
+
88
+ ## Because these long class names are pain to keep typing
89
+ config = ::Shibkit::MetaMeta.config
90
+
91
+ unless @initialised_caches
92
+
93
+
94
+ ## JIT loading of the Cache module so we can set options first
95
+ RestClient.enable Rack::Cache, config.download_cache_options
96
+
97
+ ## Allow user to write log of all downloads in a standard format
98
+ if config.downloads_logger
99
+
100
+ RestClient.enable Rack::CommonLogger, config.downloads_logger
101
+
102
+ else
103
+
104
+ RestClient.disable Rack::CommonLogger
105
+
106
+ end
107
+
108
+
109
+ @initialised_caches = true
110
+
111
+ end
112
+
113
+ ## Helps if the locations actually exist, of course.
114
+ FileUtils.mkdir_p File.join(config.cache_root, 'meta')
115
+ FileUtils.mkdir_p File.join(config.cache_root, 'body')
116
+
117
+ end
118
+
119
+
120
+
121
+
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
@@ -0,0 +1,111 @@
1
+ ## @author Pete Birkinshaw (<pete@digitalidentitylabs.com>)
2
+ ## Copyright: Copyright (c) 2011 Digital Identity Ltd.
3
+ ## License: Apache License, Version 2.0
4
+
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ##
17
+
18
+ module Shibkit
19
+ class MetaMeta
20
+
21
+ module Mixin
22
+
23
+ ## A few simple utility functions for slurping data from XML
24
+ ##
25
+ module XPathChores
26
+
27
+ private
28
+
29
+ ## Return array of element contents when given xpath
30
+ def extract_simple_list(xpath)
31
+
32
+ results = Array.new
33
+
34
+ @noko.xpath(xpath).each do |ix|
35
+
36
+ results << ix.content.to_s.strip
37
+
38
+ end
39
+
40
+ return results
41
+
42
+ end
43
+
44
+ ## Language-mapped Hash
45
+ def extract_lang_map_of_strings(xpath)
46
+
47
+ results = Hash.new
48
+ results[:en] = Array.new
49
+
50
+
51
+ @noko.xpath(xpath).each do |ix|
52
+
53
+ lang = ix['lang'] || :en
54
+ results[lang.to_sym] = ix.content.strip.squeeze('')
55
+
56
+ end
57
+
58
+ return results
59
+
60
+ end
61
+
62
+ ## Language-mapped Hash of string lists
63
+ def extract_lang_map_of_string_lists(xpath)
64
+
65
+ results = Hash.new
66
+ results[:en] = Array.new
67
+
68
+ @noko.xpath(xpath).each do |ix|
69
+
70
+ items = ix.content.split(' ')
71
+ items.each { |item| item.gsub!('+',' ') }
72
+
73
+ lang = ix['lang'] || :en
74
+ results[lang.to_sym] = items
75
+
76
+ end
77
+
78
+ return results
79
+
80
+ end
81
+
82
+ ## Language-mapped Hash
83
+ def extract_lang_map_of_objects(xpath, req_class)
84
+
85
+ results = Hash.new
86
+ results[:en] = Array.new
87
+
88
+ @noko.xpath(xpath).each do |ix|
89
+
90
+ case req_class.respond_to?(:filter)
91
+ when true
92
+ obj = req_class.new(ix).filter
93
+ when false
94
+ obj = req_class.new(ix)
95
+ end
96
+
97
+ if obj
98
+ lang = ix['lang'] || :en
99
+ results[lang] ||= Array.new
100
+ results[lang] << obj
101
+ end
102
+
103
+ end
104
+
105
+ return results
106
+
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end