aurora 0.0.1 → 0.1.10

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.
@@ -0,0 +1,13 @@
1
+ class CreateUsers < Sequel::Migration
2
+ def up
3
+ create_table :users do
4
+ primary_key :id
5
+ varchar :username, :size => 16, :unique => true, :null => false
6
+ varchar :password, :size => 32, :null => false
7
+ text :permissions, :null => false
8
+ end
9
+ end
10
+ def down
11
+ execute 'DROP TABLE users'
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class CreateTokens < Sequel::Migration
2
+ def up
3
+ create_table :tokens do
4
+ primary_key :id
5
+ varchar :username, :size => 16, :null => false
6
+ varchar :token, :size => 32, :null => false
7
+ datetime :expires_at, :null => false
8
+ end
9
+ end
10
+ def down
11
+ execute 'DROP TABLE tokens'
12
+ end
13
+ end
@@ -1,26 +1,274 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
1
+ #!/usr/bin/env ruby
3
2
  #--
4
- # Created by Matt Todd on 2007-11-10.
5
- # Copyright (c) 2007 The HUB, Clayton State University. All rights reserved.
3
+ # Created by Matt Todd on 2008-01-11.
4
+ # Copyright (c) 2008. All rights reserved.
6
5
  #++
7
6
 
7
+ $:.unshift File.dirname(File.join('..', __FILE__))
8
+ $:.unshift File.dirname(__FILE__)
9
+
8
10
  #--
9
- # Dependencies
11
+ # dependencies
10
12
  #++
11
13
 
12
- require 'rubygems'
13
- require 'logger'
14
- require 'uri'
15
- require 'json'
16
- require 'digest/md5'
17
- require 'mongrel'
14
+ %w(rubygems aurora halcyon/server sequel digest/md5).each {|dep|require dep}
18
15
 
19
16
  #--
20
- # Module
17
+ # module
21
18
  #++
22
19
 
