eric1234-sinatra-authorization 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +25 -0
- data/Rakefile +14 -0
- data/lib/sinatra/authorization.rb +93 -0
- data/sinatra-authorization.gemspec +20 -0
- data/test/authorization_test.rb +157 -0
- metadata +68 -0
data/README.rdoc
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
= Sinatra Authorization
|
|
2
|
+
|
|
3
|
+
HTTP Authorization helpers for Sinatra.
|
|
4
|
+
|
|
5
|
+
== Example
|
|
6
|
+
|
|
7
|
+
require "sinatra/authorization"
|
|
8
|
+
|
|
9
|
+
set :authorization_realm, "Protected zone"
|
|
10
|
+
|
|
11
|
+
helpers do
|
|
12
|
+
def authorize(login, password)
|
|
13
|
+
login == "admin" && password == "secret"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
get "/" do
|
|
18
|
+
"Hello"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
get "/admin" do
|
|
22
|
+
login_required
|
|
23
|
+
|
|
24
|
+
"Welcome in protected zone"
|
|
25
|
+
end
|
data/Rakefile
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require "sinatra/base"
|
|
2
|
+
|
|
3
|
+
module Sinatra
|
|
4
|
+
# HTTP Authorization helpers for Sinatra.
|
|
5
|
+
#
|
|
6
|
+
# In your helpers module, include Sinatra::Authorization and then define
|
|
7
|
+
# an #authorize(user, password) method to handle user provided
|
|
8
|
+
# credentials.
|
|
9
|
+
#
|
|
10
|
+
# Inside your events, call #login_required to trigger the HTTP
|
|
11
|
+
# Authorization window to pop up in the browser.
|
|
12
|
+
#
|
|
13
|
+
# Code adapted from {Ryan Tomayko}[http://tomayko.com/about] and
|
|
14
|
+
# {Christopher Schneid}[http://gittr.com], shared under an MIT License
|
|
15
|
+
module Authorization
|
|
16
|
+
module Helpers
|
|
17
|
+
# Redefine this method on your helpers block to actually contain
|
|
18
|
+
# your authorization logic.
|
|
19
|
+
def authorize(username, password)
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# From you app, call set :authorization_realm, "my app" to set this
|
|
24
|
+
# or define a #authorization_realm method in your helpers block.
|
|
25
|
+
def authorization_realm
|
|
26
|
+
options.authorization_realm
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Call in any event that requires authentication
|
|
30
|
+
def login_required
|
|
31
|
+
return if authorized?
|
|
32
|
+
unauthorized! unless auth.provided?
|
|
33
|
+
bad_request! unless auth.basic?
|
|
34
|
+
unauthorized! unless authorize(*auth.credentials)
|
|
35
|
+
request.env['REMOTE_USER'] = auth.username
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Convenience method to determine if a user is logged in
|
|
39
|
+
def authorized?
|
|
40
|
+
!!current_user
|
|
41
|
+
end
|
|
42
|
+
alias :logged_in? :authorized?
|
|
43
|
+
|
|
44
|
+
# Name provided by the current user to log in
|
|
45
|
+
def current_user
|
|
46
|
+
request.env['REMOTE_USER'] = auth.username if
|
|
47
|
+
auth.provided? && auth.basic? && authorize(*auth.credentials)
|
|
48
|
+
request.env['REMOTE_USER']
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
def auth
|
|
53
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def unauthorized!(realm=authorization_realm)
|
|
57
|
+
response["WWW-Authenticate"] = %(Basic realm="#{realm}")
|
|
58
|
+
throw :halt, [ 401, 'Authorization Required' ]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def bad_request!
|
|
62
|
+
throw :halt, [ 400, 'Bad Request' ]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
module DSL
|
|
67
|
+
def protecting(*patterns)
|
|
68
|
+
@protected_routes = []
|
|
69
|
+
@protected_routes += patterns
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def protecting?(path)
|
|
73
|
+
@protected_routes && @protected_routes.any? { |pattern| path =~ pattern }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def authorize(realm="app", &block)
|
|
77
|
+
define_method(:authorization_realm) { realm }
|
|
78
|
+
define_method(:authorize, &block)
|
|
79
|
+
|
|
80
|
+
before do
|
|
81
|
+
login_required if self.class.protecting?(request.path_info)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def self.registered(app)
|
|
87
|
+
Sinatra.register(DSL)
|
|
88
|
+
app.helpers Helpers
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
register Authorization
|
|
93
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = "sinatra-authorization"
|
|
3
|
+
s.rubyforge_project = "integrity"
|
|
4
|
+
s.version = "1.1"
|
|
5
|
+
s.date = "2009-04-19"
|
|
6
|
+
s.summary = "HTTP Authorization helpers for Sinatra."
|
|
7
|
+
s.description = "HTTP Authorization helpers for Sinatra."
|
|
8
|
+
s.homepage = "http://github.com/integrity/sinatra-authorization"
|
|
9
|
+
s.email = "info@integrityapp.com"
|
|
10
|
+
s.authors = ["Nicolás Sanguinetti", "Simon Rozet"]
|
|
11
|
+
s.has_rdoc = false
|
|
12
|
+
s.files = %w[
|
|
13
|
+
README.rdoc
|
|
14
|
+
Rakefile
|
|
15
|
+
sinatra-authorization.gemspec
|
|
16
|
+
lib/sinatra/authorization.rb
|
|
17
|
+
test/authorization_test.rb
|
|
18
|
+
]
|
|
19
|
+
s.add_dependency("sinatra", [">= 0.9.1.1"])
|
|
20
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
require "test/unit"
|
|
2
|
+
require "rack/test"
|
|
3
|
+
|
|
4
|
+
gem 'jeremymcanally-context', '0.5.5'
|
|
5
|
+
require "context"
|
|
6
|
+
gem 'jeremymcanally-pending', '0.1'
|
|
7
|
+
require "pending"
|
|
8
|
+
|
|
9
|
+
require File.dirname(__FILE__) + "/../lib/sinatra/authorization"
|
|
10
|
+
|
|
11
|
+
class AuthorizationApp < Sinatra::Default
|
|
12
|
+
set :environment, :test
|
|
13
|
+
|
|
14
|
+
get "/" do
|
|
15
|
+
login_required
|
|
16
|
+
|
|
17
|
+
"Welcome #{current_user} to the protected zone (#{authorized?.to_s})"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
get '/public' do
|
|
21
|
+
if authorized?
|
|
22
|
+
"#{current_user} is logged in!"
|
|
23
|
+
else
|
|
24
|
+
"Some anonymous user"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def authorize(username, password)
|
|
29
|
+
username == "user" && password = "test"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def authorization_realm
|
|
33
|
+
"Move on"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class AnotherAuthApp < Sinatra::Default
|
|
38
|
+
set :environment, :test
|
|
39
|
+
set :authorization_realm, 'Continue'
|
|
40
|
+
|
|
41
|
+
get "/" do
|
|
42
|
+
login_required
|
|
43
|
+
|
|
44
|
+
"Welcome in protected zone"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def authorize(username, password)
|
|
48
|
+
username == "user" && password = "test"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class SugarApp < Sinatra::Default
|
|
53
|
+
set :environment, :test
|
|
54
|
+
|
|
55
|
+
authorize 'The Sugar App' do |*credentials|
|
|
56
|
+
credentials == ['fizz', 'buzz']
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
protecting %r|/sekret|
|
|
60
|
+
|
|
61
|
+
get '/' do
|
|
62
|
+
login_required
|
|
63
|
+
'ok'
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
get '/ok' do
|
|
67
|
+
'ok'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
get '/sekret' do
|
|
71
|
+
'ok'
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class SinatraAuthorizationTest < Test::Unit::TestCase
|
|
76
|
+
before do
|
|
77
|
+
@session = Rack::Test::Session.new(AuthorizationApp)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def basic_auth(user="user", password="test")
|
|
81
|
+
credentials = ["#{user}:#{password}"].pack("m*")
|
|
82
|
+
|
|
83
|
+
{ "HTTP_AUTHORIZATION" => "Basic #{credentials}" }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "is authorized with correct credentials" do
|
|
87
|
+
@session.get "/", {}, basic_auth
|
|
88
|
+
assert_equal 200, @session.last_response.status
|
|
89
|
+
assert_equal 'user', @session.last_request.env['REMOTE_USER']
|
|
90
|
+
|
|
91
|
+
# Ensure current_user and authorized? works. The body indicates this
|
|
92
|
+
assert_equal "Welcome user to the protected zone (true)",
|
|
93
|
+
@session.last_response.body
|
|
94
|
+
|
|
95
|
+
# Request a public page in the same session still logged in
|
|
96
|
+
@session.get "/public", {}, basic_auth
|
|
97
|
+
assert_equal 200, @session.last_response.status
|
|
98
|
+
assert_equal 'user', @session.last_request.env['REMOTE_USER']
|
|
99
|
+
assert_equal "user is logged in!", @session.last_response.body
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "can access a public page" do
|
|
103
|
+
@session.get "/public"
|
|
104
|
+
assert_equal "Some anonymous user", @session.last_response.body
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "is unauthorized without credentials" do
|
|
108
|
+
@session.get "/"
|
|
109
|
+
assert_equal 401, @session.last_response.status
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "is unauthorized with incorrect credentials" do
|
|
113
|
+
@session.get "/", {}, basic_auth("evil", "wrong")
|
|
114
|
+
assert_equal 401, @session.last_response.status
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "returns specified realm" do
|
|
118
|
+
@session.get "/"
|
|
119
|
+
assert_equal %Q(Basic realm="Move on"), @session.last_response["WWW-Authenticate"]
|
|
120
|
+
|
|
121
|
+
@session = Rack::Test::Session.new(AnotherAuthApp)
|
|
122
|
+
@session.get "/"
|
|
123
|
+
assert_equal %Q(Basic realm="Continue"), @session.last_response["WWW-Authenticate"]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "returns a 400, Bad Request if not basic auth" do
|
|
127
|
+
@session.get "/", {}, { "HTTP_AUTHORIZATION" => "Foo bar" }
|
|
128
|
+
assert_equal 400, @session.last_response.status
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "sugarly" do
|
|
132
|
+
before do
|
|
133
|
+
@session = Rack::Test::Session.new(SugarApp)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "generates #authorize method via DSL" do
|
|
137
|
+
@session.get '/'
|
|
138
|
+
assert_equal 401, @session.last_response.status
|
|
139
|
+
|
|
140
|
+
@session.get '/', {}, basic_auth('fizz', 'buzz')
|
|
141
|
+
assert_equal 200, @session.last_response.status
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "allows realm to be specified" do
|
|
145
|
+
@session.get '/'
|
|
146
|
+
assert_equal %Q(Basic realm="The Sugar App"), @session.last_response["WWW-Authenticate"]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "allows protected actions to be specified" do
|
|
150
|
+
@session.get '/ok'
|
|
151
|
+
assert_equal 200, @session.last_response.status
|
|
152
|
+
|
|
153
|
+
@session.get '/sekret'
|
|
154
|
+
assert_equal 401, @session.last_response.status
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: eric1234-sinatra-authorization
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: "1.1"
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- "Nicol\xC3\xA1s Sanguinetti"
|
|
8
|
+
- Simon Rozet
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2009-04-19 00:00:00 -07:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: sinatra
|
|
18
|
+
type: :runtime
|
|
19
|
+
version_requirement:
|
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ">="
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: 0.9.1.1
|
|
25
|
+
version:
|
|
26
|
+
description: HTTP Authorization helpers for Sinatra.
|
|
27
|
+
email: info@integrityapp.com
|
|
28
|
+
executables: []
|
|
29
|
+
|
|
30
|
+
extensions: []
|
|
31
|
+
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
|
|
34
|
+
files:
|
|
35
|
+
- README.rdoc
|
|
36
|
+
- Rakefile
|
|
37
|
+
- sinatra-authorization.gemspec
|
|
38
|
+
- lib/sinatra/authorization.rb
|
|
39
|
+
- test/authorization_test.rb
|
|
40
|
+
has_rdoc: false
|
|
41
|
+
homepage: http://github.com/integrity/sinatra-authorization
|
|
42
|
+
licenses:
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: "0"
|
|
53
|
+
version:
|
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: "0"
|
|
59
|
+
version:
|
|
60
|
+
requirements: []
|
|
61
|
+
|
|
62
|
+
rubyforge_project: integrity
|
|
63
|
+
rubygems_version: 1.3.5
|
|
64
|
+
signing_key:
|
|
65
|
+
specification_version: 2
|
|
66
|
+
summary: HTTP Authorization helpers for Sinatra.
|
|
67
|
+
test_files: []
|
|
68
|
+
|