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

Returns a new instance of WebServerSimple.

Parameters:



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
# 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 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

generates and adds self signed cert to provided webrick options



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 )



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

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

#startObject

blocking



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

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