1
0
Fork 0
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:
Evan Phoenix 2011-12-07 10:46:36 -08:00
parent a91d64a560
commit 47f7671282
4 changed files with 92 additions and 20 deletions

View file

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

View file

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

View file

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

View file

@ -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 }