Skip to content

Instantly share code, notes, and snippets.

@nazy
Created December 8, 2012 12:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nazy/4240129 to your computer and use it in GitHub Desktop.
Save nazy/4240129 to your computer and use it in GitHub Desktop.
Authn delegation via HTTP by mod_mruby
HOST="127.0.0.1"
PORT=80
PATH="/redmine/users/current.xml" # Using Redmine REST I/F as an example.
def main
anp = Apache::AuthnProvider.new
credentials = [[anp.user, anp.password].join(":")].pack("m").gsub("\n", "")
request = {}
request['User-Agent'] = "mruby_authn_http/0.1"
request['Authorization'] = "Basic #{credentials}"
http = SimpleHttp.new(HOST, PORT)
ret = http.request("HEAD", PATH, request)
if ret.code == 200
return(Apache::AuthnProvider::AUTH_GRANTED)
else
return(Apache::AuthnProvider::AUTH_DENIED)
end
rescue => e
Apache.errlogger(3, "mruby_authn_http An exception occured : #{e.inspect}")
return Apache::AuthnProvider::AUTH_DENIED
end
##
# Simple Http
# from https://gist.github.com/3765572
class SimpleHttp
DEFAULTPORT = 80
HTTP_VERSION = "HTTP/1.0"
DEFAULT_ACCEPT = "*/*"
SEP = "\r\n"
def initialize(address, port = DEFAULTPORT)
@socket
@uri = {}
@uri[:address] = address
@uri[:port] = port ? port.to_i : DEFAULTPORT
self
end
def address; @uri[:address]; end
def port; @uri[:port]; end
def get(path = "/", request = nil)
request("GET", path, request)
end
def post(path = "/", request = nil)
request("POST", path, request)
end
# private
def request(method, path, req)
@uri[:path] = path
if @uri[:path].nil?
@uri[:path] = "/"
elsif @uri[:path][0] != "/"
@uri[:path] = "/" + @uri[:path]
end
request_header = create_request_header(method.upcase.to_s, req)
response_text = send_request(request_header)
SimpleHttpResponse.new(response_text)
end
def send_request(request_header)
@socket = TCPSocket.new(@uri[:address], @uri[:port])
@socket.write(request_header)
response_text = ""
while (t = @socket.read(1024))
response_text += t
end
@socket.close
response_text
end
def create_request_header(method, req)
req = {} unless req
str = ""
body = ""
str += sprintf("%s %s %s", method, @uri[:path], HTTP_VERSION) + SEP
header = {}
req.each do |key,value|
header[key.capitalize] = value
end
header["Host"] = @uri[:address] unless header.keys.include?("Host")
header["Accept"] = DEFAULT_ACCEPT unless header.keys.include?("Accept")
header["Connection"] = "close"
if header["Body"]
body = header["Body"]
header.delete("Body")
end
if method == "POST" && (not header.keys.include?("content-length".capitalize))
header["Content-Length"] = (body || '').length
end
header.keys.sort.each do |key|
str += sprintf("%s: %s", key, header[key]) + SEP
end
str + SEP + body
end
class SimpleHttpResponse
SEP = SimpleHttp::SEP
def initialize(response_text)
@response = {}
if response_text.include?(SEP + SEP)
@response["header"], @response["body"] = response_text.split(SEP + SEP)
else
@response["header"] = response_text
end
parse_header
self
end
def [](key); @response[key]; end
def []=(key, value); @response[key] = value; end
def header; @response['header']; end
def body; @response['body']; end
def status; @response['status']; end
def code; @response['code']; end
def date; @response['date']; end
def content_type; @response['content-type']; end
def content_length; @response['content-length']; end
def each(&block)
if block
@response.each do |k,v| block.call(k,v) end
end
end
def each_name(&block)
if block
@response.each do |k,v| block.call(k) end
end
end
# private
def parse_header
return unless @response["header"]
h = @response["header"].split(SEP)
if h[0].include?("HTTP/1")
@response["status"] = h[0].split(" ", 2).last
@response["code"] = h[0].split(" ", 3)[1].to_i
end
h.each do |line|
if line.include?(": ")
k,v = line.split(": ")
@response[k.downcase] = v
end
end
end
end
end
Apache.return(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment