shibkit-meta_meta 0.2.2

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 (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