# 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