mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
Add auth token support to the control server
This commit is contained in:
parent
a91d64a560
commit
47f7671282
4 changed files with 92 additions and 20 deletions
|
@ -142,6 +142,11 @@ module Puma
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
o.on "--control-token TOKEN",
|
||||||
|
"The token to use as authentication for the control server" do |arg|
|
||||||
|
@options[:control_auth_token] = arg
|
||||||
|
end
|
||||||
|
|
||||||
o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
|
o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
|
||||||
min, max = arg.split(":")
|
min, max = arg.split(":")
|
||||||
if max
|
if max
|
||||||
|
@ -213,10 +218,7 @@ module Puma
|
||||||
@options[:rackup] = @argv.shift || DefaultRackup
|
@options[:rackup] = @argv.shift || DefaultRackup
|
||||||
end
|
end
|
||||||
|
|
||||||
if @options[:control_url] == "auto"
|
@temp_status_path = @options[:control_path_temp]
|
||||||
path = @temp_status_path = Configuration.temp_path
|
|
||||||
@options[:control_url] = "unix://#{path}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse the options, load the rackup, start the server and wait
|
# Parse the options, load the rackup, start the server and wait
|
||||||
|
@ -273,6 +275,11 @@ module Puma
|
||||||
uri = URI.parse str
|
uri = URI.parse str
|
||||||
|
|
||||||
app = Puma::App::Status.new server, self
|
app = Puma::App::Status.new server, self
|
||||||
|
|
||||||
|
if token = @options[:control_auth_token]
|
||||||
|
app.auth_token = token unless token.empty? or token == :none
|
||||||
|
end
|
||||||
|
|
||||||
status = Puma::Server.new app, @events
|
status = Puma::Server.new app, @events
|
||||||
status.min_threads = 0
|
status.min_threads = 0
|
||||||
status.max_threads = 1
|
status.max_threads = 1
|
||||||
|
|
|
@ -25,6 +25,44 @@ module Puma
|
||||||
if @options[:binds].empty?
|
if @options[:binds].empty?
|
||||||
@options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
|
@options[:binds] << "tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if @options[:control_url] == "auto"
|
||||||
|
path = Configuration.temp_path
|
||||||
|
@options[:control_url] = "unix://#{path}"
|
||||||
|
@options[:control_url_temp] = path
|
||||||
|
end
|
||||||
|
|
||||||
|
unless @options[:control_auth_token]
|
||||||
|
setup_random_token
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_random_token
|
||||||
|
begin
|
||||||
|
require 'openssl'
|
||||||
|
rescue LoadError
|
||||||
|
end
|
||||||
|
|
||||||
|
count = 16
|
||||||
|
|
||||||
|
bytes = nil
|
||||||
|
|
||||||
|
if defined? OpenSSL::Random
|
||||||
|
bytes = OpenSSL::Random.random_bytes(count)
|
||||||
|
elsif File.exists?("/dev/urandom")
|
||||||
|
File.open("/dev/urandom") do |f|
|
||||||
|
bytes = f.read(count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if bytes
|
||||||
|
token = ""
|
||||||
|
bytes.each_byte { |b| token << b.to_s(16) }
|
||||||
|
else
|
||||||
|
token = (0..count).to_a.map { rand(255).to_s(16) }.join
|
||||||
|
end
|
||||||
|
|
||||||
|
@options[:control_auth_token] = token
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.temp_path
|
def self.temp_path
|
||||||
|
@ -48,8 +86,18 @@ module Puma
|
||||||
# Start the Puma control rack app on +url+. This app can be communicated
|
# Start the Puma control rack app on +url+. This app can be communicated
|
||||||
# with to control the main server.
|
# with to control the main server.
|
||||||
#
|
#
|
||||||
def activate_control_app(url="auto")
|
def activate_control_app(url="auto", opts=nil)
|
||||||
@options[:control_url] = url
|
@options[:control_url] = url
|
||||||
|
|
||||||
|
if opts
|
||||||
|
if tok = opts[:auth_token]
|
||||||
|
@options[:control_auth_token] = tok
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts[:no_token]
|
||||||
|
@options[:control_auth_token] = :none
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Bind the server to +url+. tcp:// and unix:// are the only accepted
|
# Bind the server to +url+. tcp:// and unix:// are the only accepted
|
||||||
|
|
|
@ -59,16 +59,34 @@ module Puma
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def request(sock, url)
|
||||||
|
token = @config.options[:control_auth_token]
|
||||||
|
if token
|
||||||
|
url = "#{url}?token=#{token}"
|
||||||
|
end
|
||||||
|
|
||||||
|
sock << "GET #{url} HTTP/1.0\r\n\r\n"
|
||||||
|
|
||||||
|
rep = sock.read.split("\r\n")
|
||||||
|
|
||||||
|
m = %r!HTTP/1.\d (\d+)!.match(rep.first)
|
||||||
|
if m[1] == "403"
|
||||||
|
raise "Unauthorized access to server (wrong auth token)"
|
||||||
|
elsif m[1] != "200"
|
||||||
|
raise "Bad response code from server: #{m[1]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
return rep.last
|
||||||
|
end
|
||||||
|
|
||||||
def command_pid
|
def command_pid
|
||||||
puts "#{@state['pid']}"
|
puts "#{@state['pid']}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def command_stop
|
def command_stop
|
||||||
sock = connect
|
sock = connect
|
||||||
sock << "GET /stop HTTP/1.0\r\n\r\n"
|
body = request sock, "/stop"
|
||||||
rep = sock.read
|
|
||||||
|
|
||||||
body = rep.split("\r\n").last
|
|
||||||
if body != '{ "status": "ok" }'
|
if body != '{ "status": "ok" }'
|
||||||
raise "Invalid response: '#{body}'"
|
raise "Invalid response: '#{body}'"
|
||||||
else
|
else
|
||||||
|
@ -78,10 +96,8 @@ module Puma
|
||||||
|
|
||||||
def command_halt
|
def command_halt
|
||||||
sock = connect
|
sock = connect
|
||||||
s << "GET /halt HTTP/1.0\r\n\r\n"
|
body = request sock, "/halt"
|
||||||
rep = s.read
|
|
||||||
|
|
||||||
body = rep.split("\r\n").last
|
|
||||||
if body != '{ "status": "ok" }'
|
if body != '{ "status": "ok" }'
|
||||||
raise "Invalid response: '#{body}'"
|
raise "Invalid response: '#{body}'"
|
||||||
else
|
else
|
||||||
|
@ -91,10 +107,8 @@ module Puma
|
||||||
|
|
||||||
def command_restart
|
def command_restart
|
||||||
sock = connect
|
sock = connect
|
||||||
sock << "GET /restart HTTP/1.0\r\n\r\n"
|
body = request sock, "/restart"
|
||||||
rep = sock.read
|
|
||||||
|
|
||||||
body = rep.split("\r\n").last
|
|
||||||
if body != '{ "status": "ok" }'
|
if body != '{ "status": "ok" }'
|
||||||
raise "Invalid response: '#{body}'"
|
raise "Invalid response: '#{body}'"
|
||||||
else
|
else
|
||||||
|
@ -104,10 +118,7 @@ module Puma
|
||||||
|
|
||||||
def command_stats
|
def command_stats
|
||||||
sock = connect
|
sock = connect
|
||||||
sock << "GET /stats HTTP/1.0\r\n\r\n"
|
body = request sock, "/stats"
|
||||||
rep = sock.read
|
|
||||||
|
|
||||||
body = rep.split("\r\n").last
|
|
||||||
|
|
||||||
puts body
|
puts body
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,7 +34,10 @@ class TestCLI < Test::Unit::TestCase
|
||||||
sin = StringIO.new
|
sin = StringIO.new
|
||||||
sout = StringIO.new
|
sout = StringIO.new
|
||||||
|
|
||||||
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control", url, "test/lobster.ru"], sin, sout
|
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
|
||||||
|
"--control", url,
|
||||||
|
"--control-token", "",
|
||||||
|
"test/lobster.ru"], sin, sout
|
||||||
cli.parse_options
|
cli.parse_options
|
||||||
|
|
||||||
t = Thread.new { cli.run }
|
t = Thread.new { cli.run }
|
||||||
|
@ -57,7 +60,10 @@ class TestCLI < Test::Unit::TestCase
|
||||||
sin = StringIO.new
|
sin = StringIO.new
|
||||||
sout = StringIO.new
|
sout = StringIO.new
|
||||||
|
|
||||||
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}", "--control", url, "test/lobster.ru"], sin, sout
|
cli = Puma::CLI.new ["-b", "unix://#{@tmp_path2}",
|
||||||
|
"--control", url,
|
||||||
|
"--control-token", "",
|
||||||
|
"test/lobster.ru"], sin, sout
|
||||||
cli.parse_options
|
cli.parse_options
|
||||||
|
|
||||||
t = Thread.new { cli.run }
|
t = Thread.new { cli.run }
|
||||||
|
|
Loading…
Reference in a new issue