Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

simple auth middleware

  • Loading branch information...
commit 5dfe25fe4d25f4211c5ede8217d2f3a75eda62a6 1 parent f84d025
@josh josh authored
Showing with 140 additions and 34 deletions.
  1. +67 −0 lib/rack/openid/simple_auth.rb
  2. +73 −34 test/test_openid.rb
View
67 lib/rack/openid/simple_auth.rb
@@ -0,0 +1,67 @@
+require 'rack/openid'
+
+module Rack #:nodoc:
+ class OpenID
+ # A simple OpenID middleware that restricts access to
+ # a single identifier.
+ #
+ # use Rack::OpenID::SimpleAuth, "http://example.org"
+ #
+ # SimpleAuth will automatically insert the required Rack::OpenID
+ # middleware, so <tt>use Rack::OpenID</tt> is unnecessary.
+ class SimpleAuth
+ def self.new(*args)
+ Rack::OpenID.new(super)
+ end
+
+ attr_reader :app, :identifier
+
+ def initialize(app, identifier)
+ @app = app
+ @identifier = identifier
+ end
+
+ def call(env)
+ if session_authenticated?(env)
+ app.call(env)
+ elsif successful_response?(env)
+ authenticate_session(env)
+ app.call(env)
+ else
+ authentication_request
+ end
+ end
+
+ private
+ def session(env)
+ env['rack.session'] || raise_session_error
+ end
+
+ def raise_session_error
+ raise RuntimeError, 'Rack::OpenID::SimpleAuth requires a session'
+ end
+
+ def session_authenticated?(env)
+ session(env)['authenticated'] == true
+ end
+
+ def authenticate_session(env)
+ session(env)['authenticated'] = true
+ end
+
+ def successful_response?(env)
+ if resp = env[OpenID::RESPONSE]
+ resp.status == :success && resp.display_identifier == identifier
+ end
+ end
+
+ def authentication_request
+ [401, { OpenID::AUTHENTICATE_HEADER => www_authenticate_header }, []]
+ end
+
+ def www_authenticate_header
+ OpenID.build_header(:identifier => identifier)
+ end
+ end
+ end
+end
View
107 test/test_openid.rb
@@ -3,6 +3,7 @@
require 'rack'
require 'rack/openid'
+require 'rack/openid/simple_auth'
log = Logger.new(STDOUT)
log.level = Logger::WARN
@@ -34,6 +35,33 @@ def fetch(url, body = nil, headers = nil, limit = nil)
end
end
+RotsServerUrl = 'http://localhost:9292'
+
+RotsApp = Rack::Builder.new do
+ require 'rots'
+
+ config = {
+ 'identity' => 'john.doe',
+ 'sreg' => {
+ 'nickname' => 'jdoe',
+ 'fullname' => 'John Doe',
+ 'email' => 'jhon@doe.com',
+ 'dob' => Date.parse('1985-09-21'),
+ 'gender' => 'M'
+ }
+ }
+
+ map("/%s" % config['identity']) do
+ run Rots::IdentityPageApp.new(config, {})
+ end
+
+ map '/server' do
+ run Rots::ServerApp.new(config, :storage => Dir.tmpdir)
+ end
+end
+
+OpenID.fetcher = MockFetcher.new(RotsApp)
+
class TestHeader < Test::Unit::TestCase
def test_build_header
@@ -69,33 +97,27 @@ def test_parse_header
end
end
-class TestOpenID < Test::Unit::TestCase
- RotsServerUrl = 'http://localhost:9292'
-
- RotsApp = Rack::Builder.new do
- require 'rots'
-
- config = {
- 'identity' => 'john.doe',
- 'sreg' => {
- 'nickname' => 'jdoe',
- 'fullname' => 'John Doe',
- 'email' => 'jhon@doe.com',
- 'dob' => Date.parse('1985-09-21'),
- 'gender' => 'M'
- }
- }
-
- map("/%s" % config['identity']) do
- run Rots::IdentityPageApp.new(config, {})
+module RackTestHelpers
+ private
+ def process(*args)
+ env = Rack::MockRequest.env_for(*args)
+ @response = Rack::MockResponse.new(*@app.call(env))
end
- map '/server' do
- run Rots::ServerApp.new(config, :storage => Dir.tmpdir)
+ def follow_redirect!
+ assert @response
+ assert_equal 303, @response.status
+
+ env = Rack::MockRequest.env_for(@response.headers['Location'])
+ status, headers, body = RotsApp.call(env)
+
+ uri = URI(headers['Location'])
+ process("#{uri.path}?#{uri.query}")
end
- end
+end
- OpenID.fetcher = MockFetcher.new(RotsApp)
+class TestOpenID < Test::Unit::TestCase
+ include RackTestHelpers
def test_with_get
@app = app
@@ -237,20 +259,37 @@ def app(options = {})
}
Rack::Session::Pool.new(Rack::OpenID.new(app))
end
+end
- def process(*args)
- env = Rack::MockRequest.env_for(*args)
- @response = Rack::MockResponse.new(*@app.call(env))
- end
+class TestSimpleAuth < Test::Unit::TestCase
+ include RackTestHelpers
- def follow_redirect!
- assert @response
- assert_equal 303, @response.status
+ def test_successful_login
+ @app = app "#{RotsServerUrl}/john.doe?openid.success=true"
- env = Rack::MockRequest.env_for(@response.headers['Location'])
- status, headers, body = RotsApp.call(env)
+ process '/dashboard'
+ follow_redirect!
- uri = URI(headers['Location'])
- process("#{uri.path}?#{uri.query}")
+ assert_equal 200, @response.status
+ assert_equal 'Hello', @response.body
+
+ cookie = @response.headers['Set-Cookie'].split(';').first
+ process '/dashboard', 'HTTP_COOKIE' => cookie
+ assert_equal 200, @response.status
+ end
+
+ def test_failed_login
+ @app = app "#{RotsServerUrl}/john.doe"
+
+ process '/dashboard'
+ follow_redirect!
+ assert_match RotsServerUrl, @response.headers['Location']
+ end
+
+ private
+ def app(identifier)
+ app = lambda { |env| [200, {'Content-Type' => 'text/html'}, ['Hello']] }
+ app = Rack::OpenID::SimpleAuth.new(app, identifier)
+ Rack::Session::Pool.new(app)
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.