23
- require 'server/base'
24
- require 'server/server'
25
- require 'server/handler'
26
- require 'server/token'
20
+ module Aurora
21
+
22
+ # = Aurora Server
23
+ #
24
+ # The Aurora Server handles user authentication requests, token creation and
25
+ # management, and permissions querying and verification.
26
+ #
27
+ # == Usage
28
+ #
29
+ # class Aurora::Server
30
+ # def authenticate(username, password)
31
+ # username == 'test' && password == 'secret'
32
+ # end
33
+ # end
34
+ #
35
+ # This will define an authentication processor for verifying users'
36
+ # authenticity. This method is only defaulted to when token authentication
37
+ # is not able to be used (such as for creating sessions), so its use should
38
+ # be minimized by token authentication.
39
+ class Server < Halcyon::Server::Base
40
+
41
+ def self.version
42
+ VERSION.join('.')
43
+ end
44
+
45
+ route do |r|
46
+ # authentication routes
47
+ r.match('/user/auth/:username').to(:module => 'user', :action => 'auth')
48
+ r.match('/token/auth/:token').to(:module => 'token', :action => 'auth')
49
+
50
+ # user routes
51
+ r.match('/user/show/:username').to(:module => 'user', :action => 'show')
52
+
53
+ # token routes
54
+ r.match('/token/destroy/:token').to(:module => 'token', :action => 'destroy')
55
+
56
+ # permission routes
57
+ r.match('/user/:username/:app/permissions').to(:module => 'user', :action => 'permisisons')
58
+ r.match('/user/:username/:app/permit/:permission').to(:module => 'user', :action => 'permit')
59
+
60
+ # generic
61
+ r.match('/:module/:action/:id').to()
62
+ r.match('/:module/:action').to()
63
+ r.match('/:action/:id').to()
64
+ r.match('/:action').to()
65
+
66
+ # failover
67
+ {:action => 'unauthorized'}
68
+ end
69
+
70
+ # Makes sure the Database server connection is created, tables migrated,
71
+ # and other tasks.
72
+ def startup
73
+ # TODO: setup startup tasks
74
+
75
+ # connect to database
76
+ host = credentials = ''
77
+ host = "#{@config[:db][:host]}/" unless @config[:db][:host].nil?
78
+ credentials = "#{@config[:db][:username]}:#{@config[:db][:password]}@" unless @config[:db][:username].nil?
79
+ @db = Sequel("#{@config[:db][:adapter]}://#{credentials}#{host}#{@config[:db][:database]}")
80
+ @logger.info 'Connected to Database.'
81
+
82
+ # run migrations if version is outdated
83
+ current_version = Sequel::Migrator.get_current_migration_version(@db)
84
+ latest_version = Sequel::Migrator.apply(@db, File.join(File.dirname(__FILE__),'migrations'))
85
+ @logger.info 'Migrations loaded!' if current_version < latest_version
86
+
87
+ # clean expired sessions/tokens
88
+ expire_tokens
89
+ @logger.info 'Expired sessions/tokens removed.'
90
+ end
91
+
92
+ # = User Module
93
+ #
94
+ # User actions, including authentication, permissions testing and
95
+ # management, and data querying.
96
+ user do
97
+
98
+ #--
99
+ # Authentication
100
+ #++
101
+
102
+ # Calls the supplied authentication method. Creates a token on success,
103
+ # returning that token, and raises Unauthorized on failure.
104
+ def auth
105
+ username, password = params[:username], @req.POST['password']
106
+ if authenticate(username, password)
107
+ # authenticated
108
+
109
+ # generate token and expiration date
110
+ token = Digest::MD5.hexdigest("#{username}:#{password}:#{Time.now.to_s}")
111
+ expiration = generate_expiration
112
+
113
+ # save to the DB
114
+ @db[:tokens].filter(:username => username).delete # removes previous tokens
115
+ @db[:tokens] << {:username => username, :token => token, :expires_at => expiration}
116
+
117
+ # create the user if not already in the DB
118
+ if @db[:users].filter(:username => username).empty?
119
+ # retrieve the new user permissions
120
+ permissions = initialize_permissions(username)
121
+
122
+ # create a new user
123
+ @db[:users] << {:username => username, :password => Digest::MD5.hexdigest(password), :permissions => permissions.to_json}
124
+ @logger.info "#{username} cached."
125
+ else
126
+ # or just cache the password so the user's profile is up-to-date
127
+ # if the authentication source is not available
128
+ @db[:users].filter(:username => username).update(:password => Digest::MD5.hexdigest(password))
129
+ @logger.debug "#{username} updated."
130
+ end
131
+
132
+ # return success with token for client
133
+ ok(token)
134
+ else
135
+ # failed authentication
136
+ raise Exceptions::Unauthorized.new
137
+ end
138
+ end
139
+
140
+ #--
141
+ # General
142
+ #++
143
+
144
+ # Show user data.
145
+ def show
146
+ # TODO: consider removing as potentially unsafe
147
+ end
148
+
149
+ #--
150
+ # Permissions
151
+ #++
152
+
153
+ # Request the full permissions of a given user
154
+ def permissions
155
+ # TODO: consider removing as potentially unsafe
156
+ # (in the event a malicious user wants to model a super user with a real
157
+ # super user's permissions)
158
+ end
159
+
160
+ # Handles action branching depending on the method for permission setting
161
+ # or getting. Defers to +permit?+ and +permit!+.
162
+ def permit
163
+ case method
164
+ when :get
165
+ permit?
166
+ when :post
167
+ permit!
168
+ end
169
+ end
170
+
171
+ # Does the user have permission?
172
+ def permit?
173
+ username, app, permission = params[:username], params[:app], params[:permission]
174
+
175
+ # pull the permissions for the user
176
+ perms = JSON.parse(@db[:users][:username => username][:permissions])
177
+
178
+ # test the permissions
179
+ unless perms[app].nil?
180
+ ok(perms[app][permission])
181
+ else
182
+ # no permissions were found for the given app
183
+ ok(false)
184
+ end
185
+ end
186
+
187
+ # Give permissions to user
188
+ def permit!
189
+ username, app, permission, value = params[:username], params[:app], params[:permission], post[:value]
190
+
191
+ # pull the permissions for the user
192
+ perms = JSON.parse(@db[:users][:username => username][:permissions])
193
+
194
+ # test the permissions
195
+ unless perms[app].nil?
196
+ if perms[app][permission] == value
197
+ ok(true)
198
+ else
199
+ raise Exceptions::Unauthorized.new
200
+ end
201
+ else
202
+ # no permissions were found for the given app
203
+ raise Exceptions::Unauthorized.new
204
+ end
205
+ end
206
+
207
+ end
208
+
209
+ # = Token Module
210
+ #
211
+ # Token actions, including authentication and destroying tokens. Tokens
212
+ # represent authenticated sessions allowing for faster repeated
213
+ # authentication requests in a short period of time (such as each page load
214
+ # in a larger web application).
215
+ token do
216
+
217
+ # Authenticates the token.
218
+ def auth
219
+ # expire_tokens # TODO: investigate how much of a performance hit checking (and deleting) is
220
+ unless @db[:tokens].filter('token = ? AND expires_at > ?', params[:token], Time.now).empty?
221
+ # authenticated
222
+
223
+ # update the expiration date if close to expiring
224
+ unless @db[:tokens].filter('token = ? AND expires_at <= ?', params[:token], generate_expiration(15)).empty?
225
+ @db[:tokens].filter(:token => params[:token]).update(:expires_at => generate_expiration)
226
+ end
227
+
228
+ # return success and token for client
229
+ ok(params[:token])
230
+ else
231
+ # failed authentication
232
+ raise Exceptions::Unauthorized.new
233
+ end
234
+ end
235
+
236
+ def destroy
237
+ @db[:tokens].filter(:token => params[:token]).delete
238
+ ok
239
+ end
240
+
241
+ end
242
+
243
+ # The default unauthorized action which raises an Unauthorized exception
244
+ def unauthorized(params={})
245
+ raise Exceptions::Unauthorized.new
246
+ end
247
+
248
+ #--
249
+ # Utility methods
250
+ #++
251
+
252
+ # Removes expired tokens.
253
+ def expire_tokens
254
+ @db[:tokens].filter('expires_at < ?',Time.now).delete
255
+ end
256
+
257
+ # Sets up a given user's permissions. Overwrite this method to specify more
258
+ # specific or dynamic default permissions, for instance connecting to LDAP
259
+ # to determine department and granting permissions that way.
260
+ def initialize_permissions(username)
261
+ # by default, no permissions are setup
262
+ # the returned value is JSON-ized
263
+ {}
264
+ end
265
+
266
+ # Generates a new time to expire from the minutes given, defaulting to the
267
+ # number of minutes given as a token lifetime in the configuration file.
268
+ def generate_expiration(lifetime=@config[:tokens][:lifetime])
269
+ (Time.now + (lifetime.to_i*60))
270
+ end
271
+
272
+ end
273
+
274
+ end
@@ -0,0 +1,24 @@
1
+ describe "Aurora::Server" do
2
+
3
+ before do
4
+ @serv = Specr.new :port => 6211
5
+ end
6
+
7
+ it "should authenticate users with proper credentials" do
8
+ response = JSON.parse(Rack::MockRequest.new(@serv).post("/user/auth/test", :input => '&password=pass&').body)
9
+ response['status'].should == 200
10
+ end
11
+
12
+ it "should provide a token for authenticated users with proper credentials" do
13
+ response = JSON.parse(Rack::MockRequest.new(@serv).post("/user/auth/test", :input => '&password=pass&').body)
14
+ response['status'].should == 200
15
+ response['body'].should == Digest::MD5.hexdigest(Time.now.to_s)
16
+ end
17
+
18
+ it "should return unauthorized error if improper credentials are attempting authentication" do
19
+ response = JSON.parse(Rack::MockRequest.new(@serv).post("/user/auth/test", :input => '&password=fail&').body)
20
+ response['status'].should == 401
21
+ response['body'].should == 'Unauthorized'
22
+ end
23
+
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'rack/mock'
2
+ require 'aurora/server'
3
+
4
+ $test = true
5
+
6
+ # Testing inheriting the Aurora server
7
+ class Specr < Aurora::Server
8
+ def authenticate(user, pass)
9
+ # if pass isn't pass then it fails... get it?
10
+ pass == 'pass'
11
+ end
12
+ end
13
+
14
+ # Testing modifying the aurora server's authenticate method directly
15
+ class Aurora::Server
16
+ def authenticate(user, pass)
17
+ # if pass isn't pass then it fails... get it?
18
+ pass == 'pass'
19
+ end
20
+ end
metadata CHANGED
@@ -1,112 +1,68 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aurora
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- platform: ""
4
+ version: 0.1.10
5
+ platform: ruby
6
6
  authors:
