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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +52 -0
- data/Icon.png +0 -0
- data/LICENSE.txt +177 -0
- data/README.md +789 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/examples/biggest_entity_id.rb +4 -0
- data/lib/shibkit/meta_meta.rb +600 -0
- data/lib/shibkit/meta_meta/attribute.rb +73 -0
- data/lib/shibkit/meta_meta/config.rb +463 -0
- data/lib/shibkit/meta_meta/contact.rb +85 -0
- data/lib/shibkit/meta_meta/data/default_metadata/example_federation_metadata.xml +168 -0
- data/lib/shibkit/meta_meta/data/default_metadata/local_metadata.xml +66 -0
- data/lib/shibkit/meta_meta/data/default_metadata/uncommon_federation_metadata.xml +115 -0
- data/lib/shibkit/meta_meta/data/default_metadata_cache.yml +166 -0
- data/lib/shibkit/meta_meta/data/dev_sources.yml +86 -0
- data/lib/shibkit/meta_meta/data/real_sources.yml +163 -0
- data/lib/shibkit/meta_meta/entity.rb +219 -0
- data/lib/shibkit/meta_meta/federation.rb +161 -0
- data/lib/shibkit/meta_meta/idp.rb +81 -0
- data/lib/shibkit/meta_meta/logo.rb +216 -0
- data/lib/shibkit/meta_meta/metadata_item.rb +244 -0
- data/lib/shibkit/meta_meta/mixin/cached_downloads.rb +127 -0
- data/lib/shibkit/meta_meta/mixin/xpath_chores.rb +111 -0
- data/lib/shibkit/meta_meta/organisation.rb +73 -0
- data/lib/shibkit/meta_meta/provider.rb +195 -0
- data/lib/shibkit/meta_meta/provisioning/base.rb +33 -0
- data/lib/shibkit/meta_meta/requested_attribute.rb +29 -0
- data/lib/shibkit/meta_meta/service.rb +94 -0
- data/lib/shibkit/meta_meta/source.rb +558 -0
- data/lib/shibkit/meta_meta/sp.rb +79 -0
- data/shibkit-meta_meta.gemspec +154 -0
- data/spec/meta_meta/attribute/token +0 -0
- data/spec/meta_meta/config/autoloading_and_refreshing_spec.rb +72 -0
- data/spec/meta_meta/config/code_nspec.rb +13 -0
- data/spec/meta_meta/config/configuration_spec.rb +30 -0
- data/spec/meta_meta/config/creation_spec.rb +43 -0
- data/spec/meta_meta/config/downloading_and_caching_settings_spec.rb +216 -0
- data/spec/meta_meta/config/env_platform_settings.rb +129 -0
- data/spec/meta_meta/config/filtering_settings_spec.rb +123 -0
- data/spec/meta_meta/config/init.rb +8 -0
- data/spec/meta_meta/config/logger_settings_spec.rb +91 -0
- data/spec/meta_meta/config/smartcache_settings_spec.rb +110 -0
- data/spec/meta_meta/config/source_file_settings_spec.rb +99 -0
- data/spec/meta_meta/config/tagging_settings_spec.rb +81 -0
- data/spec/meta_meta/config/working_directory_settings_spec.rb +106 -0
- data/spec/meta_meta/config/xml_processing_settings_spec.rb +75 -0
- data/spec/meta_meta/contact/contact_oldspec.rb +0 -0
- data/spec/meta_meta/entity/entity_oldspec.rb +53 -0
- data/spec/meta_meta/federation/federation_oldspec.rb +0 -0
- data/spec/meta_meta/idp/token +0 -0
- data/spec/meta_meta/logo/token +0 -0
- data/spec/meta_meta/meta_meta/cache_example.yaml +141284 -0
- data/spec/meta_meta/meta_meta/meta_meta_spec.rb +269 -0
- data/spec/meta_meta/meta_meta/saved_sources.yaml +46 -0
- data/spec/meta_meta/metadata_item/token +0 -0
- data/spec/meta_meta/organisation/organisation_oldspec.rb +0 -0
- data/spec/meta_meta/provider/token +0 -0
- data/spec/meta_meta/requested_attribute/token +0 -0
- data/spec/meta_meta/service/token +0 -0
- data/spec/meta_meta/source/application_extras_spec.rb +234 -0
- data/spec/meta_meta/source/conversion_spec.rb +75 -0
- data/spec/meta_meta/source/creation_spec.rb +0 -0
- data/spec/meta_meta/source/downloads_and_caching_spec.rb +0 -0
- data/spec/meta_meta/source/federation_information_spec.rb +11 -0
- data/spec/meta_meta/source/fixtures.rb +24 -0
- data/spec/meta_meta/source/init.rb +1 -0
- data/spec/meta_meta/source/loading_and_saving_spec.rb +0 -0
- data/spec/meta_meta/source/metadata_details_spec.rb +0 -0
- data/spec/meta_meta/source/metadata_integrity_spec.rb +0 -0
- data/spec/meta_meta/source/selection_spec.rb +0 -0
- data/spec/meta_meta/source/source_oldspec.rb +353 -0
- data/spec/meta_meta/source/xml_parsing_spec.rb +0 -0
- data/spec/meta_meta/sp/token +0 -0
- data/spec/meta_meta/template +2 -0
- data/spec/moi/config_spec.rb +0 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/supply_xml.rb +0 -0
- metadata +320 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler'
|
|
5
|
+
begin
|
|
6
|
+
Bundler.setup(:default, :development)
|
|
7
|
+
rescue Bundler::BundlerError => e
|
|
8
|
+
$stderr.puts e.message
|
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
10
|
+
exit e.status_code
|
|
11
|
+
end
|
|
12
|
+
require 'rake'
|
|
13
|
+
|
|
14
|
+
require 'jeweler'
|
|
15
|
+
Jeweler::Tasks.new do |gem|
|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
17
|
+
gem.name = "shibkit-meta_meta"
|
|
18
|
+
gem.homepage = "https://github.com/Digital-Identity-Labs/shibkit-meta_meta"
|
|
19
|
+
gem.license = "Apache 2.0"
|
|
20
|
+
gem.summary = %Q{Downloads and parses Shibboleth (SAML2) metadata.}
|
|
21
|
+
gem.description = %Q{Utilities for friendly handling of Shibboleth/SAML2 metadata. Easily download and parse metadata XML into Ruby objects.}
|
|
22
|
+
gem.email = "gems@digitalidentitylabs.com"
|
|
23
|
+
gem.authors = ["Pete Birkinshaw"]
|
|
24
|
+
gem.files.exclude 'lib/scratch_test.rb'
|
|
25
|
+
# dependencies defined in Gemfile
|
|
26
|
+
end
|
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
require 'rspec/core'
|
|
31
|
+
require 'rspec/core/rake_task'
|
|
32
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
33
|
+
##
|
|
34
|
+
spec.pattern = FileList['spec/**/**/*_spec.rb']
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
task :default => :spec
|
|
38
|
+
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.2.2
|
|
@@ -0,0 +1,600 @@
|
|
|
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
|
+
require 'rubygems'
|
|
19
|
+
|
|
20
|
+
require 'nokogiri'
|
|
21
|
+
require 'yaml'
|
|
22
|
+
require 'open-uri'
|
|
23
|
+
require 'logger'
|
|
24
|
+
require 'fileutils'
|
|
25
|
+
require 'digest/sha1'
|
|
26
|
+
|
|
27
|
+
require 'shibkit/meta_meta/config'
|
|
28
|
+
require 'shibkit/meta_meta/metadata_item'
|
|
29
|
+
require 'shibkit/meta_meta/contact'
|
|
30
|
+
require 'shibkit/meta_meta/source'
|
|
31
|
+
require 'shibkit/meta_meta/entity'
|
|
32
|
+
require 'shibkit/meta_meta/federation'
|
|
33
|
+
require 'shibkit/meta_meta/organisation'
|
|
34
|
+
|
|
35
|
+
module Shibkit
|
|
36
|
+
|
|
37
|
+
## Simple library to parse Shibboleth metadata files into Ruby objects
|
|
38
|
+
class MetaMeta
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
def self.config(&block)
|
|
42
|
+
|
|
43
|
+
if block
|
|
44
|
+
return ::Shibkit::MetaMeta::Config.instance.configure(&block)
|
|
45
|
+
else
|
|
46
|
+
return ::Shibkit::MetaMeta::Config.instance
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
## Flush out all available sources, metadata caches, etc.
|
|
52
|
+
def self.reset
|
|
53
|
+
|
|
54
|
+
log.info "Resetting all sources, metadata caches, etc."
|
|
55
|
+
|
|
56
|
+
## Clear the source data
|
|
57
|
+
@additional_sources = Hash.new
|
|
58
|
+
@loaded_sources = Hash.new
|
|
59
|
+
|
|
60
|
+
## Clear federation entity data
|
|
61
|
+
self.flush
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
## Clear all loaded entity & federation data
|
|
66
|
+
def self.flush
|
|
67
|
+
|
|
68
|
+
log.info "Flushing all loaded objects"
|
|
69
|
+
|
|
70
|
+
@orgs = Array.new
|
|
71
|
+
@entities = Array.new
|
|
72
|
+
@federations = Array.new
|
|
73
|
+
@by_uri = Hash.new
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
## Delete all cache files
|
|
78
|
+
def self.delete_all_cached_files!
|
|
79
|
+
|
|
80
|
+
dir = config.cache_root
|
|
81
|
+
|
|
82
|
+
if config.can_delete?
|
|
83
|
+
|
|
84
|
+
log.info "Deleting all files at #{dir}..."
|
|
85
|
+
FileUtils.rm_rf dir
|
|
86
|
+
FileUtils.mkdir_p dir
|
|
87
|
+
|
|
88
|
+
else
|
|
89
|
+
|
|
90
|
+
log.warn "Cannot delete files at #{dir} - check config settings."
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
## Convenience method to add a source from a hash or object
|
|
97
|
+
def self.add_source(data)
|
|
98
|
+
|
|
99
|
+
@additional_sources ||= Hash.new
|
|
100
|
+
|
|
101
|
+
case data
|
|
102
|
+
when Hash
|
|
103
|
+
source = Source.from_hash(data)
|
|
104
|
+
when ::Shibkit::MetaMeta::Source
|
|
105
|
+
source = data
|
|
106
|
+
else
|
|
107
|
+
raise "Expected either hash or Source object!"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
log.info "Added a source for #{source.uri}"
|
|
111
|
+
|
|
112
|
+
@additional_sources[source.uri] = source
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
## Have we loaded any sources?
|
|
117
|
+
def self.loaded_sources?
|
|
118
|
+
|
|
119
|
+
return @loaded_sources ? true : false
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
## Load sources from a YAML file
|
|
124
|
+
def self.load_sources(filename=self.config.sources_file)
|
|
125
|
+
|
|
126
|
+
log.info "Loading sources from disk..."
|
|
127
|
+
|
|
128
|
+
@loaded_sources = Hash.new
|
|
129
|
+
|
|
130
|
+
Source.load(filename).each do |source|
|
|
131
|
+
|
|
132
|
+
## More than one definition for a source is a problem
|
|
133
|
+
raise "Duplicate source for #{source.uri}!" if @loaded_sources[source.uri]
|
|
134
|
+
|
|
135
|
+
@loaded_sources[source.uri] = source
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
## Save all known sources to sources list file
|
|
142
|
+
def self.save_sources(filename)
|
|
143
|
+
|
|
144
|
+
log.info "Saving sources to #{filename}..."
|
|
145
|
+
|
|
146
|
+
src_dump = Hash.new
|
|
147
|
+
self.sources.each { |s| src_dump[s.uri] = s.to_hash }
|
|
148
|
+
|
|
149
|
+
File.open(filename, 'w') { |out| YAML.dump(src_dump, out) }
|
|
150
|
+
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
## List all sources as an array
|
|
154
|
+
def self.sources
|
|
155
|
+
|
|
156
|
+
if self.config.autoload? and loaded_sources.size == 0 and additional_sources.size == 0
|
|
157
|
+
|
|
158
|
+
self.load_sources
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
all_sources_indexed = loaded_sources.merge(additional_sources)
|
|
163
|
+
|
|
164
|
+
sources = all_sources_indexed.values
|
|
165
|
+
|
|
166
|
+
sources = sources.sort {|a,b| a.created_at <=> b.created_at }
|
|
167
|
+
|
|
168
|
+
if self.filtered_sources?
|
|
169
|
+
|
|
170
|
+
sources = sources.select { |s| self.selected_federation_uris.include? s.uri }
|
|
171
|
+
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
return sources
|
|
175
|
+
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
## List of federation/collection uris
|
|
179
|
+
def self.selected_federation_uris
|
|
180
|
+
|
|
181
|
+
return self.config.selected_federation_uris
|
|
182
|
+
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
## Has a limited subset of federations/sources been selected?
|
|
186
|
+
def self.filtered_sources?
|
|
187
|
+
|
|
188
|
+
return self.selected_federation_uris.empty? ? false : true
|
|
189
|
+
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
## Loads federation metadata contents
|
|
193
|
+
def self.load_cache_file(file_or_url, format=:yaml)
|
|
194
|
+
|
|
195
|
+
self.reset
|
|
196
|
+
|
|
197
|
+
log.info "Loading object cache file from #{file_or_url} as #{format} data..."
|
|
198
|
+
|
|
199
|
+
@federations = case format
|
|
200
|
+
when :yaml
|
|
201
|
+
YAML.load(File.open(file_or_url))
|
|
202
|
+
when :marshal
|
|
203
|
+
Marshal.load(File.open(file_or_url))
|
|
204
|
+
else
|
|
205
|
+
raise "Unexpected cache file format requested! Please use :yaml or :marshal"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
self.entities
|
|
209
|
+
|
|
210
|
+
log.info "Processing complete."
|
|
211
|
+
|
|
212
|
+
return true
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
## Save entity data into a YAML file.
|
|
217
|
+
def self.save_cache_file(file_path, format=:yaml)
|
|
218
|
+
|
|
219
|
+
log.info "Saving object cache file to #{file_path} as #{format} data..."
|
|
220
|
+
|
|
221
|
+
## Will *not* overwrite the example/default file in gem! TODO: this code is awful.
|
|
222
|
+
gem_data_path = "#{::File.dirname(__FILE__)}/data"
|
|
223
|
+
if file_path.include? gem_data_path
|
|
224
|
+
raise "Attempt to overwrite gem's default metadata cache! Please specify your own file to save cache in"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
self.textify_xml!
|
|
228
|
+
|
|
229
|
+
## Write the YAML to disk
|
|
230
|
+
File.open(file_path, 'w') do |out|
|
|
231
|
+
|
|
232
|
+
case format
|
|
233
|
+
when :yaml
|
|
234
|
+
YAML.dump(@federations, out)
|
|
235
|
+
when :marshal
|
|
236
|
+
Marshal.dump(@federations, out)
|
|
237
|
+
else
|
|
238
|
+
raise "Unexpected cache file format requested! Please use :yaml or :marshal"
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
return true
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
## Parses sources and returns an array of all federation object
|
|
248
|
+
def self.process_sources
|
|
249
|
+
|
|
250
|
+
if config.smartcache_active?
|
|
251
|
+
return if self.smartcache_load
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
log.info "Processing content of sources into objects..."
|
|
255
|
+
|
|
256
|
+
raise "MetaMeta sources are not an Array! (Should not be a #{self.sources.class})" unless
|
|
257
|
+
self.sources.kind_of? Array
|
|
258
|
+
|
|
259
|
+
self.flush
|
|
260
|
+
|
|
261
|
+
self.sources.each do |source|
|
|
262
|
+
|
|
263
|
+
if self.filtered_sources?
|
|
264
|
+
|
|
265
|
+
next unless self.selected_federation_uris.include? source.uri
|
|
266
|
+
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
start_time = Time.new
|
|
270
|
+
|
|
271
|
+
federation = source.to_federation
|
|
272
|
+
|
|
273
|
+
## Store all federations in array
|
|
274
|
+
@federations << federation
|
|
275
|
+
|
|
276
|
+
log.info "Loaded #{federation.entities.count} entities from #{federation} metadata file in #{Time.new - start_time} seconds."
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
## Bodge to make sure primary ents are set, multifederation calculated, etc
|
|
282
|
+
#self.entities # Issue 14
|
|
283
|
+
|
|
284
|
+
log.info "Processing complete. #{@federations.count} sets of metadata have been loaded."
|
|
285
|
+
|
|
286
|
+
self.smartcache_save if config.smartcache_active?
|
|
287
|
+
|
|
288
|
+
return @federations
|
|
289
|
+
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
## Downloads and reprocesses metadata files
|
|
293
|
+
def self.refresh(force=false)
|
|
294
|
+
|
|
295
|
+
log.info "Refreshing all selected federations"
|
|
296
|
+
|
|
297
|
+
## Reload source lists overwriting previous set
|
|
298
|
+
self.load_sources
|
|
299
|
+
|
|
300
|
+
## Reprocess sources to create fresh set of federation and entity objects
|
|
301
|
+
self.process_sources
|
|
302
|
+
|
|
303
|
+
return true
|
|
304
|
+
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def self.stockup(force=false)
|
|
308
|
+
|
|
309
|
+
if self.config.autoload?
|
|
310
|
+
|
|
311
|
+
self.process_sources unless @federations
|
|
312
|
+
self.process_sources if @federations.empty?
|
|
313
|
+
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
## Have objects been loaded from metadata?
|
|
319
|
+
def self.stocked?
|
|
320
|
+
|
|
321
|
+
return false unless @federations
|
|
322
|
+
return false if @federations.empty?
|
|
323
|
+
|
|
324
|
+
return true
|
|
325
|
+
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
## Return list of Federations objects (filtered if select_federations is set)
|
|
329
|
+
def self.federations
|
|
330
|
+
|
|
331
|
+
return [] if @federations.nil? and ! config.autoload?
|
|
332
|
+
|
|
333
|
+
self.stockup
|
|
334
|
+
|
|
335
|
+
if self.filtered_sources?
|
|
336
|
+
|
|
337
|
+
return @federations.select { |f| self.selected_federation_uris.include? f.uri }
|
|
338
|
+
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
return @federations
|
|
342
|
+
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
## All primary entities from all federations
|
|
346
|
+
def self.entities
|
|
347
|
+
|
|
348
|
+
return [] if @entities.nil? and ! config.autoload?
|
|
349
|
+
|
|
350
|
+
## Populate memoised array of entities if it's empty
|
|
351
|
+
unless @entities and @entities.size > 0
|
|
352
|
+
|
|
353
|
+
## Array for memoising primary entities
|
|
354
|
+
@entities ||= Array.new
|
|
355
|
+
|
|
356
|
+
## For keeping track of already processed entities & marking them as primary
|
|
357
|
+
processed = Hash.new
|
|
358
|
+
|
|
359
|
+
self.federations.each do |f|
|
|
360
|
+
|
|
361
|
+
f.entities.each do |e|
|
|
362
|
+
|
|
363
|
+
## If we've already found the primary version of the entity
|
|
364
|
+
if processed[e.uri]
|
|
365
|
+
|
|
366
|
+
## Add this federation's URI to the primary
|
|
367
|
+
primary = processed[e.uri]
|
|
368
|
+
primary.other_federation_uris << f.uri
|
|
369
|
+
|
|
370
|
+
## Add tags from the non-primary to the primary
|
|
371
|
+
primary.tags << e.tags if config.merge_primary_tags?
|
|
372
|
+
|
|
373
|
+
next
|
|
374
|
+
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
## Mark this entity as the primary and remember it as already processed.
|
|
378
|
+
e.primary = true
|
|
379
|
+
processed[e.uri] = e
|
|
380
|
+
|
|
381
|
+
## Collect entity
|
|
382
|
+
@entities << e
|
|
383
|
+
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
## BODGE: Needs a better fix. Issue 14
|
|
389
|
+
#@entities = @entities.compact
|
|
390
|
+
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
return @entities
|
|
394
|
+
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def self.orgs
|
|
398
|
+
|
|
399
|
+
unless @orgs and @orgs.size > 0
|
|
400
|
+
|
|
401
|
+
@orgs ||= Array.new
|
|
402
|
+
|
|
403
|
+
processed = Hash.new
|
|
404
|
+
|
|
405
|
+
self.entities.each do |e|
|
|
406
|
+
|
|
407
|
+
org = e.organisation
|
|
408
|
+
|
|
409
|
+
next unless org
|
|
410
|
+
next if processed[org.druid]
|
|
411
|
+
|
|
412
|
+
@orgs << org
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
processed[org.druid] = true
|
|
416
|
+
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
@orgs.sort! {|a,b| a.druid <=> b.druid }
|
|
420
|
+
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
return @orgs
|
|
424
|
+
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
##
|
|
428
|
+
def self.idps
|
|
429
|
+
|
|
430
|
+
return entities.select { |e| e.idp? }
|
|
431
|
+
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
##
|
|
435
|
+
def self.sps
|
|
436
|
+
|
|
437
|
+
return entities.select { |e| e.sp? }
|
|
438
|
+
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def self.from_uri(uri)
|
|
442
|
+
|
|
443
|
+
unless @by_uri and @by_uri.size > 0
|
|
444
|
+
|
|
445
|
+
@by_uri ||= Hash.new
|
|
446
|
+
|
|
447
|
+
self.federations.each { |f| @by_uri[f.uri] = f unless @by_uri[f.uri] }
|
|
448
|
+
self.entities.each { |e| @by_uri[e.uri] = e unless @by_uri[e.uri] }
|
|
449
|
+
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
return @by_uri[uri]
|
|
453
|
+
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def self.textify_xml!
|
|
457
|
+
|
|
458
|
+
@federations.each { |f| f.textify_xml(true) }
|
|
459
|
+
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def self.purge_xml!
|
|
463
|
+
|
|
464
|
+
@federations.each { |f| f.purge_xml(true) }
|
|
465
|
+
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
private
|
|
469
|
+
|
|
470
|
+
## Logging
|
|
471
|
+
def self.log
|
|
472
|
+
|
|
473
|
+
return ::Shibkit::MetaMeta.config.logger
|
|
474
|
+
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
private
|
|
478
|
+
|
|
479
|
+
## Access to all additional sources
|
|
480
|
+
def self.additional_sources
|
|
481
|
+
|
|
482
|
+
@additional_sources ||= Hash.new
|
|
483
|
+
return @additional_sources
|
|
484
|
+
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
## Access to all additional sources
|
|
488
|
+
def self.loaded_sources
|
|
489
|
+
|
|
490
|
+
@loaded_sources ||= Hash.new
|
|
491
|
+
return @loaded_sources
|
|
492
|
+
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
##
|
|
496
|
+
def self.smartcache_load
|
|
497
|
+
|
|
498
|
+
log.info "Checking smartcache status..."
|
|
499
|
+
|
|
500
|
+
object_file = config.smartcache_object_file
|
|
501
|
+
scmd_file = config.smartcache_info_file
|
|
502
|
+
expiry_period = config.smartcache_expiry
|
|
503
|
+
|
|
504
|
+
## Do we even have a file?
|
|
505
|
+
return false unless File.exists? object_file
|
|
506
|
+
return false unless File.exists? scmd_file
|
|
507
|
+
|
|
508
|
+
start_time = Time.new
|
|
509
|
+
|
|
510
|
+
## Make sure the dump metadata is suitable
|
|
511
|
+
info = YAML.load(File.open(scmd_file))
|
|
512
|
+
|
|
513
|
+
## Check
|
|
514
|
+
cache_age = (Time.new.to_i - info[:created_at].to_i)
|
|
515
|
+
return false unless cache_age < expiry_period.to_i
|
|
516
|
+
|
|
517
|
+
return false unless info[:version] == config.version
|
|
518
|
+
|
|
519
|
+
return false unless info[:platform] == config.platform
|
|
520
|
+
|
|
521
|
+
return false unless info[:format] == :marshal
|
|
522
|
+
|
|
523
|
+
return false unless info[:object_file] == object_file
|
|
524
|
+
|
|
525
|
+
return false unless info[:purge_xml] == config.purge_xml?
|
|
526
|
+
return false unless info[:source_xml] == config.remember_source_xml?
|
|
527
|
+
return false unless info[:groups] == Digest::SHA1.hexdigest(config.selected_groups.join)
|
|
528
|
+
|
|
529
|
+
log.info "Smartcache is valid: loading objects..."
|
|
530
|
+
|
|
531
|
+
## If file does not exist (or is stale) and we have objects, save
|
|
532
|
+
self.load_cache_file(object_file, :marshal)
|
|
533
|
+
|
|
534
|
+
log.info "Loaded #{@federations.count} federations and #{@entities.count} entities from smartcache in #{Time.new - start_time} seconds."
|
|
535
|
+
|
|
536
|
+
return true
|
|
537
|
+
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
##
|
|
541
|
+
def self.smartcache_save
|
|
542
|
+
|
|
543
|
+
object_file = config.smartcache_object_file
|
|
544
|
+
scmd_file = config.smartcache_info_file
|
|
545
|
+
|
|
546
|
+
log.info "Saving smartcache with #{@federations.count} federations and #{@entities.count} entities..."
|
|
547
|
+
|
|
548
|
+
## Save file in fast marsh
|
|
549
|
+
mkdir_p config.cache_root unless File.exists? config.cache_root
|
|
550
|
+
self.save_cache_file(object_file, :marshal)
|
|
551
|
+
|
|
552
|
+
info = {
|
|
553
|
+
:created_at => Time.new,
|
|
554
|
+
:version => config.version,
|
|
555
|
+
:platform => config.platform,
|
|
556
|
+
:object_file => object_file,
|
|
557
|
+
:format => :marshal,
|
|
558
|
+
:purge_xml => config.purge_xml?,
|
|
559
|
+
:source_xml => config.remember_source_xml?,
|
|
560
|
+
:groups => Digest::SHA1.hexdigest(config.selected_groups.join)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
File.open(scmd_file, 'w') { |out| YAML.dump(info, out) }
|
|
564
|
+
|
|
565
|
+
log.info "Saved smartcache."
|
|
566
|
+
|
|
567
|
+
return true
|
|
568
|
+
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
## Stats
|
|
572
|
+
def self.stats
|
|
573
|
+
|
|
574
|
+
stats = Hash.new
|
|
575
|
+
|
|
576
|
+
stats[:federations] = Hash.new
|
|
577
|
+
|
|
578
|
+
self.federations.each do |f|
|
|
579
|
+
|
|
580
|
+
stats[:federations][f.uri] = Hash.new
|
|
581
|
+
stats[:federations][f.uri][:sp_count] = f.sps.count
|
|
582
|
+
stats[:federations][f.uri][:idp_count] = f.idps.count
|
|
583
|
+
stats[:federations][f.uri][:entities] = f.entities.count
|
|
584
|
+
stats[:federations][f.uri][:uri_count] = f.entities.collect {|e| e.uri}.uniq.count
|
|
585
|
+
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
stats[:federation_count] = self.federations.count
|
|
589
|
+
stats[:entities_count] = self.federations.inject(0) {|m,f| m+f.entities.count}
|
|
590
|
+
stats[:primary_entities_count] = self.entities.count
|
|
591
|
+
stats[:organisation_count] = self.orgs.count
|
|
592
|
+
|
|
593
|
+
return stats
|
|
594
|
+
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
end
|
|
600
|
+
end
|