class Shibkit::MetaMeta
Simple library to parse Shibboleth metadata files into Ruby objects
Public Class Methods
Convenience method to add a source from a hash or object
# File lib/shibkit/meta_meta.rb, line 97 def self.add_source(data) @additional_sources ||= Hash.new case data when Hash source = Source.from_hash(data) when ::Shibkit::MetaMeta::Source source = data else raise "Expected either hash or Source object!" end log.info "Added a source for #{source.uri}" @additional_sources[source.uri] = source end
# File lib/shibkit/meta_meta.rb, line 41 def self.config(&block) if block return ::Shibkit::MetaMeta::Config.instance.configure(&block) else return ::Shibkit::MetaMeta::Config.instance end end
Delete all cache files
# File lib/shibkit/meta_meta.rb, line 78 def self.delete_all_cached_files! dir = config.cache_root if config.can_delete? log.info "Deleting all files at #{dir}..." FileUtils.rm_rf dir FileUtils.mkdir_p dir else log.warn "Cannot delete files at #{dir} - check config settings." end end
All primary entities from all federations
# File lib/shibkit/meta_meta.rb, line 346 def self.entities return [] if @entities.nil? and ! config.autoload? ## Populate memoised array of entities if it's empty unless @entities and @entities.size > 0 ## Array for memoising primary entities @entities ||= Array.new ## For keeping track of already processed entities & marking them as primary processed = Hash.new self.federations.each do |f| f.entities.each do |e| ## If we've already found the primary version of the entity if processed[e.uri] ## Add this federation's URI to the primary primary = processed[e.uri] primary.other_federation_uris << f.uri ## Add tags from the non-primary to the primary primary.tags << e.tags if config.merge_primary_tags? next end ## Mark this entity as the primary and remember it as already processed. e.primary = true processed[e.uri] = e ## Collect entity @entities << e end end ## BODGE: Needs a better fix. Issue 14 #@entities = @entities.compact end return @entities end
Return list of Federations objects (filtered if select_federations is set)
# File lib/shibkit/meta_meta.rb, line 329 def self.federations return [] if @federations.nil? and ! config.autoload? self.stockup if self.filtered_sources? return @federations.select { |f| self.selected_federation_uris.include? f.uri } end return @federations end
Has a limited subset of federations/sources been selected?
# File lib/shibkit/meta_meta.rb, line 186 def self.filtered_sources? return self.selected_federation_uris.empty? ? false : true end
Clear all loaded entity & federation data
# File lib/shibkit/meta_meta.rb, line 66 def self.flush log.info "Flushing all loaded objects" @orgs = Array.new @entities = Array.new @federations = Array.new @by_uri = Hash.new end
# File lib/shibkit/meta_meta.rb, line 441 def self.from_uri(uri) unless @by_uri and @by_uri.size > 0 @by_uri ||= Hash.new self.federations.each { |f| @by_uri[f.uri] = f unless @by_uri[f.uri] } self.entities.each { |e| @by_uri[e.uri] = e unless @by_uri[e.uri] } end return @by_uri[uri] end
# File lib/shibkit/meta_meta.rb, line 428 def self.idps return entities.select { |e| e.idp? } end
Loads federation metadata contents
# File lib/shibkit/meta_meta.rb, line 193 def self.load_cache_file(file_or_url, format=:yaml) self.reset log.info "Loading object cache file from #{file_or_url} as #{format} data..." @federations = case format when :yaml YAML.load(File.open(file_or_url)) when :marshal Marshal.load(File.open(file_or_url)) else raise "Unexpected cache file format requested! Please use :yaml or :marshal" end self.entities log.info "Processing complete." return true end
Load sources from a YAML file
# File lib/shibkit/meta_meta.rb, line 124 def self.load_sources(filename=self.config.sources_file) log.info "Loading sources from disk..." @loaded_sources = Hash.new Source.load(filename).each do |source| ## More than one definition for a source is a problem raise "Duplicate source for #{source.uri}!" if @loaded_sources[source.uri] @loaded_sources[source.uri] = source end end
Have we loaded any sources?
# File lib/shibkit/meta_meta.rb, line 117 def self.loaded_sources? return @loaded_sources ? true : false end
# File lib/shibkit/meta_meta.rb, line 397 def self.orgs unless @orgs and @orgs.size > 0 @orgs ||= Array.new processed = Hash.new self.entities.each do |e| org = e.organisation next unless org next if processed[org.druid] @orgs << org processed[org.druid] = true end @orgs.sort! {|a,b| a.druid <=> b.druid } end return @orgs end
Parses sources and returns an array of all federation object
# File lib/shibkit/meta_meta.rb, line 248 def self.process_sources if config.smartcache_active? return if self.smartcache_load end log.info "Processing content of sources into objects..." raise "MetaMeta sources are not an Array! (Should not be a #{self.sources.class})" unless self.sources.kind_of? Array self.flush self.sources.each do |source| if self.filtered_sources? next unless self.selected_federation_uris.include? source.uri end start_time = Time.new federation = source.to_federation ## Store all federations in array @federations << federation log.info "Loaded #{federation.entities.count} entities from #{federation} metadata file in #{Time.new - start_time} seconds." end ## Bodge to make sure primary ents are set, multifederation calculated, etc #self.entities # Issue 14 log.info "Processing complete. #{@federations.count} sets of metadata have been loaded." self.smartcache_save if config.smartcache_active? return @federations end
# File lib/shibkit/meta_meta.rb, line 462 def self.purge_xml! @federations.each { |f| f.purge_xml(true) } end
Downloads and reprocesses metadata files
# File lib/shibkit/meta_meta.rb, line 293 def self.refresh(force=false) log.info "Refreshing all selected federations" ## Reload source lists overwriting previous set self.load_sources ## Reprocess sources to create fresh set of federation and entity objects self.process_sources return true end
Flush out all available sources, metadata caches, etc.
# File lib/shibkit/meta_meta.rb, line 52 def self.reset log.info "Resetting all sources, metadata caches, etc." ## Clear the source data @additional_sources = Hash.new @loaded_sources = Hash.new ## Clear federation entity data self.flush end
Save entity data into a YAML file.
# File lib/shibkit/meta_meta.rb, line 217 def self.save_cache_file(file_path, format=:yaml) log.info "Saving object cache file to #{file_path} as #{format} data..." ## Will *not* overwrite the example/default file in gem! TODO: this code is awful. gem_data_path = "#{::File.dirname(__FILE__)}/data" if file_path.include? gem_data_path raise "Attempt to overwrite gem's default metadata cache! Please specify your own file to save cache in" end self.textify_xml! ## Write the YAML to disk File.open(file_path, 'w') do |out| case format when :yaml YAML.dump(@federations, out) when :marshal Marshal.dump(@federations, out) else raise "Unexpected cache file format requested! Please use :yaml or :marshal" end end return true end
Save all known sources to sources list file
# File lib/shibkit/meta_meta.rb, line 142 def self.save_sources(filename) log.info "Saving sources to #{filename}..." src_dump = Hash.new self.sources.each { |s| src_dump[s.uri] = s.to_hash } File.open(filename, 'w') { |out| YAML.dump(src_dump, out) } end
List of federation/collection uris
# File lib/shibkit/meta_meta.rb, line 179 def self.selected_federation_uris return self.config.selected_federation_uris end
List all sources as an array
# File lib/shibkit/meta_meta.rb, line 154 def self.sources if self.config.autoload? and loaded_sources.size == 0 and additional_sources.size == 0 self.load_sources end all_sources_indexed = loaded_sources.merge(additional_sources) sources = all_sources_indexed.values sources = sources.sort {|a,b| a.created_at <=> b.created_at } if self.filtered_sources? sources = sources.select { |s| self.selected_federation_uris.include? s.uri } end return sources end
# File lib/shibkit/meta_meta.rb, line 435 def self.sps return entities.select { |e| e.sp? } end
Have objects been loaded from metadata?
# File lib/shibkit/meta_meta.rb, line 319 def self.stocked? return false unless @federations return false if @federations.empty? return true end
# File lib/shibkit/meta_meta.rb, line 307 def self.stockup(force=false) if self.config.autoload? self.process_sources unless @federations self.process_sources if @federations.empty? end end
# File lib/shibkit/meta_meta.rb, line 456 def self.textify_xml! @federations.each { |f| f.textify_xml(true) } end
Private Class Methods
Access to all additional sources
# File lib/shibkit/meta_meta.rb, line 480 def self.additional_sources @additional_sources ||= Hash.new return @additional_sources end
Access to all additional sources
# File lib/shibkit/meta_meta.rb, line 488 def self.loaded_sources @loaded_sources ||= Hash.new return @loaded_sources end
Logging
# File lib/shibkit/meta_meta.rb, line 471 def self.log return ::Shibkit::MetaMeta.config.logger end
# File lib/shibkit/meta_meta.rb, line 496 def self.smartcache_load log.info "Checking smartcache status..." object_file = config.smartcache_object_file scmd_file = config.smartcache_info_file expiry_period = config.smartcache_expiry ## Do we even have a file? return false unless File.exists? object_file return false unless File.exists? scmd_file start_time = Time.new ## Make sure the dump metadata is suitable info = YAML.load(File.open(scmd_file)) ## Check cache_age = (Time.new.to_i - info[:created_at].to_i) return false unless cache_age < expiry_period.to_i return false unless info[:version] == config.version return false unless info[:platform] == config.platform return false unless info[:format] == :marshal return false unless info[:object_file] == object_file return false unless info[:purge_xml] == config.purge_xml? return false unless info[:source_xml] == config.remember_source_xml? return false unless info[:groups] == Digest::SHA1.hexdigest(config.selected_groups.join) log.info "Smartcache is valid: loading objects..." ## If file does not exist (or is stale) and we have objects, save self.load_cache_file(object_file, :marshal) log.info "Loaded #{@federations.count} federations and #{@entities.count} entities from smartcache in #{Time.new - start_time} seconds." return true end
# File lib/shibkit/meta_meta.rb, line 541 def self.smartcache_save object_file = config.smartcache_object_file scmd_file = config.smartcache_info_file log.info "Saving smartcache with #{@federations.count} federations and #{@entities.count} entities..." ## Save file in fast marsh mkdir_p config.cache_root unless File.exists? config.cache_root self.save_cache_file(object_file, :marshal) info = { :created_at => Time.new, :version => config.version, :platform => config.platform, :object_file => object_file, :format => :marshal, :purge_xml => config.purge_xml?, :source_xml => config.remember_source_xml?, :groups => Digest::SHA1.hexdigest(config.selected_groups.join) } File.open(scmd_file, 'w') { |out| YAML.dump(info, out) } log.info "Saved smartcache." return true end
Stats
# File lib/shibkit/meta_meta.rb, line 572 def self.stats stats = Hash.new stats[:federations] = Hash.new self.federations.each do |f| stats[:federations][f.uri] = Hash.new stats[:federations][f.uri][:sp_count] = f.sps.count stats[:federations][f.uri][:idp_count] = f.idps.count stats[:federations][f.uri][:entities] = f.entities.count stats[:federations][f.uri][:uri_count] = f.entities.collect {|e| e.uri}.uniq.count end stats[:federation_count] = self.federations.count stats[:entities_count] = self.federations.inject(0) {|m,f| m+f.entities.count} stats[:primary_entities_count] = self.entities.count stats[:organisation_count] = self.orgs.count return stats end