7
7
  - Matt Todd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2007-11-27 00:00:00 -05:00
12
+ date: 2008-02-19 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: json
16
+ name: halcyon
17
17
  version_requirement:
18
18
  version_requirements: !ruby/object:Gem::Requirement
19
19
  requirements:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.1.1
22
+ version: 0.3.28
23
23
  version:
24
- - !ruby/object:Gem::Dependency
25
- name: mongrel
26
- version_requirement:
27
- version_requirements: !ruby/object:Gem::Requirement
28
- requirements:
29
- - - ">="
30
- - !ruby/object:Gem::Version
31
- version: 1.1.1
32
- version:
33
- - !ruby/object:Gem::Dependency
34
- name: dhkeyexchange
35
- version_requirement:
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 1.0.0
41
- version:
42
- - !ruby/object:Gem::Dependency
43
- name: rack
44
- version_requirement:
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 0.2.0
50
- version:
51
- description: Simple authentication server and user permissions management tool.
52
- email: mtodd@clayton.edu
53
- executables: []
54
-
24
+ description: A Simple Authentication Server
25
+ email: chiology@gmail.com
26
+ executables:
27
+ - aurora
55
28
  extensions: []
56
29
 
57
30
  extra_rdoc_files:
58
- - History.txt
59
- - License.txt
60
- - Manifest.txt
61
- - README.txt
62
- - website/index.txt
31
+ - lib
63
32
  files:
