shibboleths_lil_helper 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +16 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +199 -0
- data/Rakefile +54 -0
- data/TODOS.txt +15 -0
- data/VERSION +1 -0
- data/bin/slh +9 -0
- data/doc/debugging_shibboleth.markdown +8 -0
- data/doc/deprecated_code_that_could_be_useful.rb +32 -0
- data/doc/for_slh_developers.markdown +38 -0
- data/doc/nuances.markdown +13 -0
- data/doc/technical_question_and_answer.markdown +85 -0
- data/lib/shibboleths_lil_helper.rb +9 -0
- data/lib/slh.rb +17 -0
- data/lib/slh/class_methods.rb +83 -0
- data/lib/slh/cli.rb +140 -0
- data/lib/slh/cli/command_base.rb +32 -0
- data/lib/slh/cli/compare_metadata.rb +53 -0
- data/lib/slh/cli/copy_templates_to_override.rb +12 -0
- data/lib/slh/cli/describe_config.rb +75 -0
- data/lib/slh/cli/fetch_metadata.rb +27 -0
- data/lib/slh/cli/generate.rb +20 -0
- data/lib/slh/cli/generate_capistrano_deploy.rb +35 -0
- data/lib/slh/cli/generate_metadata.rb +53 -0
- data/lib/slh/cli/host_filterable_base.rb +16 -0
- data/lib/slh/cli/initialize.rb +30 -0
- data/lib/slh/cli/verify_metadata_encryption.rb +25 -0
- data/lib/slh/models/base.rb +23 -0
- data/lib/slh/models/host.rb +55 -0
- data/lib/slh/models/site.rb +139 -0
- data/lib/slh/models/site_path.rb +17 -0
- data/lib/slh/models/strategy.rb +131 -0
- data/lib/slh/models/version.rb +4 -0
- data/lib/slh/templates/_application_details.erb +33 -0
- data/lib/slh/templates/config.rb.erb +33 -0
- data/lib/slh/templates/deploy.rb.erb +42 -0
- data/lib/slh/templates/shib_apache.conf.erb +24 -0
- data/lib/slh/templates/shibboleth2.xml.erb +44 -0
- data/lib/slh/templates/sp_metadata_for_entity_id_to_give_to_idp.xml.erb +40 -0
- data/lib/slh/templates/sp_metadata_for_host_to_give_to_idp.xml.erb +33 -0
- data/shibboleths_lil_helper.gemspec +111 -0
- data/test/fixtures/dummy1.rb +15 -0
- data/test/fixtures/dummy1_output/attribute-map.xml +5 -0
- data/test/fixtures/dummy1_output/shib_for_vhost.conf +15 -0
- data/test/fixtures/dummy1_output/shibboleth2.xml +27 -0
- data/test/helper.rb +18 -0
- data/test/test_shibboleths_lil_helper.rb +105 -0
- metadata +211 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
class Slh::Cli::DescribeConfig < Slh::Cli::CommandBase
|
2
|
+
def default_options
|
3
|
+
{ :mode => :all, :filter => :none}
|
4
|
+
end
|
5
|
+
def option_parser
|
6
|
+
@valid_modes = %w(all hosts)
|
7
|
+
return OptionParser.new do |opts|
|
8
|
+
opts.on('-m','--mode MODE', "Can be #{@valid_modes.join(',')}, extracts specified info from shibboleths_lil_helper/config.rb") do |value|
|
9
|
+
unless @valid_modes.include?(value)
|
10
|
+
raise "invalid mode option passed, #{value}"
|
11
|
+
end
|
12
|
+
@options[:mode] = value.to_sym
|
13
|
+
end
|
14
|
+
opts.on('-f','--filter FILTER', "Output will be filtered by matching hosts if specified") do |value|
|
15
|
+
@options[:filter] = value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def perform_action
|
21
|
+
@output = []
|
22
|
+
case @options[:mode]
|
23
|
+
when :all
|
24
|
+
Slh.strategies.each do |strategy|
|
25
|
+
@output << strategy.name
|
26
|
+
strategy.hosts.each do |host|
|
27
|
+
next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
28
|
+
@output << " #{host.name} #{host.host_type}"
|
29
|
+
host.sites.each do |site|
|
30
|
+
@output << " #{site.name}"
|
31
|
+
site.paths.each do |path|
|
32
|
+
@output << " #{path.name} #{path.flavor}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
when :hosts
|
38
|
+
warn_on_multiple_strategies = false
|
39
|
+
host_strategy_mappings = {}
|
40
|
+
Slh.strategies.each do |strategy|
|
41
|
+
strategy.hosts.each do |host|
|
42
|
+
next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
43
|
+
host_strategy_mappings[host.name] ||= []
|
44
|
+
host_strategy_mappings[host.name] << strategy
|
45
|
+
end
|
46
|
+
end
|
47
|
+
host_strategy_mappings.each_pair do |host,strat_array|
|
48
|
+
if strat_array.length > 1
|
49
|
+
warn_on_multiple_strategies = true
|
50
|
+
@output << [host, {:highlight => :red}]
|
51
|
+
else
|
52
|
+
@output << host
|
53
|
+
end
|
54
|
+
strat_array.each_with_index do |strat,index|
|
55
|
+
@output << " ---#{index+1}---"
|
56
|
+
@output << " strategy name: #{strat.name}"
|
57
|
+
@output << " sp_entity_id #{strat.sp_entity_id}"
|
58
|
+
@output << " idp_metadata_url #{strat.idp_metadata_url}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if warn_on_multiple_strategies
|
62
|
+
@output << ["Make sure to check that the highlighted hosts with multiple strategies are configured correctly on your target hosts, only one can function correctly for a given host once deployed", {:highlight => :red}]
|
63
|
+
end
|
64
|
+
else
|
65
|
+
raise "invalid mode #{@options[:mode]}"
|
66
|
+
end
|
67
|
+
@output.each do |line|
|
68
|
+
if line.kind_of?(String) || line.kind_of?(Symbol)
|
69
|
+
Slh::Cli.instance.output line.to_s
|
70
|
+
elsif line.kind_of? Array
|
71
|
+
Slh::Cli.instance.output line[0], line[1]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Slh::Cli::FetchMetadata < Slh::Cli::HostFilterableBase
|
2
|
+
def perform_action
|
3
|
+
Slh.strategies.each do |strategy|
|
4
|
+
Slh::Cli.instance.output "Fetching metadata for all sites associated with strategy #{strategy.name}"
|
5
|
+
strategy.hosts.each do |host|
|
6
|
+
next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
7
|
+
host.sites.each do |site|
|
8
|
+
# Slh::Cli.instance.output "Writing fetched metadata for #{site.name} to \n #{site.fetched_metadata_path}"
|
9
|
+
FileUtils.mkdir_p(site.config_dir)
|
10
|
+
File.open(site.fetched_metadata_path,'w') do |f|
|
11
|
+
begin
|
12
|
+
f.write(site.metadata)
|
13
|
+
rescue Slh::Models::Site::CouldNotGetMetadata => e
|
14
|
+
Slh::Cli.instance.output "NOT FOUND metadata not found at #{site.metadata_url}", :highlight => :red
|
15
|
+
Slh::Cli.instance.output " Error message: #{e.message}"
|
16
|
+
next # skip this site
|
17
|
+
rescue Timeout::Error => e
|
18
|
+
Slh::Cli.instance.output " TIMEOUT at #{site.metadata_url}", :highlight => :red
|
19
|
+
Slh::Cli.instance.output " Remote metadata not available at #{site.metadata_url}, exception message: #{e.message}"
|
20
|
+
next # skip this site
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Slh::Cli::Generate < Slh::Cli::HostFilterableBase
|
2
|
+
def perform_action
|
3
|
+
Slh.strategies.each do |strategy|
|
4
|
+
Slh::Cli.instance.output "Generating Native SP config files for strategy #{strategy.name.to_s}"
|
5
|
+
FileUtils.rm_rf(strategy.config_dir)
|
6
|
+
FileUtils.mkdir_p(strategy.config_dir)
|
7
|
+
strategy.hosts.each do |host|
|
8
|
+
next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
9
|
+
Slh::Cli.instance.output " Generating host config for #{host.name}"
|
10
|
+
Slh::Models::Strategy::VALID_CONFIG_FILES.each do |cf|
|
11
|
+
next if host.host_type == :iis && cf == 'shib_apache.conf' # not needed
|
12
|
+
FileUtils.mkdir_p(host.config_dir)
|
13
|
+
File.open(strategy.config_file_path(cf,host), 'w') {|f| f.write(strategy.generate_config_file_content(cf,host)) }
|
14
|
+
Slh::Cli.instance.output " Wrote #{strategy.config_file_path(cf,host)}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
Slh::Cli.instance.output "You MUST deploy these files your web servers and restart httpd and shibd for subsequent commands to work", :highlight => true
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Slh::Cli::GenerateCapistranoDeploy < Slh::Cli::CommandBase
|
2
|
+
def default_options
|
3
|
+
{ }
|
4
|
+
end
|
5
|
+
def perform_action
|
6
|
+
Slh::Cli.instance.output "Generating a config/deploy.rb"
|
7
|
+
self.generate_deploy_dot_rb
|
8
|
+
Slh::Cli.instance.output "Will MUST change the TODO sections in this file and setup the symlinks correctly on your target servers for you to be able to do\ncap deploy HOST=somehost.com", :highlight => true
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def config_dir
|
13
|
+
'config'
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_deploy_dot_rb
|
17
|
+
file_path = File.join(self.config_dir, 'deploy.rb')
|
18
|
+
if File.exists?(file_path)
|
19
|
+
Slh::Cli.instance.output "#{file_path} already exists, MISSION ABORT.", :exit => true
|
20
|
+
end
|
21
|
+
FileUtils.mkdir_p(self.config_dir)
|
22
|
+
File.open(file_path, 'w') do |f|
|
23
|
+
f.write(self.generate_config_file_content)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def config_template_file_path
|
28
|
+
File.join(File.dirname(__FILE__), '..', 'templates','deploy.rb.erb')
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_config_file_content
|
32
|
+
ERB.new(File.read(self.config_template_file_path)).result(binding)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Slh::Cli::GenerateMetadata < Slh::Cli::HostFilterableBase
|
2
|
+
|
3
|
+
# def perform_action
|
4
|
+
# Slh.strategies.each do |strategy|
|
5
|
+
# strategy.hosts.each do |host|
|
6
|
+
# next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
7
|
+
# host_dir = strategy.config_dir_for_host(host)
|
8
|
+
# file_path = 'sp_metadata_for_host_to_give_to_idp.xml'
|
9
|
+
# @strategy = strategy
|
10
|
+
# @host = host
|
11
|
+
# # Global config shared across vhosts like the X509Certificate
|
12
|
+
# # uses the first site arbirarily
|
13
|
+
# @first_site_for_host = @host.sites.first
|
14
|
+
# Slh::Cli.instance.output "Generating metadata for #{host.name}"
|
15
|
+
# the_written_file = "sp_metadata_for_#{host.name.gsub(/[^a-zA-Z0-9\-_\.]/,'_')}.xml"
|
16
|
+
# the_written_path = File.join(host_dir, the_written_file)
|
17
|
+
# File.open(the_written_path,'w') do |f|
|
18
|
+
# f.write(ERB.new(strategy.config_template_content(file_path)).result(binding))
|
19
|
+
# Slh::Cli.instance.output "Wrote file to #{the_written_path}"
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
|
25
|
+
def perform_action
|
26
|
+
template_rel_file_path ='sp_metadata_for_entity_id_to_give_to_idp.xml'
|
27
|
+
Slh.strategies.each do |strategy|
|
28
|
+
Slh::Cli.instance.output "Generating #{template_rel_file_path} for strategy #{strategy.name}, sp_entity_id=#{strategy.sp_entity_id}"
|
29
|
+
if @options[:filter].kind_of?(String)
|
30
|
+
matching_hosts = strategy.hosts.select {|h| h.name.match(@options[:filter])}
|
31
|
+
if matching_hosts.empty?
|
32
|
+
Slh::Cli.instance.output "No hosts matched in this strategy for filter #{@options[:filter]}, aborting for this strategy", :highlight => :red
|
33
|
+
next
|
34
|
+
else
|
35
|
+
Slh::Cli.instance.output "#{matching_hosts.map {|x| x.name}.join(',')} hosts matched in this strategy for filter #{@options[:filter]}", :highlight => :green
|
36
|
+
end
|
37
|
+
else
|
38
|
+
matching_hosts = strategy.hosts
|
39
|
+
end
|
40
|
+
|
41
|
+
# expose vars for ERB template
|
42
|
+
@strategy = strategy
|
43
|
+
@matching_hosts = matching_hosts
|
44
|
+
# @options is also exposed to utilize the --filter option
|
45
|
+
|
46
|
+
file_path = File.join(strategy.config_dir,"#{strategy.name}_sp_metadata_for_idp.xml")
|
47
|
+
File.open(file_path,'w') do |f|
|
48
|
+
f.write(ERB.new(strategy.config_template_content(template_rel_file_path)).result(binding))
|
49
|
+
Slh::Cli::instance.output "Wrote metadata to\n #{file_path}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# An abstract class shared by generators that filter by host
|
2
|
+
# Generators that loop over hosts and want to support this form of filtering might consider
|
3
|
+
# extending from this class and use this code in their host iterator
|
4
|
+
# next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
5
|
+
class Slh::Cli::HostFilterableBase < Slh::Cli::CommandBase
|
6
|
+
def default_options
|
7
|
+
{:filter => :none}
|
8
|
+
end
|
9
|
+
def option_parser
|
10
|
+
return OptionParser.new do |opts|
|
11
|
+
opts.on('-f','--filter FILTER', "Output will be filtered by matching hosts if specified") do |value|
|
12
|
+
@options[:filter] = value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Slh::Cli::Initialize < Slh::Cli::CommandBase
|
2
|
+
def default_options
|
3
|
+
{ :force_create => false }
|
4
|
+
end
|
5
|
+
def option_parser
|
6
|
+
return OptionParser.new do |opts|
|
7
|
+
opts.on('-f','--force', "Destroy existing dir if exists") do
|
8
|
+
@options[:force_create] = true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def perform_action
|
13
|
+
Slh::Cli.instance.output "Generating shibboleths_lil_helper/config.rb as a starting point"
|
14
|
+
if self.options[:force_create]
|
15
|
+
if File.directory?(Slh.config_dir)
|
16
|
+
FileUtils.rm_rf(Slh.config_dir)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
begin
|
20
|
+
FileUtils.mkdir(Slh.config_dir)
|
21
|
+
rescue Exception => e
|
22
|
+
Slh::Cli.instance.output "Could not create directory, use --force option #{Slh.config_dir}", :exception => e
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
|
26
|
+
config_string = ERB.new(File.read(File.join(File.dirname(__FILE__),'..','templates','config.rb.erb'))).result(binding)
|
27
|
+
File.open(Slh.config_file,'w') {|f| f.write(config_string)}
|
28
|
+
Slh::Cli.instance.output "You should go edit #{Slh.config_file} to reflect your organizations Shib setup", :highlight => :red
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Slh::Cli::VerifyMetadataEncryption < Slh::Cli::HostFilterableBase
|
2
|
+
def perform_action
|
3
|
+
Slh.strategies.each do |strategy|
|
4
|
+
broken = false
|
5
|
+
Slh::Cli.instance.output "Iterating hosts for strategy #{strategy.name}"
|
6
|
+
key_originator_site = strategy.key_originator_site
|
7
|
+
strategy.hosts.each do |host|
|
8
|
+
next if @options[:filter].kind_of?(String) && !host.name.match(@options[:filter])
|
9
|
+
Slh::Cli.instance.output "Iterating sites for host #{host.name}"
|
10
|
+
host.sites.each do |site|
|
11
|
+
if key_originator_site.x509_certificate_string == site.x509_certificate_string
|
12
|
+
Slh::Cli.instance.output " X509Certificate matches for #{site.name} ", :highlight => :green
|
13
|
+
else
|
14
|
+
Slh::Cli.instance.output " Mismatching X509Certificate for #{site.name}, WILL NOT WORK", :highlight => :red
|
15
|
+
broken = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
if broken
|
20
|
+
Slh::Cli.instance.output "To fix issues highlighted above need to copy the sp-key.pem and sp-cert.pem files from host #{key_originator_site.parent_host.name} to the hosts associated with each of the sites listed above", :highlight => true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Slh::Models::Base
|
2
|
+
def set(attr_accessor_name, val)
|
3
|
+
self.send("#{attr_accessor_name}=",val)
|
4
|
+
end
|
5
|
+
|
6
|
+
# A wee-bit-o-meta-programming to dynamically create stuff you might want to expose
|
7
|
+
# and interpolate in templates
|
8
|
+
# http://blog.jayfields.com/2008/02/ruby-dynamically-define-method.html
|
9
|
+
# Allows stuff like
|
10
|
+
# # in config.rb
|
11
|
+
# set_custom :poo,'the_poo'
|
12
|
+
# # in a template
|
13
|
+
# <%= @strategy.poo -%> ---> will return "the_poo"
|
14
|
+
#
|
15
|
+
def set_custom(attr_accessor_name,val)
|
16
|
+
(class << self; self; end).class_eval do
|
17
|
+
define_method attr_accessor_name do
|
18
|
+
val
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return true
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# This model represents the actual hostname/machine the shib SP instance lives on
|
2
|
+
class Slh::Models::Host < Slh::Models::Base
|
3
|
+
##########################
|
4
|
+
# CORE API METHODS BEGIN #
|
5
|
+
##########################
|
6
|
+
def for_site(site_name, &block)
|
7
|
+
@sites << Slh::Models::Site.new(site_name,self, &block)
|
8
|
+
end
|
9
|
+
########################
|
10
|
+
# CORE API METHODS END #
|
11
|
+
########################
|
12
|
+
|
13
|
+
attr_reader :name, :sites, :parent_strategy
|
14
|
+
attr_accessor :host_type, :shib_prefix
|
15
|
+
def initialize(host_name,parent_strategy,&block)
|
16
|
+
@parent_strategy = parent_strategy
|
17
|
+
@name = host_name
|
18
|
+
@host_type = :apache
|
19
|
+
@sites = []
|
20
|
+
if block_given?
|
21
|
+
self.instance_eval(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
if self.sites.length == 0
|
25
|
+
raise "Misconfiguration on host=#{self.name}: You must define at least one site for a host even if it's the same name as the host"
|
26
|
+
end
|
27
|
+
if self.host_type == :iis
|
28
|
+
if self.sites.detect {|x| x.site_id.nil?}
|
29
|
+
raise "If your :host_type is iis, you must specify :site_id for all of your sites"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# File.join('', 'asdf.txt') returns '/asdf.txt'. We need a way to accomodate
|
36
|
+
# shib_prefix when needed, but avoiding values like '/shibboleth2.xml' when
|
37
|
+
# a prefix isn't set.
|
38
|
+
# For interpolation into templates
|
39
|
+
def prefixed_filepath_for(filename)
|
40
|
+
filepath = filename
|
41
|
+
unless @shib_prefix.nil?
|
42
|
+
filepath = File.join(@shib_prefix, filename)
|
43
|
+
end
|
44
|
+
filepath
|
45
|
+
end
|
46
|
+
|
47
|
+
def config_dir
|
48
|
+
File.join(self.parent_strategy.config_dir,self.name.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
# refers to the file within this checkout
|
52
|
+
def shibboleth2_path
|
53
|
+
File.join(self.config_dir,'shibboleth2.xml')
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
class Slh::Models::Site < Slh::Models::Base
|
2
|
+
##########################
|
3
|
+
# CORE API METHODS BEGIN #
|
4
|
+
##########################
|
5
|
+
def protect(site_path, &block)
|
6
|
+
if site_path == '/' && !@paths.empty?
|
7
|
+
raise "If you want to protect the entire site, you must specify \"protect '/'\" before all other site path rules"
|
8
|
+
end
|
9
|
+
@paths << Slh::Models::SitePath.new(site_path, self, &block)
|
10
|
+
end
|
11
|
+
##########################
|
12
|
+
# CORE API METHODS END #
|
13
|
+
##########################
|
14
|
+
class CouldNotGetMetadata < Exception; end
|
15
|
+
attr_reader :name, :paths, :parent_host
|
16
|
+
|
17
|
+
# This indicates the site is where all other sites get their encryption keys from
|
18
|
+
# and where the metadata X509Certificate comes from
|
19
|
+
attr_accessor :is_key_originator
|
20
|
+
|
21
|
+
# site_id is for hosts who's host_type == :iis
|
22
|
+
attr_accessor :site_id
|
23
|
+
def initialize(site_name,parent_host,&block)
|
24
|
+
@parent_host = parent_host
|
25
|
+
@name = site_name
|
26
|
+
@paths = []
|
27
|
+
self.is_key_originator = false
|
28
|
+
if block_given?
|
29
|
+
self.instance_eval(&block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def metadata
|
34
|
+
if @metadata.blank?
|
35
|
+
url = URI.parse(self.metadata_url)
|
36
|
+
http = Net::HTTP.new(url.host, url.port)
|
37
|
+
http.use_ssl = true
|
38
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
39
|
+
http.open_timeout = 5
|
40
|
+
http.read_timeout = 5
|
41
|
+
begin
|
42
|
+
the_metadata_for_site = http.get(url.path)
|
43
|
+
rescue
|
44
|
+
raise CouldNotGetMetadata.new("Could not https GET #{self.metadata_url}, have you deployed your generated shib config files to this machine and restarted shibd?")
|
45
|
+
end
|
46
|
+
case the_metadata_for_site
|
47
|
+
when Net::HTTPSuccess
|
48
|
+
@metadata = the_metadata_for_site.body
|
49
|
+
else
|
50
|
+
raise CouldNotGetMetadata.new("Got a non-200 http status code (actual=#{the_metadata_for_site.code}) from #{self.metadata_url}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@metadata
|
54
|
+
end
|
55
|
+
|
56
|
+
def metadata_nokogiri
|
57
|
+
if @metadata_nokogiri.blank?
|
58
|
+
@metadata_nokogiri = Nokogiri::XML(self.metadata)
|
59
|
+
end
|
60
|
+
@metadata_nokogiri
|
61
|
+
end
|
62
|
+
|
63
|
+
def metadata_url
|
64
|
+
"#{self.to_https_prefixed_name}/Shibboleth.sso/Metadata"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Gets interpolated into the sp_metadata_for_host_to_give_to_idp.xml
|
68
|
+
# file
|
69
|
+
def x509_certificate_string
|
70
|
+
t=self.metadata_nokogiri.clone
|
71
|
+
t.remove_namespaces!
|
72
|
+
the_xpath = "//KeyDescriptor/KeyInfo/X509Data/X509Certificate"
|
73
|
+
node = t.xpath(the_xpath)
|
74
|
+
if node.blank?
|
75
|
+
raise "Could not extract X509Certificate from #{site.name}"
|
76
|
+
else
|
77
|
+
node.inner_text
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
# See these for specs
|
84
|
+
# https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPRequestMapHowTo
|
85
|
+
# https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPRequestMapPath
|
86
|
+
# https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPRequestMapPathRegex
|
87
|
+
def to_auth_request_map_directive
|
88
|
+
common_host_begin = "<Host name=\"#{self.name}\" redirectToSSL=\"443\" applicationId=\"#{self.name}\" "
|
89
|
+
host_end = '</Host>'
|
90
|
+
path_strings = []
|
91
|
+
if self.paths.first.name == '/'
|
92
|
+
host_begin = common_host_begin + " #{self.auth_request_map_xml_payload_for_flavor(self.paths.first.flavor)}>"
|
93
|
+
else
|
94
|
+
host_begin = common_host_begin + ">" # just close the tag, we all good
|
95
|
+
end
|
96
|
+
self.paths.each do |p|
|
97
|
+
next if p.name == '/' # Already dealt with/baked into the <Host> Xml
|
98
|
+
if p.flavor == :authentication_required_for_specific_users
|
99
|
+
path_strings << <<-EOS
|
100
|
+
<!-- Shibboleths Lil Helper flavor=#{p.flavor} -->
|
101
|
+
<Path name="#{p.name}" #{self.auth_request_map_xml_payload_for_flavor(p.flavor)}>
|
102
|
+
<AccessControl>
|
103
|
+
<Rule require="user">#{p.specific_users.join(' ')}</Rule>
|
104
|
+
</AccessControl>
|
105
|
+
</Path>
|
106
|
+
EOS
|
107
|
+
else
|
108
|
+
path_strings << "<Path name=\"#{p.name}\" #{self.auth_request_map_xml_payload_for_flavor(p.flavor)} />"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return "#{host_begin}\n#{path_strings.join("\n")}\n#{host_end}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def to_https_prefixed_name
|
115
|
+
"https://#{self.name}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def config_dir
|
119
|
+
File.join(self.parent_host.config_dir,self.name.to_s)
|
120
|
+
end
|
121
|
+
|
122
|
+
def fetched_metadata_path
|
123
|
+
File.join(self.config_dir,'fetched_metadata.xml')
|
124
|
+
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
# Internal helper, used in <RequestMapper>
|
128
|
+
# returned strings are interpoleted into <Host> or <Path>
|
129
|
+
#
|
130
|
+
def auth_request_map_xml_payload_for_flavor(flavor)
|
131
|
+
if flavor == :authentication_optional
|
132
|
+
'authType="shibboleth" requireSession="false"'
|
133
|
+
elsif [:authentication_required,:authentication_required_for_specific_users].include?(flavor)
|
134
|
+
'authType="shibboleth" requireSession="true"'
|
135
|
+
else
|
136
|
+
raise "No auth_request_map_xml_payload_for_flavor flavor=#{flavor}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|