sinatra-authorize 0.0.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/.gitignore +2 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +37 -0
- data/Rakefile +7 -0
- data/lib/sinatra/authorize.rb +77 -0
- data/lib/sinatra-authorize/version.rb +5 -0
- data/readme.md +108 -0
- data/sinatra-authorize.gemspec +29 -0
- data/spec/sinatra/authorize_spec.rb +148 -0
- data/spec/spec_helper.rb +19 -0
- metadata +150 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sinatra-authorize (0.0.0)
|
5
|
+
sinatra (>= 1.2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.1.2)
|
11
|
+
rack (1.2.2)
|
12
|
+
rack-test (0.5.7)
|
13
|
+
rack (>= 1.0)
|
14
|
+
rake (0.8.7)
|
15
|
+
rspec (2.5.0)
|
16
|
+
rspec-core (~> 2.5.0)
|
17
|
+
rspec-expectations (~> 2.5.0)
|
18
|
+
rspec-mocks (~> 2.5.0)
|
19
|
+
rspec-core (2.5.1)
|
20
|
+
rspec-expectations (2.5.0)
|
21
|
+
diff-lcs (~> 1.1.2)
|
22
|
+
rspec-mocks (2.5.0)
|
23
|
+
sinatra (1.2.2)
|
24
|
+
rack (~> 1.1)
|
25
|
+
tilt (>= 1.2.2, < 2.0)
|
26
|
+
tilt (1.2.2)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
bundler (>= 1.0.0.rc.5)
|
33
|
+
rack-test (>= 0.5.7)
|
34
|
+
rake (>= 0.8)
|
35
|
+
rspec (>= 2.4)
|
36
|
+
sinatra (>= 1.2)
|
37
|
+
sinatra-authorize!
|
data/Rakefile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module Authorize
|
5
|
+
class Condition < Proc; end
|
6
|
+
|
7
|
+
def authorize(opts = {}, &block)
|
8
|
+
opts = {opts => []} if opts.is_a?(Symbol)
|
9
|
+
|
10
|
+
if opts[:deny]
|
11
|
+
args = *(opts[:deny])
|
12
|
+
set(:authorize_default, Proc.new {
|
13
|
+
authorize_condition(:deny, args)
|
14
|
+
})
|
15
|
+
else
|
16
|
+
args = *(opts[:allow] || [])
|
17
|
+
set(:authorize_default, Proc.new {
|
18
|
+
authorize_condition(:allow, args)
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
if block_given?
|
23
|
+
define_method(:authorize_do_block, block)
|
24
|
+
authorize_do = instance_method(:authorize_do_block)
|
25
|
+
remove_method(:authorize_do_block)
|
26
|
+
|
27
|
+
set :authorize_do, Proc.new { authorize_do }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def allow(*args)
|
32
|
+
condition &(authorize_condition(:allow, args))
|
33
|
+
end
|
34
|
+
|
35
|
+
def deny(*args)
|
36
|
+
condition &(authorize_condition(:deny, args))
|
37
|
+
end
|
38
|
+
|
39
|
+
def authorize_condition(rule, args)
|
40
|
+
Condition.new { settings.authorize_do.bind(self).call(rule, args) }
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def registered(app)
|
45
|
+
app.authorize do |rule, args|
|
46
|
+
raise "No authorize block is specified."
|
47
|
+
end
|
48
|
+
|
49
|
+
app.class_eval do
|
50
|
+
alias :old_process_route :process_route
|
51
|
+
|
52
|
+
def process_route(pattern, keys, conditions, &block)
|
53
|
+
authorize_conditions = conditions.select do |cond|
|
54
|
+
cond.is_a?(Authorize::Condition)
|
55
|
+
end
|
56
|
+
|
57
|
+
regular_conditions = conditions - authorize_conditions
|
58
|
+
|
59
|
+
old_process_route(pattern, keys, regular_conditions) do
|
60
|
+
throw :halt, 403 if authorize_route(authorize_conditions) == false
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def authorize_route(conditions)
|
66
|
+
conditions = conditions.dup
|
67
|
+
conditions.unshift(settings.authorize_default)
|
68
|
+
conditions = conditions.collect { |cond| instance_eval(&cond) }
|
69
|
+
conditions.select { |allow| allow == true || allow == false }.last
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
register Authorize
|
77
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# sinatra-authorize
|
2
|
+
|
3
|
+
### Authentication-agnostic rule-based authorization extension for Sinatra
|
4
|
+
|
5
|
+
Provides a flexible rule-based authorization framework:
|
6
|
+
|
7
|
+
* Define `authorize` block for evaluating rules
|
8
|
+
* Set default rule for all routes
|
9
|
+
* Override default rule per route
|
10
|
+
|
11
|
+
Choice of authentication approach is entirely up to the application.
|
12
|
+
|
13
|
+
### Installation
|
14
|
+
|
15
|
+
gem install sinatra-authorize
|
16
|
+
|
17
|
+
### Usage
|
18
|
+
|
19
|
+
Define `authorize` block for evaluating rules, and optionally set the default rule:
|
20
|
+
|
21
|
+
authorize :deny => :all do |rule, args|
|
22
|
+
# evaluate rule
|
23
|
+
end
|
24
|
+
|
25
|
+
Omitting a default rule when defining the `authorize` block makes
|
26
|
+
`:allow => []` the default rule.
|
27
|
+
|
28
|
+
Override default rule per route:
|
29
|
+
|
30
|
+
get '/', :allow => :all do
|
31
|
+
# :allow => :all rule overrides default :deny => :all rule
|
32
|
+
end
|
33
|
+
|
34
|
+
Authorization is performed just before the route is evaluated, after the
|
35
|
+
pattern has been matched and any other conditions have been evaluated.
|
36
|
+
|
37
|
+
#### Usage scenario
|
38
|
+
|
39
|
+
Simple scenario with default `:allow` rule, which is overriden for protected
|
40
|
+
routes:
|
41
|
+
|
42
|
+
require 'sinatra'
|
43
|
+
require 'sinatra/authorize'
|
44
|
+
|
45
|
+
enable :sessions
|
46
|
+
|
47
|
+
authorize do |rule, args|
|
48
|
+
if args == [:user]
|
49
|
+
session[:user] != nil
|
50
|
+
elsif args == [:admin]
|
51
|
+
session[:admin] != nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Availabe to all, as default rule is :allow => []
|
56
|
+
get '/' do
|
57
|
+
end
|
58
|
+
|
59
|
+
# Availabe to all, as default rule is :allow => []
|
60
|
+
post '/authenticate' do
|
61
|
+
if params[:username] == 'username' && params[:password] == 'password'
|
62
|
+
session[:user] = params[:username]
|
63
|
+
|
64
|
+
if session[:user] == 'admin'
|
65
|
+
session[:admin] = true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Only run for authorized user requests, because of override rule
|
71
|
+
get '/content/:id' :allow => :user do
|
72
|
+
end
|
73
|
+
|
74
|
+
# Only run for authorized admin requests, because of override rule
|
75
|
+
get '/admin/content/:id', :allow => :admin do
|
76
|
+
end
|
77
|
+
|
78
|
+
The `authorize` block only needs to handle the `:allow` rules present in the
|
79
|
+
scenario. Also, only the rule arguments used, `:user` and `:admin`, are
|
80
|
+
accounted for. No default rule is set when defining the `authorize` block,
|
81
|
+
thus making `:allow => []` the default rule. The routes `/` and `/authenticate`
|
82
|
+
is evaluated using the default `:allow` rule, whereas the `/content/:id` and
|
83
|
+
`/admin/content:id` routes override the default rule.
|
84
|
+
|
85
|
+
### License
|
86
|
+
|
87
|
+
(The MIT License)
|
88
|
+
|
89
|
+
Copyright (c) 2011 Ole Petter Bang <olepbang@gmail.com>
|
90
|
+
|
91
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
92
|
+
a copy of this software and associated documentation files (the
|
93
|
+
'Software'), to deal in the Software without restriction, including
|
94
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
95
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
96
|
+
permit persons to whom the Software is furnished to do so, subject to
|
97
|
+
the following conditions:
|
98
|
+
|
99
|
+
The above copyright notice and this permission notice shall be
|
100
|
+
included in all copies or substantial portions of the Software.
|
101
|
+
|
102
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
103
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
104
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
105
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
106
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
107
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
108
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
3
|
+
require 'sinatra-authorize/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "sinatra-authorize"
|
7
|
+
s.version = Sinatra::Authorize::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ole Petter Bang"]
|
10
|
+
s.email = ["olepbang@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/gnab/sinatra-authorize"
|
12
|
+
s.summary = "Smooth authentication-agnostic rule-based authorization " +
|
13
|
+
"extension for Sinatra"
|
14
|
+
s.description = s.summary
|
15
|
+
|
16
|
+
s.required_rubygems_version = ">= 1.3.6"
|
17
|
+
s.rubyforge_project = "sinatra-authorize"
|
18
|
+
|
19
|
+
s.add_development_dependency "bundler", ">= 1.0.0.rc.5"
|
20
|
+
s.add_development_dependency "rake", ">= 0.8"
|
21
|
+
s.add_development_dependency "rack-test", ">= 0.5.7"
|
22
|
+
s.add_development_dependency "rspec", ">= 2.4"
|
23
|
+
|
24
|
+
s.add_runtime_dependency "sinatra", ">= 1.2"
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.executables = `git ls-files`.split("\n").select{|f| f =~ /^bin/}
|
28
|
+
s.require_path = 'lib'
|
29
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
shared_examples_for "when no default authorization is set" do
|
4
|
+
it 'should allow route with allow all rule' do
|
5
|
+
app.get('/', :allow => :all) {}
|
6
|
+
get '/'
|
7
|
+
last_response.status.should == 200
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should allow route with deny none rule' do
|
11
|
+
app.get('/', :deny => :none) {}
|
12
|
+
get '/'
|
13
|
+
last_response.status.should == 200
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should deny route with deny all rule' do
|
17
|
+
app.get('/', :deny => :all) {}
|
18
|
+
get '/'
|
19
|
+
last_response.status.should == 403
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should deny route with allow none rule' do
|
23
|
+
app.get('/', :allow => :none) {}
|
24
|
+
get '/'
|
25
|
+
last_response.status.should == 403
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Sinatra::Authorize do
|
30
|
+
|
31
|
+
before :all do
|
32
|
+
app.authorize do |rule, args|
|
33
|
+
allow_default = lambda do |args|
|
34
|
+
if args == [] || args == [:all]
|
35
|
+
true
|
36
|
+
elsif args == [:none]
|
37
|
+
false
|
38
|
+
else
|
39
|
+
raise "Unknown authorization rule argument: #{args}."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if rule == :allow
|
44
|
+
allow_default.call(args)
|
45
|
+
elsif rule == :deny
|
46
|
+
!allow_default.call(args)
|
47
|
+
else
|
48
|
+
raise "Unknown authorization rule: #{rule}."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
before do
|
54
|
+
app.reset!
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should allow routes by default' do
|
58
|
+
app.get('/') {}
|
59
|
+
get '/'
|
60
|
+
last_response.status.should == 200
|
61
|
+
end
|
62
|
+
|
63
|
+
it_behaves_like "when no default authorization is set"
|
64
|
+
|
65
|
+
context "#authorize :allow" do
|
66
|
+
before do
|
67
|
+
app.authorize :allow
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should allow routes by default' do
|
71
|
+
app.get('/') {}
|
72
|
+
get '/'
|
73
|
+
last_response.status.should == 200
|
74
|
+
end
|
75
|
+
|
76
|
+
it_behaves_like "when no default authorization is set"
|
77
|
+
|
78
|
+
context ' => :all' do
|
79
|
+
before do
|
80
|
+
app.authorize :allow => :all
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should allow routes by default' do
|
84
|
+
app.get('/') {}
|
85
|
+
get '/'
|
86
|
+
last_response.status.should == 200
|
87
|
+
end
|
88
|
+
|
89
|
+
it_behaves_like "when no default authorization is set"
|
90
|
+
end
|
91
|
+
|
92
|
+
context ' => :none' do
|
93
|
+
before do
|
94
|
+
app.authorize :allow => :none
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should deny routes by default' do
|
98
|
+
app.get('/') {}
|
99
|
+
get '/'
|
100
|
+
last_response.status.should == 403
|
101
|
+
end
|
102
|
+
|
103
|
+
it_behaves_like "when no default authorization is set"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context '#authorize :deny' do
|
108
|
+
before do
|
109
|
+
app.authorize :deny
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should deny routes by default' do
|
113
|
+
app.get('/') {}
|
114
|
+
get '/'
|
115
|
+
last_response.status.should == 403
|
116
|
+
end
|
117
|
+
|
118
|
+
it_behaves_like "when no default authorization is set"
|
119
|
+
|
120
|
+
context ' => :all' do
|
121
|
+
before do
|
122
|
+
app.authorize :deny => :all
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should deny routes by default' do
|
126
|
+
app.get('/') {}
|
127
|
+
get '/'
|
128
|
+
last_response.status.should == 403
|
129
|
+
end
|
130
|
+
|
131
|
+
it_behaves_like "when no default authorization is set"
|
132
|
+
end
|
133
|
+
|
134
|
+
context ' => :none' do
|
135
|
+
before do
|
136
|
+
app.authorize :deny => :none
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should allow routes by default' do
|
140
|
+
app.get('/') {}
|
141
|
+
get '/'
|
142
|
+
last_response.status.should == 200
|
143
|
+
end
|
144
|
+
|
145
|
+
it_behaves_like "when no default authorization is set"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
3
|
+
ENV['RACK_ENV'] = 'test'
|
4
|
+
|
5
|
+
require 'rspec'
|
6
|
+
require 'rack/test'
|
7
|
+
require 'sinatra/base'
|
8
|
+
require 'sinatra/authorize'
|
9
|
+
|
10
|
+
module SpecHelper
|
11
|
+
def app
|
12
|
+
@app ||= Sinatra::Application
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.include Rack::Test::Methods
|
18
|
+
config.include SpecHelper
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-authorize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ole Petter Bang
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-04-16 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: bundler
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
- rc
|
33
|
+
- 5
|
34
|
+
version: 1.0.0.rc.5
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
- 8
|
48
|
+
version: "0.8"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: rack-test
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
- 5
|
62
|
+
- 7
|
63
|
+
version: 0.5.7
|
64
|
+
type: :development
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: rspec
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 2
|
76
|
+
- 4
|
77
|
+
version: "2.4"
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: sinatra
|
82
|
+
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 1
|
90
|
+
- 2
|
91
|
+
version: "1.2"
|
92
|
+
type: :runtime
|
93
|
+
version_requirements: *id005
|
94
|
+
description: Smooth authentication-agnostic rule-based authorization extension for Sinatra
|
95
|
+
email:
|
96
|
+
- olepbang@gmail.com
|
97
|
+
executables: []
|
98
|
+
|
99
|
+
extensions: []
|
100
|
+
|
101
|
+
extra_rdoc_files: []
|
102
|
+
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- .rspec
|
106
|
+
- Gemfile
|
107
|
+
- Gemfile.lock
|
108
|
+
- Rakefile
|
109
|
+
- lib/sinatra-authorize/version.rb
|
110
|
+
- lib/sinatra/authorize.rb
|
111
|
+
- readme.md
|
112
|
+
- sinatra-authorize.gemspec
|
113
|
+
- spec/sinatra/authorize_spec.rb
|
114
|
+
- spec/spec_helper.rb
|
115
|
+
has_rdoc: true
|
116
|
+
homepage: https://github.com/gnab/sinatra-authorize
|
117
|
+
licenses: []
|
118
|
+
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
segments:
|
130
|
+
- 0
|
131
|
+
version: "0"
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
segments:
|
138
|
+
- 1
|
139
|
+
- 3
|
140
|
+
- 6
|
141
|
+
version: 1.3.6
|
142
|
+
requirements: []
|
143
|
+
|
144
|
+
rubyforge_project: sinatra-authorize
|
145
|
+
rubygems_version: 1.3.7
|
146
|
+
signing_key:
|
147
|
+
specification_version: 3
|
148
|
+
summary: Smooth authentication-agnostic rule-based authorization extension for Sinatra
|
149
|
+
test_files: []
|
150
|
+
|