Skip to content

Commit

Permalink
Vendor rack 0.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
josh committed Nov 22, 2008
1 parent 4b36f76 commit cc67272
Show file tree
Hide file tree
Showing 42 changed files with 4,225 additions and 0 deletions.
1 change: 1 addition & 0 deletions actionpack/lib/action_controller.rb
Expand Up @@ -32,6 +32,7 @@
end

$:.unshift "#{File.dirname(__FILE__)}/action_controller/vendor/html-scanner"
require 'action_controller/vendor/rack'

require 'action_controller/base'
require 'action_controller/request'
Expand Down
81 changes: 81 additions & 0 deletions actionpack/lib/action_controller/vendor/rack-0.4.0/rack.rb
@@ -0,0 +1,81 @@
# Copyright (C) 2007, 2008 Christian Neukirchen <purl.org/net/chneukirchen>
#
# Rack is freely distributable under the terms of an MIT-style license.
# See COPYING or http://www.opensource.org/licenses/mit-license.php.

$: << File.expand_path(File.dirname(__FILE__))


# The Rack main module, serving as a namespace for all core Rack
# modules and classes.
#
# All modules meant for use in your application are <tt>autoload</tt>ed here,
# so it should be enough just to <tt>require rack.rb</tt> in your code.

module Rack
# The Rack protocol version number implemented.
VERSION = [0,1]

# Return the Rack protocol version as a dotted string.
def self.version
VERSION.join(".")
end

# Return the Rack release as a dotted string.
def self.release
"0.4"
end

autoload :Builder, "rack/builder"
autoload :Cascade, "rack/cascade"
autoload :CommonLogger, "rack/commonlogger"
autoload :File, "rack/file"
autoload :Deflater, "rack/deflater"
autoload :Directory, "rack/directory"
autoload :ForwardRequest, "rack/recursive"
autoload :Handler, "rack/handler"
autoload :Lint, "rack/lint"
autoload :Recursive, "rack/recursive"
autoload :Reloader, "rack/reloader"
autoload :ShowExceptions, "rack/showexceptions"
autoload :ShowStatus, "rack/showstatus"
autoload :Static, "rack/static"
autoload :URLMap, "rack/urlmap"
autoload :Utils, "rack/utils"

autoload :MockRequest, "rack/mock"
autoload :MockResponse, "rack/mock"

autoload :Request, "rack/request"
autoload :Response, "rack/response"

module Auth
autoload :Basic, "rack/auth/basic"
autoload :AbstractRequest, "rack/auth/abstract/request"
autoload :AbstractHandler, "rack/auth/abstract/handler"
autoload :OpenID, "rack/auth/openid"
module Digest
autoload :MD5, "rack/auth/digest/md5"
autoload :Nonce, "rack/auth/digest/nonce"
autoload :Params, "rack/auth/digest/params"
autoload :Request, "rack/auth/digest/request"
end
end

module Session
autoload :Cookie, "rack/session/cookie"
autoload :Pool, "rack/session/pool"
autoload :Memcache, "rack/session/memcache"
end

# *Adapters* connect Rack with third party web frameworks.
#
# Rack includes an adapter for Camping, see README for other
# frameworks supporting Rack in their code bases.
#
# Refer to the submodules for framework-specific calling details.

module Adapter
autoload :Camping, "rack/adapter/camping"
end
end
@@ -0,0 +1,22 @@
module Rack
module Adapter
class Camping
def initialize(app)
@app = app
end

def call(env)
env["PATH_INFO"] ||= ""
env["SCRIPT_NAME"] ||= ""
controller = @app.run(env['rack.input'], env)
h = controller.headers
h.each_pair do |k,v|
if v.kind_of? URI
h[k] = v.to_s
end
end
[controller.status, controller.headers, controller.body]
end
end
end
end
@@ -0,0 +1,28 @@
module Rack
module Auth
# Rack::Auth::AbstractHandler implements common authentication functionality.
#
# +realm+ should be set for all handlers.

class AbstractHandler

