sinatra-fx-auth 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a6f47b09ab7c03c218d5f31d127b7ded750369b
4
+ data.tar.gz: 374c52ff11220a5726cd5238b3da53b0368de8f7
5
+ SHA512:
6
+ metadata.gz: a1428420f5b125f9b93190dfe1f2e1ac04ee21b813f57e2674d072e2f99672c50c0567e6c3ab120fdfd11d7da219ef6c4d69ff9248c76758873ea609f090db1b
7
+ data.tar.gz: 3cc1af4f9055ff0269e58aa985b56d71b5450a3d82ba96683c90005f3c22aaf78a81a67a252fe312250f9cc9f9a0161c5bb73fcd1fc15238c72e6db136328a14
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .idea
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Dave Jackson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # Sinatra::Fx::Auth
2
+
3
+ Sinatra::Fx::Auth is a RESTful Authentication and Role-based Authorization extension for Sinatra.
4
+ No sessions or cookies required.
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'sinatra-fx-auth'
12
+
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install sinatra-fx-auth
22
+
23
+
24
+ ## Usage
25
+ ``` ruby
26
+ require 'sinatra/base'
27
+ require 'sinatra/fx-auth'
28
+
29
+ class MyApp < Sinatra::Base
30
+ register Sinatra::Fx::Auth
31
+
32
+ # Accessible by all
33
+ get '/products' do
34
+ # ...
35
+ end
36
+
37
+ # Requires an authenticated :admin
38
+ put '/products/:id', :auth => :admin do
39
+ # ...
40
+ end
41
+
42
+ # Requires an authenticated :admin or the :user with the given :id
43
+ get '/customers/:id/cart', :auth => [:admin, :user] do
44
+ # ...
45
+ end
46
+ end
47
+ ```
48
+
49
+
50
+ ## Contributing
51
+
52
+ 1. Fork it
53
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
54
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
55
+ 4. Push to the branch (`git push origin my-new-feature`)
56
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rubygems'
3
+ require 'cucumber'
4
+ require 'cucumber/rake/task'
5
+
6
+
7
+ Cucumber::Rake::Task.new :test do |task|
8
+ task.cucumber_opts = "features --format pretty"
9
+ end
File without changes
@@ -0,0 +1,9 @@
1
+ Feature: API Sign Off
2
+
3
+ Scenario: API Sign Off
4
+
5
+ Given I have a User Profile
6
+ And I sign on with valid credentials
7
+ And I am online
8
+ When the App signs me off
9
+ Then I am offline
@@ -0,0 +1,76 @@
1
+ Feature: API Sign On
2
+
3
+ Scenario: API Valid Credentials
4
+
5
+ Given I have a User Profile
6
+ And I am offline
7
+ When the App signs me on with valid credentials
8
+ Then the App receives a 201 response code
9
+ And the App receives an Auth Token
10
+ # And I am online
11
+
12
+
13
+
14
+ Scenario: API Invalid Credentials
15
+
16
+ Given I have a User Profile
17
+ And I am offline
18
+ When the App tries to sign me on with invalid credentials
19
+ Then the App receives a 401 response code
20
+ And the App receives an Invalid User error
21
+ # And I am offline
22
+
23
+
24
+
25
+ Scenario: API Locked Account
26
+
27
+ Given I have a User Profile
28
+ And I am offline
29
+ When the App tries to sign me on with invalid credentials
30
+ And the App tries to sign me on with invalid credentials
31
+ And the App tries to sign me on with invalid credentials
32
+ Then the App receives a 423 response code
33
+ And the App receives a Locked User error
34
+ # And I am locked out
35
+
36
+
37
+
38
+ Scenario: API Locked Valid Sign On Attempt
39
+
40
+ Given I have a Locked User Profile
41
+ When the App signs me on with valid credentials
42
+ Then the App receives a 423 response code
43
+ And the App receives a Locked User error
44
+ # And I am locked out
45
+
46
+
47
+
48
+ Scenario: API Locked Invalid Sign On Attempt
49
+
50
+ Given I have a Locked User Profile
51
+ When the App tries to sign me on with invalid credentials
52
+ Then the App receives a 423 response code
53
+ And the App receives a Locked User error
54
+ # And I am locked out
55
+
56
+
57
+
58
+ Scenario: API Online Valid Sign On Attempt
59
+
60
+ Given I have a User Profile
61
+ When the App signs me on with valid credentials
62
+ And the App signs me on with valid credentials
63
+ Then the App receives a 201 response code
64
+ And the App receives an Auth Token
65
+ # And I am online
66
+
67
+
68
+ # TODO FIX ME - How should this respond?
69
+ Scenario: API Online Invalid Sign On Attempt
70
+
71
+ Given I have a User Profile
72
+ When the App signs me on with valid credentials
73
+ And the App tries to sign me on with invalid credentials
74
+ Then the App receives a 201 response code
75
+ And the App receives an Auth Token
76
+ # And I am online
@@ -0,0 +1,38 @@
1
+ Feature: API Sign Up
2
+
3
+ Scenario: API Valid Sign Up
4
+
5
+ When the App signs me up with valid credentials
6
+ Then the App receives a 201 response code
7
+ And the App receives an Auth Token
8
+
9
+
10
+ Scenario: API Sign Up with Duplicate Email
11
+
12
+ When the App tries to sign me up with a duplicate email
13
+ Then the App receives a 409 response code
14
+ And the App receives a duplicate email error
15
+
16
+
17
+
18
+ Scenario: API Sign Up with Invalid Email
19
+
20
+ When the App tries to sign me up with an invalid email address
21
+ Then the App receives a 412 response code
22
+ And the App receive an invalid email error
23
+
24
+
25
+ # TODO Return 422 for semantic error?
26
+ Scenario: API Sign Up with Missing Email
27
+
28
+ When the App tries to sign me up with a missing email address
29
+ Then the App receives a 412 response code
30
+ And the App receives a missing email error
31
+
32
+
33
+
34
+ Scenario: API Sign Up with Missing Password
35
+
36
+ When the App tries to sign me up with a missing password
37
+ Then the App receives a 412 response code
38
+ And the App receives a missing password error
@@ -0,0 +1,13 @@
1
+
2
+ When /^the App signs me off$/ do
3
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
4
+ @client.header 'X-AUTH-TOKEN', @user.pass_key.token
5
+ @client.delete '/profiles/' + @user.id.to_s + '/key'
6
+ @user.reload # Refresh from the database
7
+ end
8
+
9
+
10
+ Then /^I am offline$/ do
11
+ @user.status.should == :offline
12
+ end
13
+
@@ -0,0 +1,18 @@
1
+
2
+ When /^the App tries to sign me on with invalid credentials$/ do
3
+ credentials = {
4
+ :profile => {
5
+ :email => "bad@email.com",
6
+ :pass_phrase => "bad-password"
7
+ }
8
+ }
9
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
10
+ @client.post '/profiles/' + @user.id.to_s + '/key', credentials
11
+ end
12
+
13
+
14
+ When /^the App receives an Invalid User error$/ do
15
+ received = JSON.parse @client.last_response.body
16
+ expected = JSON.parse({:error => "The email or pass phrase you provided doesn't match our records."}.to_json)
17
+ received.should == expected
18
+ end
@@ -0,0 +1,13 @@
1
+
2
+ When /^the App receives a Locked User error$/ do
3
+ received = JSON.parse @client.last_response.body
4
+ expected = JSON.parse({:error => "Your account is locked. You can try to sign on again in 30 minutes."}.to_json)
5
+ received.should == expected
6
+ end
7
+
8
+
9
+ Given /^I have a Locked User Profile$/ do
10
+ @user = FactoryGirl.create :user_profile
11
+ @user.status = :locked
12
+ @user.save
13
+ end
@@ -0,0 +1,27 @@
1
+
2
+ Given /^I have a User Profile$/ do
3
+ @user = FactoryGirl.create :user_profile
4
+ @user.save # TODO Determine why this is necessary
5
+ end
6
+
7
+
8
+ When /^the App signs me on with valid credentials$/ do
9
+ credentials = {
10
+ :profile => {
11
+ :email => @user.email,
12
+ :pass_phrase => "password"
13
+ }
14
+ }
15
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
16
+ @client.post '/profiles/' + @user.id.to_s + '/key', credentials
17
+ end
18
+
19
+
20
+ When /^I sign on with valid credentials$/ do
21
+ @user.sign_on @user.email, 'password'
22
+ end
23
+
24
+
25
+ When /^I am online$/ do
26
+ @user.status.should == :online
27
+ end
@@ -0,0 +1,20 @@
1
+
2
+ When /^the App tries to sign me up with a duplicate email$/ do
3
+ email = FactoryGirl.generate :email
4
+ @user = AuthFx::UserProfile.sign_up email, "password"
5
+ credentials = {
6
+ :profile => {
7
+ :email => email,
8
+ :pass_phrase => "password"
9
+ }
10
+ }
11
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
12
+ @client.post '/profiles/', credentials
13
+ end
14
+
15
+
16
+ Then /^the App receives a duplicate email error$/ do
17
+ received = JSON.parse @client.last_response.body
18
+ expected = JSON.parse({:error => "We already have that email."}.to_json)
19
+ received.should == expected
20
+ end
@@ -0,0 +1,18 @@
1
+
2
+ When /^the App tries to sign me up with an invalid email address$/ do
3
+ credentials = {
4
+ :profile => {
5
+ :email => "bad.email.com",
6
+ :pass_phrase => "password"
7
+ }
8
+ }
9
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
10
+ @client.post '/profiles/', credentials
11
+ end
12
+
13
+
14
+ Then /^the App receive an invalid email error$/ do
15
+ received = JSON.parse @client.last_response.body
16
+ expected = JSON.parse({:errors => {:email => ["Doesn't look like an email address to me ..."]}}.to_json)
17
+ received.should == expected
18
+ end
@@ -0,0 +1,18 @@
1
+
2
+ When /^the App tries to sign me up with a missing email address$/ do
3
+ credentials = {
4
+ :profile => {
5
+ :email => "",
6
+ :pass_phrase => "password"
7
+ }
8
+ }
9
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
10
+ @client.post '/profiles/', credentials
11
+ end
12
+
13
+
14
+ Then /^the App receives a missing email error$/ do
15
+ received = JSON.parse @client.last_response.body
16
+ expected = JSON.parse({:errors => {:email => ["We need your email address."]}}.to_json)
17
+ received.should == expected
18
+ end
@@ -0,0 +1,23 @@
1
+
2
+ When /^the App signs me up with valid credentials$/ do
3
+ email = FactoryGirl.generate :email
4
+ credentials = {
5
+ :profile => {
6
+ :email => email,
7
+ :pass_phrase => "password"
8
+ }
9
+ }
10
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
11
+ @client.post '/profiles/', credentials
12
+ end
13
+
14
+
15
+ Then /^the App receives a (\d+) response code$/ do |arg|
16
+ @client.last_response.status.should == arg.to_i
17
+ end
18
+
19
+
20
+ Then /^the App receives an Auth Token$/ do
21
+ token = @client.last_response.headers['X-AUTH-TOKEN']
22
+ token.should_not.nil?
23
+ end
@@ -0,0 +1,19 @@
1
+
2
+ When /^the App tries to sign me up with a missing password$/ do
3
+ email = FactoryGirl.generate :email
4
+ credentials = {
5
+ :profile => {
6
+ :email => email,
7
+ :pass_phrase => ""
8
+ }
9
+ }
10
+ @client = Rack::Test::Session.new Rack::MockSession.new Test::App
11
+ @client.post '/profiles/', credentials
12
+ end
13
+
14
+
15
+ Then /^the App receives a missing password error$/ do
16
+ received = JSON.parse @client.last_response.body
17
+ expected = JSON.parse({:errors => {:pass_phrase => ["Pass phrase must be between 5 and 50 characters long"]}}.to_json)
18
+ received.should == expected
19
+ end
@@ -0,0 +1,23 @@
1
+ require 'sinatra/base'
2
+ require 'sinatra/fx-auth'
3
+ require 'rack/test'
4
+
5
+ require 'fx-auth/models'
6
+ require './test/factories'
7
+
8
+
9
+ module Test
10
+ class App < Sinatra::Base
11
+ register Sinatra::Fx::Auth
12
+ end
13
+ end
14
+
15
+
16
+ module AppHelper
17
+ def app
18
+ Test::App
19
+ end
20
+ end
21
+
22
+
23
+ World(Rack::Test::Methods, AppHelper)
@@ -0,0 +1,263 @@
1
+ require 'fx-auth/models'
2
+
3
+
4
+ module Sinatra
5
+ module Fx
6
+ module Auth
7
+ include AuthFx
8
+
9
+ module Helpers
10
+
11
+ def authenticated?
12
+ authenticated = false
13
+ profile, token = token_credentials
14
+ authenticated = profile.authenticate? token if profile #, request.ip if profile
15
+ log_authentication_failure profile, token unless authenticated #, request.ip unless authenticated
16
+ authenticated
17
+ end
18
+
19
+
20
+ def authorized? *roles
21
+ authorized = false
22
+ profile, token = token_credentials
23
+ authorized = profile.authorized? roles if profile
24
+ log_authorization_failure profile, roles unless authorized
25
+ authorized
26
+ end
27
+
28
+
29
+ private
30
+
31
+
32
+ def token_credentials
33
+ profile = nil
34
+ token = request.env['HTTP_X_AUTH_TOKEN']
35
+ unless token.nil?
36
+ passkey = Auth::PassKey.first :token => token
37
+ profile = passkey.user_profile if passkey
38
+ end
39
+ return profile, token
40
+ end
41
+
42
+
43
+ def param_credentials
44
+ return params[:profile][:email], params[:profile][:pass_phrase]
45
+ end
46
+
47
+
48
+ def valid_params?
49
+ # TODO Handle JSON body as well as FORM encoding
50
+ # request.body.rewind # in case someone already read it
51
+ # profile = JSON.parse request.body.read
52
+
53
+ params[:profile] and params[:profile][:email] and params[:profile][:pass_phrase]
54
+ end
55
+
56
+
57
+ def error_message
58
+ message = env['sinatra.error'].message
59
+ logger.error '### Error: ' + message + ' ###'
60
+ {:error => message}.to_json
61
+ end
62
+
63
+
64
+ def find_user
65
+ profile = Auth::UserProfile.get params[:id]
66
+ raise Auth::MissingUserError unless profile
67
+ profile
68
+ end
69
+
70
+
71
+ def profile_exclusions
72
+ [
73
+ :created_at,
74
+ :updated_at,
75
+ :email_verification_code,
76
+ :pass_phrase,
77
+ :pass_phrase_crypt,
78
+ :pass_phrase_expires_at,
79
+ :sign_on_attempts,
80
+ :locked_until
81
+ ]
82
+ end
83
+
84
+
85
+ def pass_key_exclusions
86
+ [
87
+ :id,
88
+ :created_at,
89
+ :updated_at,
90
+ :user_profile_id
91
+ ]
92
+ end
93
+
94
+
95
+ def log_authentication_failure profile, token #, ip_address
96
+ logger.warn '### BEGIN Authentication FAILURE ###'
97
+ if profile
98
+ logger.warn ' Profile: ' + profile.id.to_s
99
+ logger.warn ' Status: ' + profile.status.to_s if profile.status != :online
100
+ if profile.pass_key
101
+ logger.warn ' Token: ' + profile.pass_key.token + ' != Attempted: ' + token if profile.pass_key.token != token
102
+ logger.warn ' Expired: ' + profile.pass_key.expires.to_s + ' < ' + Time.now.to_s if profile.pass_key.expired?
103
+ #logger.warn ' IP: ' + profile.pass_key.ip_address.to_s + ' != Attempted: ' + ip_address if profile.pass_key.ip_address != ip_address
104
+ else
105
+ logger.warn ' PassKey: Missing'
106
+ end
107
+ else
108
+ logger.warn ' Profile: Not Found'
109
+ end
110
+ logger.warn '### END Authentication FAILURE ###'
111
+ end
112
+
113
+
114
+ def log_authorization_failure profile, allowed_roles
115
+ logger.warn '### BEGIN Authorization FAILURE ###'
116
+ if profile
117
+ profile_roles = []
118
+ profile.roles.each { |role| profile_roles.push role.name.to_sym }
119
+ logger.warn ' Profile: ' + profile.id.to_s
120
+ logger.warn ' Allowed Roles: ' + allowed_roles.to_s
121
+ logger.warn ' Profile Roles: ' + profile_roles.to_s
122
+ else
123
+ logger.warn ' Profile: Not Found'
124
+ end
125
+ logger.warn '### END Authorization FAILURE ###'
126
+ end
127
+
128
+ end
129
+
130
+
131
+ def self.registered app
132
+ app.helpers Auth::Helpers
133
+
134
+ app.enable :logging
135
+
136
+ app.set :raise_errors, Proc.new { false }
137
+ app.set :show_exceptions, false
138
+
139
+
140
+ app.set :auth do |*roles|
141
+ condition do
142
+ unless authenticated? and authorized? *roles
143
+ halt 401 # TODO Return any additional info? Expired session, etc.?
144
+ end
145
+ end
146
+ end
147
+
148
+
149
+ app.before do
150
+ content_type 'application/json' # TODO Support other representations, XML, etc.
151
+ end
152
+
153
+
154
+ # Sign Up
155
+ app.post '/profiles/?' do
156
+ halt 422 unless valid_params?
157
+
158
+ email, pass_phrase = param_credentials
159
+ profile = UserProfile.sign_up email, pass_phrase #, request.ip
160
+
161
+ if profile.errors.length == 0
162
+ headers "location" => '/profiles/' + profile.id.to_s,
163
+ "X-AUTH-TOKEN" => profile.pass_key.token
164
+ body profile.to_json :exclude => profile_exclusions
165
+ status 201
166
+
167
+ else
168
+ errs = {:errors => profile.errors.to_h}
169
+ body errs.to_json
170
+ status 412
171
+ end
172
+ end
173
+
174
+
175
+ # Sign On
176
+ app.post '/profiles/:id/key/?' do
177
+ profile = find_user
178
+
179
+ raise InvalidUserError unless valid_params?
180
+ raise LockedUserError.new :locked_until => profile.locked_until if profile.status == :locked
181
+
182
+ email, pass_phrase = param_credentials
183
+ pass_key = profile.sign_on email, pass_phrase #, request.ip
184
+
185
+ if pass_key
186
+ headers "location" => '/profiles/' + profile.id.to_s + '/key',
187
+ "X-AUTH-TOKEN" => pass_key.token
188
+ body pass_key.to_json :exclude => pass_key_exclusions
189
+ status 201
190
+ end
191
+ end
192
+
193
+
194
+ # Sign Off
195
+ app.delete '/profiles/:id/key', :auth => [:admin, :user] do
196
+ profile = find_user
197
+ profile.sign_off
198
+ end
199
+
200
+
201
+ app.get '/profiles/:id', :auth => [:admin, :user] do
202
+ profile = find_user
203
+ profile.to_json :exclude => profile_exclusions
204
+ end
205
+
206
+
207
+ app.put '/profiles/:id', :auth => [:admin, :user] do
208
+ profile = find_user
209
+ if profile.update params[:profile]
210
+ profile.to_json :exclude => profile_exclusions
211
+ else
212
+ errs = {:errors => profile.errors.to_h}
213
+ body errs.to_json
214
+ status 412
215
+ end
216
+ end
217
+
218
+
219
+ app.get '/profiles/?', :auth => :admin do
220
+ UserProfile.all.to_json :exclude => profile_exclusions
221
+ end
222
+
223
+
224
+ app.delete '/profiles/:id', :auth => :admin do
225
+ profile = find_user
226
+ unless profile.destroy
227
+ errs = {:errors => profile.errors.to_h}
228
+ body errs.to_json
229
+ status 412
230
+ end
231
+ end
232
+
233
+
234
+ app.error InvalidUserError do
235
+ halt 401, error_message
236
+ end
237
+
238
+
239
+ app.error MissingUserError do
240
+ halt 404, error_message
241
+ end
242
+
243
+
244
+ app.error DuplicateUserError do
245
+ halt 409, error_message
246
+ end
247
+
248
+
249
+ app.error LockedUserError do
250
+ halt 423, error_message
251
+ end
252
+
253
+
254
+ app.error do
255
+ halt 500, error_message
256
+ end
257
+
258
+ end
259
+
260
+ #register Auth
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,9 @@
1
+ module Sinatra
2
+ module Fx
3
+
4
+ module Auth
5
+ VERSION = "0.1.0"
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ require "sinatra/version"
2
+ require "sinatra/fx-auth"
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'sinatra/version'
7
+
8
+
9
+ Gem::Specification.new do |gem|
10
+ gem.name = "sinatra-fx-auth"
11
+ gem.version = Sinatra::Fx::Auth::VERSION
12
+
13
+ gem.authors = ["Dave Jackson"]
14
+ gem.email = %w(dave.jackson@anywarefx.com)
15
+ gem.description = %q{Sinatra::Fx::Auth - RESTful Authentication with Role-based Authorization for Sinatra}
16
+ gem.summary = %q{Sinatra::Fx::Auth - RESTful Authentication with Role-based Authorization for Sinatra}
17
+ gem.homepage = ""
18
+
19
+ gem.files = `git ls-files`.split($/)
20
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
21
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
+ gem.require_paths = %w(lib)
23
+
24
+ gem.add_dependency 'sinatra'
25
+ gem.add_dependency 'fx-auth'
26
+
27
+ gem.add_development_dependency 'rake'
28
+ gem.add_development_dependency 'cucumber'
29
+ gem.add_development_dependency 'rspec'
30
+ gem.add_development_dependency 'factory_girl'
31
+ gem.add_development_dependency 'rack-test'
32
+ gem.add_development_dependency 'dm-sqlite-adapter'
33
+ end
data/test/factories.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'factory_girl'
2
+ require 'test/seeds'
3
+
4
+
5
+ FactoryGirl.define do
6
+
7
+ sequence :email do |n|
8
+ "profile#{n}@example.com"
9
+ end
10
+
11
+
12
+ factory :user_profile, :class => AuthFx::UserProfile do
13
+ email
14
+ pass_phrase "password"
15
+ end
16
+
17
+ end
data/test/seeds.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'fx-auth/models'
2
+
3
+
4
+ DataMapper::Logger.new $stdout, :debug
5
+ DataMapper.setup :default, 'sqlite::memory:'
6
+ DataMapper.auto_migrate!
7
+
8
+
9
+ AuthFx::UserProfile.create(
10
+ {
11
+ :email => 'admin@authfx.com',
12
+ :pass_phrase => 'password',
13
+
14
+ :roles => [
15
+ {
16
+ :name => 'admin'
17
+ },
18
+ {
19
+ :name => 'user'
20
+ }
21
+ ]
22
+ }
23
+ )
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-fx-auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dave Jackson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ name: sinatra
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ name: fx-auth
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: rake
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ name: cucumber
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: rspec
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ name: factory_girl
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ name: rack-test
104
+ prerelease: false
105
+ type: :development
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ name: dm-sqlite-adapter
118
+ prerelease: false
119
+ type: :development
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Sinatra::Fx::Auth - RESTful Authentication with Role-based Authorization for Sinatra
126
+ email:
127
+ - dave.jackson@anywarefx.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - .gitignore
133
+ - Gemfile
134
+ - LICENSE.txt
135
+ - README.md
136
+ - Rakefile
137
+ - features/api_profile_list.feature
138
+ - features/api_sign_off.feature
139
+ - features/api_sign_on.feature
140
+ - features/api_sign_up.feature
141
+ - features/step_definitions/api_sign_off/api_sign_off.rb
142
+ - features/step_definitions/api_sign_on/api_invalid_credentials.rb
143
+ - features/step_definitions/api_sign_on/api_locked_account.rb
144
+ - features/step_definitions/api_sign_on/api_valid_credentials.rb
145
+ - features/step_definitions/api_sign_up/api_duplicate_email.rb
146
+ - features/step_definitions/api_sign_up/api_invalid_email.rb
147
+ - features/step_definitions/api_sign_up/api_missing_email.rb
148
+ - features/step_definitions/api_sign_up/api_valid_sign_up.rb
149
+ - features/step_definitions/api_sign_up/missing_password.rb
150
+ - features/support/env.rb
151
+ - lib/sinatra-fx-auth.rb
152
+ - lib/sinatra/fx-auth.rb
153
+ - lib/sinatra/version.rb
154
+ - sinatra-fx-auth.gemspec
155
+ - test/factories.rb
156
+ - test/seeds.rb
157
+ homepage: ''
158
+ licenses: []
159
+ metadata: {}
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - '>='
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubyforge_project:
176
+ rubygems_version: 2.1.9
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: Sinatra::Fx::Auth - RESTful Authentication with Role-based Authorization for Sinatra
180
+ test_files:
181
+ - features/api_profile_list.feature
182
+ - features/api_sign_off.feature
183
+ - features/api_sign_on.feature
184
+ - features/api_sign_up.feature
185
+ - features/step_definitions/api_sign_off/api_sign_off.rb
186
+ - features/step_definitions/api_sign_on/api_invalid_credentials.rb
187
+ - features/step_definitions/api_sign_on/api_locked_account.rb
188
+ - features/step_definitions/api_sign_on/api_valid_credentials.rb
189
+ - features/step_definitions/api_sign_up/api_duplicate_email.rb
190
+ - features/step_definitions/api_sign_up/api_invalid_email.rb
191
+ - features/step_definitions/api_sign_up/api_missing_email.rb
192
+ - features/step_definitions/api_sign_up/api_valid_sign_up.rb
193
+ - features/step_definitions/api_sign_up/missing_password.rb
194
+ - features/support/env.rb
195
+ - test/factories.rb
196
+ - test/seeds.rb