# frozen_string_literal: true
namespace :saml_camel do # rubocop:disable Metrics/BlockLength
desc 'Generate Files for Saml' task :generate_saml do # rubocop:disable Metrics/BlockLength dir = "#{Rails.root}/config/saml/" FileUtils.mkdir(dir) unless Dir.exist?(dir) specified_env = ENV['environment'] default_envs = %w[production test development] key = generate_key cert = generate_cert(key) settings = generate_saml_settings.to_json # TODO: pull in specified idp certificate idp_cert = "MIIEWjCCA0KgAwIBAgIJAP1rB/FjRgy6MA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNV
BAYTAlVTMRcwFQYDVQQIEw5Ob3J0aCBDYXJvbGluYTEPMA0GA1UEBxMGRHVyaGFt MRgwFgYDVQQKEw9EdWtlIFVuaXZlcnNpdHkxDDAKBgNVBAsTA09JVDEaMBgGA1UE AxMRc2hpYi5vaXQuZHVrZS5lZHUwHhcNMTAwOTA5MTI0NDU1WhcNMjgwOTA0MTI0 NDU1WjB7MQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzAN BgNVBAcTBkR1cmhhbTEYMBYGA1UEChMPRHVrZSBVbml2ZXJzaXR5MQwwCgYDVQQL EwNPSVQxGjAYBgNVBAMTEXNoaWIub2l0LmR1a2UuZWR1MIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAt+hnl6gSRi0Y8VuNl6PCPYejj7VfVs/y8bRa5zAY RHwb75+vBSs2j1yeUcSore9Ba5Ni7v947V34afRMGRPOqr4TEDZxU+1Bg0zAvSrR n4Y8B+zyJuhtOpmOZzTwE9o/Oc+CB4kYV/K0woKZdcoxHJm8TbqBqdxU4fFYUlNU o4Dr5jRdCSr9MHBOqGWXtQMg16qYNB7StNk4twY29FNnpZwkVTfsE76uVsRMkG8i 6/RiHpXZ/ioOOqndptbEGdsOIE3ivAJOZdvYwnDe5NnTH06P01HsxH3OOnYqhuG2 J6qdhqoelGeHRG+jfl8YkYXCcKQvja2tJ5G+6iqSN7DP6QIDAQABo4HgMIHdMB0G A1UdDgQWBBQHYXwB6otkfyMOmUI59j8823hFRDCBrQYDVR0jBIGlMIGigBQHYXwB 6otkfyMOmUI59j8823hFRKF/pH0wezELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5v cnRoIENhcm9saW5hMQ8wDQYDVQQHEwZEdXJoYW0xGDAWBgNVBAoTD0R1a2UgVW5p dmVyc2l0eTEMMAoGA1UECxMDT0lUMRowGAYDVQQDExFzaGliLm9pdC5kdWtlLmVk dYIJAP1rB/FjRgy6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAG7q wJpiSLJbx2gj/cGDYeuBW/CeRGNghjQ/mb076P3WXsRNPAimcXulSUbQkS6eDH4t Ifvsa0jf4FRsEOwH/x8354/0wyv4RwuavX25kjpmoFn3O+eKokyzsc7/Q2gsm0mv V8XQo+5b+4we8AFYlAVp26nLeIqAiJM8xZJ9yHuzVL1O4yxIWIKECWHLqY5+1nas XNiLURrHhsK5pZUPLuhzJFgZuJT62TtnrjJXlrRhJ389VSkh6R64C6ncjNkg6/Cu tA6SX0infqNRyPRNJK+bnQd1yOP4++tjD/lAPE+5tiD/waI3fArt43ZE/qp7pYMS 9TEfyQ5QpfRYAUFWXBc=“
if specified_env dir = "#{Rails.root}/config/saml/#{specified_env}" FileUtils.mkdir(dir) unless Dir.exist?(dir) File.open("#{Rails.root}/config/saml/#{specified_env}/saml_certificate.crt", 'w+') { |f| f.write(cert) } # rubocop:disable Metrics/LineLength File.open("#{Rails.root}/config/saml/#{specified_env}/saml_key.key", 'w+') { |f| f.write(key) } # rubocop:disable Metrics/LineLength File.open("#{Rails.root}/config/saml/#{specified_env}/idp_certificate.crt", 'w+') { |f| f.write(idp_cert) } # rubocop:disable Metrics/LineLength File.open("#{Rails.root}/config/saml/#{specified_env}/settings.json", 'w+') { |f| f.write(settings) } # rubocop:disable Metrics/LineLength File.open('.gitignore', 'a') { |f| f.write("config/saml/#{specified_env}/saml_key.key") } else default_envs.each do |e| dir = "#{Rails.root}/config/saml/#{e}" FileUtils.mkdir(dir) unless Dir.exist?(dir) File.open("#{Rails.root}/config/saml/#{e}/saml_certificate.crt", 'w+') { |f| f.write(cert) } # rubocop:disable Metrics/LineLength File.open("#{Rails.root}/config/saml/#{e}/saml_key.key", 'w+') { |f| f.write(key) } # rubocop:disable Metrics/LineLength File.open("#{Rails.root}/config/saml/#{e}/idp_certificate.crt", 'w+') { |f| f.write(idp_cert) } # rubocop:disable Metrics/LineLength File.open("#{Rails.root}/config/saml/#{e}/settings.json", 'w+') { |f| f.write(settings) } # rubocop:disable Metrics/LineLength File.open('.gitignore', 'a') { |f| f.write("config/saml/#{e}/saml_key.key\n") } # rubocop:disable Metrics/LineLength end end end def generate_saml_settings # rubocop:disable Metrics/MethodLength { _comment: 'note you will need to restart the application when you make changes to this file', settings: { acs: 'http://localhost:3000/saml/consumeSaml', raw_response_acs: 'http://localhost:3000/saml/consumeSaml/rawResponse', entity_id: 'https://your-entity-id.com', sso_url: 'https://shib.oit.duke.edu/idp/profile/SAML2/Redirect/SSO', logout_url: 'https://shib.oit.duke.edu/cgi-bin/logout.pl', primary_id: 'eduPersonPrincipalName', sp_session_timeout: 1, sp_session_lifetime: 8, clock_drift: false, test_auth_path: true, saml_logging: true, debug: false, shib_module: false }, 'attribute_map': { 'urn:oid:1.3.6.1.4.1.5923.1.1.1.9': 'eduPersonScopedAffiliation', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6': 'eduPersonPrincipalName', 'urn:oid:2.5.4.3': 'cn', 'urn:oid:0.9.2342.19200300.100.1.1': 'uid', 'urn:oid:0.9.2342.19200300.100.1.3': 'mail', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.5': 'eduPersonPrimaryAffiliation', 'urn:oid:2.16.840.1.113730.3.1.241': 'displayName', 'urn:mace:duke.edu:idms:unique-id': 'duDukeID', 'urn:mace:duke.edu:idms:dku-id': 'dku-id', 'urn:oid:1.3.6.1.4.1.5923.1.5.1.1': 'isMemberOf', 'urn:oid:2.5.4.42': 'givenName', 'urn:oid:2.5.4.4': 'sn', 'urn:oid:2.5.4.11': 'ou', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.1': 'eduPersonAffiliation', 'urn:oid:2.5.4.20': 'telephoneNumber', 'urn:oid:2.5.4.12': 'title', 'urn:mace:duke.edu:idms:middle-name1': 'duMiddleName1', 'urn:mace:duke.edu:idms:proxy-token': 'duProxyToken' } } end def generate_key OpenSSL::PKey::RSA.new(2048) end def generate_cert(key) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize puts '\n\nPlease provide the following details to generate your saml key and certificate:' STDOUT.puts 'Country Name (2 letter code) [AU]:' country = STDIN.gets.strip STDOUT.puts 'State or Province Name (full name) [Some-State]:' state = STDIN.gets.strip STDOUT.puts 'Locality Name (eg, city):' city = STDIN.gets.strip STDOUT.puts 'Organization Name (eg, company):' org = STDIN.gets.strip STDOUT.puts 'Organizational Unit Name (eg, section):' unit = STDIN.gets.strip STDOUT.puts 'Common Name (non url name, remember this is not a server cert):' cn = STDIN.gets.strip STDOUT.puts 'Email Address:' email = STDIN.gets.strip public_key = key.public_key # generate subject line of cert subject = "/C=#{country}/ST=#{state}/L=#{city}/O=#{org}/OU=#{unit}/CN=#{cn}/emailAddress=#{email}" # rubocop:disable Metrics/LineLength cert = OpenSSL::X509::Certificate.new # TODO: this line breaks when https:// is added for CN cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject) cert.not_before = Time.now cert.not_after = Time.now + 365 * 24 * 60 * 60 cert.public_key = public_key cert.serial = 0x0 cert.version = 2 ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = cert cert.extensions = [ ef.create_extension('basicConstraints', 'CA:TRUE', true), ef.create_extension('subjectKeyIdentifier', 'hash'), # ef.create_extension("keyUsage", "cRLSign,keyCertSign", true), ] cert.add_extension ef.create_extension('authorityKeyIdentifier', 'keyid:always,issuer:always') cert.sign key, OpenSSL::Digest::SHA256.new end
end