Class: Aspera::WebServerSimple

Inherits:
WEBrick::HTTPServer
  • Object
show all
Defined in:
lib/aspera/web_server_simple.rb

Overview

Simple WEBrick server with HTTPS support

Direct Known Subclasses

WebAuth

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri, certificate: nil) ⇒ WebServerSimple



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/aspera/web_server_simple.rb', line 42

def initialize(uri, certificate: nil)
  @url = uri
  # see https://www.rubydoc.info/stdlib/webrick/WEBrick/Config
  webrick_options = {
    BindAddress: uri.host,
    Port:        uri.port,
    Logger:      Log.log,
    AccessLog:   [[self, WEBrick::AccessLog::COMMON_LOG_FORMAT]] # replace default access log to call local method "<<" below
  }
  case uri.scheme
  when 'http'
    Log.log.debug('HTTP mode')
  when 'https'
    webrick_options[:SSLEnable] = true
    if certificate.nil?
      webrick_options[:SSLCertName] = [['CN', WEBrick::Utils.getservername]]
    else
      Aspera.assert_type(certificate, Hash)
      certificate = certificate.symbolize_keys
      raise "unexpected key in certificate config: only: #{CERT_PARAMETERS.join(', ')}" if certificate.keys.any?{|key|!CERT_PARAMETERS.include?(key)}
      if certificate.key?(:pkcs12)
        Log.log.debug('Using PKCS12 certificate')
        raise 'pkcs12 requires a key (password)' unless certificate.key?(:key)
        pkcs12 = OpenSSL::PKCS12.new(File.read(certificate[:pkcs12]), certificate[:key])
        webrick_options[:SSLCertificate] = pkcs12.certificate
        webrick_options[:SSLPrivateKey] = pkcs12.key
        webrick_options[:SSLExtraChainCert] = pkcs12.ca_certs
      else
        Log.log.debug('Using PEM certificate')
        webrick_options[:SSLPrivateKey] = if certificate.key?(:key)
          OpenSSL::PKey::RSA.new(File.read(certificate[:key]))
        else
          OpenSSL::PKey::RSA.new(4096)
        end
        if certificate.key?(:cert)
          webrick_options[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.read(certificate[:cert]))
        else
          webrick_options[:SSLCertificate] = OpenSSL::X509::Certificate.new
          self.class.fill_self_signed_cert(webrick_options[:SSLCertificate], webrick_options[:SSLPrivateKey])
        end
        if certificate.key?(:chain)
          webrick_options[:SSLExtraChainCert] = [OpenSSL::X509::Certificate.new(File.read(certificate[:chain]))]
        end
      end
    end
  end
  # call constructor of parent class, but capture STDERR
  # self signed certificate generates characters on STDERR
  # see create_self_signed_cert in webrick/ssl.rb
  Log.capture_stderr { super(webrick_options) }
end

Class Method Details

.fill_self_signed_cert(cert, key, digest = 'SHA256') ⇒ Object

Fill and self sign provided certificate



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/aspera/web_server_simple.rb', line 21

def fill_self_signed_cert(cert, key, digest = 'SHA256')
  cert.subject = cert.issuer = OpenSSL::X509::Name.parse(GENERIC_ISSUER)
  cert.not_before = cert.not_after = Time.now
  cert.not_after += ONE_YEAR_SECONDS
  cert.public_key = key.public_key
  cert.serial = 0x0
  cert.version = 2
  ef = OpenSSL::X509::ExtensionFactory.new
  ef.issuer_certificate = cert
  ef.subject_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.new(digest))
end

Instance Method Details

#<<(access_log) ⇒ Object

log web server access ( option AccessLog )



103
104
105
# File 'lib/aspera/web_server_simple.rb', line 103

def <<(access_log)
  Log.log.debug{"webrick log #{access_log.chomp}"}
end

#startObject

blocking



95
96
97
98
99
100
# File 'lib/aspera/web_server_simple.rb', line 95

def start
  Log.log.info{"Listening on #{@url}"}
  # kill -HUP for graceful shutdown
  Kernel.trap('HUP') { shutdown }
  super
end