64
- - History.txt
65
- - License.txt
66
- - Manifest.txt
67
- - README.txt
33
+ - lib
68
34
  - Rakefile
69
- - config/hoe.rb
70
- - config/requirements.rb
71
- - examples/basics.rb
72
- - lib/aurora.rb
35
+ - test/aurora
36
+ - test/aurora/server_spec.rb
37
+ - test/spec_helper.rb
38
+ - lib/aurora
73
39
  - lib/aurora/client.rb
74
- - lib/aurora/client/base.rb
75
- - lib/aurora/client/token.rb
40
+ - lib/aurora/migrations
41
+ - lib/aurora/migrations/001_create_users.rb
42
+ - lib/aurora/migrations/002_create_tokens.rb
76
43
  - lib/aurora/server.rb
77
- - lib/aurora/server/base.rb
78
- - lib/aurora/server/handler.rb
79
- - lib/aurora/server/server.rb
80
- - lib/aurora/server/token.rb
81
- - lib/aurora/version.rb
82
- - log/debug.log
83
- - script/destroy
84
- - script/generate
85
- - script/txt2html
86
- - setup.rb
87
- - tasks/deployment.rake
88
- - tasks/environment.rake
89
- - tasks/website.rake
90
- - test/test_aurora.rb
91
- - test/test_helper.rb
92
- - website/index.html
93
- - website/index.txt
94
- - website/javascripts/rounded_corners_lite.inc.js
95
- - website/stylesheets/screen.css
96
- - website/template.rhtml
44
+ - lib/aurora.rb
97
45
  has_rdoc: true
98
46
  homepage: http://aurora.rubyforge.org
99
47
  post_install_message:
100
48
  rdoc_options:
101
- - --main
102
- - README.txt
49
+ - --all
50
+ - --quiet
51
+ - --op
52
+ - rdoc
53
+ - --line-numbers
54
+ - --inline-source
55
+ - --title
56
+ - "\"Aurora Documentation\""
57
+ - --exclude
58
+ - "\"^(_darcs|test|pkg|.svn)/\""
103
59
  require_paths:
104
60
  - lib
105
61
  required_ruby_version: !ruby/object:Gem::Requirement
106
62
  requirements:
107
63
  - - ">="
108
64
  - !ruby/object:Gem::Version
109
- version: "0"
65
+ version: 1.8.6
110
66
  version:
111
67
  required_rubygems_version: !ruby/object:Gem::Requirement
112
68
  requirements:
@@ -114,13 +70,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
70
  - !ruby/object:Gem::Version
115
71
  version: "0"
116
72
  version:
117
- requirements: []
118
-
119
- rubyforge_project: aurora
120
- rubygems_version: 0.9.5
73
+ requirements:
74
+ - ""
75
+ rubyforge_project:
76
+ rubygems_version: 1.0.1
121
77
  signing_key:
122
78
  specification_version: 2
123
- summary: Simple authentication server and user permissions management tool.
124
- test_files:
125
- - test/test_aurora.rb
126
- - test/test_helper.rb
79
+ summary: A Simple Authentication Server
80
+ test_files: []
81
+