attr_accessor :realm

def initialize(app, &authenticator)
@app, @authenticator = app, authenticator
end


private

def unauthorized(www_authenticate = challenge)
return [ 401, { 'WWW-Authenticate' => www_authenticate.to_s }, [] ]
end

def bad_request
[ 400, {}, [] ]
end

end
end
end
@@ -0,0 +1,37 @@
module Rack
module Auth
class AbstractRequest

def initialize(env)
@env = env
end

def provided?
!authorization_key.nil?
end

def parts
@parts ||= @env[authorization_key].split(' ', 2)
end

def scheme
@scheme ||= parts.first.downcase.to_sym
end

def params
@params ||= parts.last
end


private

AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']

def authorization_key
@authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) }
end

end

end
end
@@ -0,0 +1,58 @@
require 'rack/auth/abstract/handler'
require 'rack/auth/abstract/request'

module Rack
module Auth
# Rack::Auth::Basic implements HTTP Basic Authentication, as per RFC 2617.
#
# Initialize with the Rack application that you want protecting,
# and a block that checks if a username and password pair are valid.
#
# See also: <tt>example/protectedlobster.rb</tt>

class Basic < AbstractHandler

def call(env)
auth = Basic::Request.new(env)

return unauthorized unless auth.provided?

return bad_request unless auth.basic?

if valid?(auth)
env['REMOTE_USER'] = auth.username

return @app.call(env)
end

unauthorized
end


private

def challenge
'Basic realm="%s"' % realm
end

def valid?(auth)
@authenticator.call(*auth.credentials)
end

class Request < Auth::AbstractRequest
def basic?
:basic == scheme
end

def credentials
@credentials ||= params.unpack("m*").first.split(/:/, 2)
end

def username
credentials.first
end
end

end
end
end
@@ -0,0 +1,124 @@
require 'rack/auth/abstract/handler'
require 'rack/auth/digest/request'
require 'rack/auth/digest/params'
require 'rack/auth/digest/nonce'
require 'digest/md5'

module Rack
module Auth
module Digest
# Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
# HTTP Digest Authentication, as per RFC 2617.
#
# Initialize with the [Rack] application that you want protecting,
# and a block that looks up a plaintext password for a given username.
#
# +opaque+ needs to be set to a constant base64/hexadecimal string.
#
class MD5 < AbstractHandler

attr_accessor :opaque

attr_writer :passwords_hashed

def initialize(app)
super
@passwords_hashed = nil
end

def passwords_hashed?
!!@passwords_hashed
end

def call(env)
auth = Request.new(env)

unless auth.provided?
return unauthorized
end

if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
return bad_request
end

if valid?(auth)
if auth.nonce.stale?
return unauthorized(challenge(:stale => true))
else
env['REMOTE_USER'] = auth.username

return @app.call(env)
end
end

unauthorized
end


private

QOP = 'auth'.freeze

def params(hash = {})
Params.new do |params|
params['realm'] = realm
params['nonce'] = Nonce.new.to_s
params['opaque'] = H(opaque)
params['qop'] = QOP

hash.each { |k, v| params[k] = v }
end
end

def challenge(hash = {})
"Digest #{params(hash)}"
end

def valid?(auth)
valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
end

def valid_qop?(auth)
QOP == auth.qop
end

def valid_opaque?(auth)
H(opaque) == auth.opaque
end

def valid_nonce?(auth)
auth.nonce.valid?
end

def valid_digest?(auth)
digest(auth, @authenticator.call(auth.username)) == auth.response
end

def md5(data)
::Digest::MD5.hexdigest(data)
end

alias :H :md5

def KD(secret, data)
H([secret, data] * ':')
end

def A1(auth, password)
[ auth.username, auth.realm, password ] * ':'
end

def A2(auth)
[ auth.method, auth.uri ] * ':'
end

def digest(auth, password)
password_hash = passwords_hashed? ? password : H(A1(auth, password))

KD(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':')
end

end
end
end
end

0 comments on commit cc67272

Please sign in to comment.