rack_warden 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Zjc4YzFlOTkwNzRhN2EyNjVmZWJjZDZmOGEzZTZjNjY5NmE1YjQ3OA==
4
+ OGI4OGQxNWNhZTkwNWNlODQ3ZTkwNWFmZTZiODFkM2MwNTMzNWZkZg==
5
5
  data.tar.gz: !binary |-
6
- NzFlMzJjNmE5ZGM5ZGRhYzVkYmZhNzRmMDFlY2ExODkzMTM0MzhmYQ==
6
+ YWFiYWY3NmRjNzZmNjJhMzIzM2Y2YjFmY2I5OGVjMmI5OGFmMDQ4Mg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZmVhMmMyMmI1MTI0NDRmNmEwYzA1YWQ0MTE2YjdiM2M3NGI0OTQwM2VmNDgz
10
- ZTY5MGVlOGJlODY4ZjM3ZDBlNWI0YTE0MmQxN2QwN2Y1Y2I2MmI2ZmVmZjc1
11
- NzIwNGFiNTM1MzBiZTM0MWI5YWIxY2VkMDYyNmM5ZjFjZjgxYTI=
9
+ NWVlZDdkMzczOTIwMjYzY2I4NjZiZmExNzlmYWQyZmU5OGJjYTg1YWUyZDA3
10
+ YzcwNDYzOGZiMzBlNDg2NjQ2ZmI1YTBkNjU3MTc0YTFiM2Y3NTgzZTQyNzNk
11
+ MjUyMGI2NzVlMTkwOWQ0ODdiZWRhYzVkMTI5ZDFjMWNhMzhjZGE=
12
12
  data.tar.gz: !binary |-
13
- NzgyMWUwMzcwYWIzYTZkMjJkODdmODY4ZTkzYzlmYTE5OWNkMmY1NTJhOTZk
14
- YTEwNTgwMTUwYjhiNDQyMzQwYmEyYTZhMzY2YzA0OTIxYjMzYzk2YjIzMWJl
15
- NWM4Y2E4NzcxZmY4ZTgzYjMzNjU5ZmJkN2JlYjA4MjE4ZGYyMzk=
13
+ YzQ3ZTIzMjMyNWQ4YTRmMmQxMTRiNjMwNDliOTkwN2IyZTVjOGY3MjQ3MGIz
14
+ ODg0ZTBhMTk3ZmE4MzE3YTNiNzhjN2ExMGJmYTZhNGViZDJhYjNlOGNiZTky
15
+ MjhhMzE4MWFkMzAyZDUyZGMwZmYwYjQ0ZDQ5Mjk2NmE1ZDA4MWI=
data/README.md CHANGED
@@ -4,17 +4,17 @@ RackWarden is a rack middleware mini-app that provides user authentication and m
4
4
 
5
5
  RackWarden uses Sinatra for the mini-app, Warden for authentication, and DataMapper for database connections. It is based on the sinatra-warden-example at https://github.com/sklise/sinatra-warden-example. If you are new to Warden or Sinatra, I highly recommend downloading and experimenting with that example.
6
6
 
7
- My goal in developing this software is to have drop-in authentication containing most of the features you see in user/account management sections of a typical web site. But I don't want to be strapped by this module in any of my projects, so it must be customizable. Or rather, overridable. The basics of this flexibility are already in place, and it will be a central theme throughout. See below for examples on overriding and customizing RackWarden.
7
+ My goal in developing this software is to have drop-in authentication containing most of the features you see in user/account management sections of a typical web site. But I don't want to be strapped by this module in any of my projects, so it must be customizable. Or rather, overridable. The basics of this flexibility are already in place, and it will be a central theme throughout.
8
8
 
9
9
  Please note that RackWarden is a work-in-progress. The gemspec, the files, the code, and the documentation can and will change over time. Follow on github for the latest fixes, changes, and developments.
10
10
 
11
11
  ## What Does it Do?
12
12
 
13
- RackWarden acts as a self-sufficient gatekeeper for your ruby web app. Once you enable RackWarden in your rack-based project, all routes/actions in your project will require a login and will redirect browsers to an authentication page. RackWarden provides its own view & layout templates to facilitate user authentication. RackWarden also provides it's own tables to store user data.
13
+ RackWarden is a modular gatekeeper for your ruby web app. Once you enable RackWarden in your rack-based project, all routes/actions in your project will require a login and will redirect browsers to an authentication page. RackWarden provides its own view & layout templates to facilitate user authentication. RackWarden also provides it's own database & table structure to store user data. Views, layouts, databases, and tables are easily customized and/or overridden, however.
14
14
 
15
15
  Once RackWarden authenticates a user, it gets out of the way, and the user is returned to your application. RackWarden also provides a number of user management tools for common actions like creating, updating, and deleting users.
16
16
 
17
- Most of the RackWarden features can be customized. You can override the views, the database, the actions, and even the authentication logic with your own templates and code. The easiest (and possibly the most dramatic) customization is to provide RackWarden with your own layout template, giving RackWarden the look-and-feel of your own application.
17
+ Most of the RackWarden features can be customized. You can override the views, the database, the actions, and even the authentication logic with your own templates and code. The easiest (and possibly the most dramatic) customization is to provide RackWarden with your own layout template, giving RackWarden the appearane of the application you're integrating it with.
18
18
 
19
19
 
20
20
  ## Installation
@@ -39,7 +39,7 @@ A few simple steps will have your entire app protected.
39
39
  ### Sinatra
40
40
 
41
41
  class MySinatraApp < Sinatra::Base
42
- use RackWarden::App
42
+ use RackWarden
43
43
 
44
44
  get "/" do
45
45
  erb "All routes are now protected"
@@ -50,7 +50,7 @@ A few simple steps will have your entire app protected.
50
50
 
51
51
  application.rb or environment.rb
52
52
 
53
- config.middleware.use RackWarden::App
53
+ config.middleware.use RackWarden
54
54
 
55
55
  # All routes are now protected
56
56
 
@@ -60,19 +60,19 @@ application.rb or environment.rb
60
60
 
61
61
  RackWarden will look for a configuration file named rack\_warden.yml in your project root or in your project/config/ directory.
62
62
 
63
- ---
64
- database: sqlite3:///usr/local/some_other_database.sqlite3.db
65
- layout: :'my_custom_layout.html.erb'
63
+ ---
64
+ database: sqlite3:///usr/local/some_other_database.sqlite3.db
65
+ layout: :'my_custom_layout.html.erb'
66
66
 
67
67
 
68
68
  You an also pass configuration settings to RackWarden through the ```use``` method of your framework. The params hash of ```use``` will be translated directly to RackWarden's settings. In addition to RackWarden's specific configuration options, you can also pass in any standard Sinatra settings.
69
69
 
70
- If you pass a block with the ```use``` method, the block will be evaluated in the context of the RackWarden::App class. Anything you do in that block is just as if you were writing code in the app class itself. While in the block, you also have access to the current instance of RackWarden::App and the current instance of the parent app.
70
+ If you pass a block with the ```use``` method, the block will be evaluated in the context of the RackWarden::App class. Anything you do in that block is just as if you were writing code in the app class itself. While in the block, you also have access to the current instance of RackWarden::App.
71
71
 
72
- use RackWarden::App do |rack_warden_app_instance, parent_app_instance|
72
+ use RackWarden::App do |rack_warden_app_instance|
73
73
  set :somesetting, 'some_value'
74
74
  end
75
-
75
+
76
76
 
77
77
  ## Configuration Options
78
78
 
@@ -154,15 +154,22 @@ Settings for Google's recaptcha service
154
154
 
155
155
  ### :log\_path
156
156
 
157
- File.join(Dir.pwd, 'log', 'rack_warden.log')
157
+ File.join(Dir.pwd, 'log', 'rack_warden.log')
158
+
159
+ ### :user\_table\_name
160
+
161
+ nil
162
+
163
+ ### :views
164
+
165
+ File.expand_path("../views/", __FILE__)
166
+
158
167
 
159
168
  ## Customization
160
169
 
161
170
  ### Views
162
171
 
163
- To customize RackWarden for your specific project, you can set :views to point to a directory within your project. Then create templates that match the names of RackWarden templates, and they will be picked up and rendered. RackWarden looks for templates at the top level of your views directory as a default. You can change or add to this when you define the middleware in your project.
164
-
165
- Update: also looks in views/rack\_warden/ for view templates.
172
+ To customize RackWarden for your specific project, you can set :views to point to a directory within your project. Then create templates that match the names of RackWarden templates, and they will be picked up and rendered. RackWarden looks for templates at the top level of your views directory and in views/rack\_warden (if it exists) as a default. You can change or add to this with the ```:views``` setting.
166
173
 
167
174
  use RackWarden::App, :views => File.join(Dir.pwd, 'app/views/another_directory')
168
175
 
@@ -175,15 +182,20 @@ Just remember that RackWarden is Sinatra, and any templates you pass must use Si
175
182
 
176
183
  ### Database
177
184
 
178
- As a default, RackWarden will use the database specified in your project. You can also pass a database specification with the ```:database_config``` setting.
179
-
180
- # As a url
181
- database_config: 'sqlite3:///path/to/my/database.sqlite3.db'
182
-
183
- # As a hash
184
- database_config: {adapter: 'sqlite3', database: '/path/to/my/database.sqlite3.db'}
185
+ As a default, RackWarden will use a sqlite3 in-memory database (that starts fresh each time you boot your app). To use the database specified in your project, just pass ```:auto``` to the ```:database_config``` setting. Pass ```:file``` to set up a sqlite3 database in your app's working directory. Or pass your own custom database specification (a url or hash). If you use a database other than sqlite3, you will need to include the respective DataMapper extension gems in your Gemfile or in your manually installed gem list. For MySQL, use dm-mysql-adapter, for Postgres use dm-postgres-adapter. See the DataMapper site for more info on database adapters.
186
+
187
+ # Database specification as a url
188
+ database_config: 'sqlite3:///path/to/my/database.sqlite3.db'
189
+
190
+ # Database specification as a hash
191
+ database_config: {adapter: 'sqlite3', database: '/path/to/my/database.sqlite3.db'}
192
+
193
+ # Use a remote MySQL database
194
+ database_config: {adapter: 'mysql', username: 'will', password: 'mypass',
195
+ host: 'somehost', database: 'my_database'}
185
196
 
186
- If your project has no database, or if you pass ```false``` to the ```:database_config``` setting, RackWarden will create its own database in the working directory as 'rack_warden.sqlite3.db'.
197
+ # Format for database urls
198
+ #<adapter>://<username>:<password>@<host>:<port>/<database_name>
187
199
 
188
200
 
189
201
 
@@ -17,7 +17,10 @@ module RackWarden
17
17
  autoload :App, 'rack_warden/app'
18
18
  autoload :User, "rack_warden/models"
19
19
  autoload :Pref, "rack_warden/models"
20
+ autoload :Routes, "rack_warden/routes"
20
21
  autoload :VERSION, "rack_warden/version"
22
+ autoload :WardenConfig, "rack_warden/warden"
23
+ autoload :RackWardenHelpers, "rack_warden/helpers"
21
24
  module Frameworks
22
25
  autoload :Base, 'rack_warden/frameworks'
23
26
  autoload :Sinatra, 'rack_warden/frameworks/sinatra'
@@ -33,18 +36,22 @@ module RackWarden
33
36
  # Utility to get middleware stack. Maybe temporary.
34
37
  def self.middleware_classes(app=nil)
35
38
  r = [app || Rack::Builder.parse_file(File.join(Dir.pwd, 'config.ru')).first]
36
-
37
39
  while ((next_app = r.last.instance_variable_get(:@app)) != nil)
38
40
  r << next_app
39
41
  end
40
-
41
42
  r.map{|e| e.instance_variable_defined?(:@app) ? e.class : e }
42
43
  end
43
44
  #app = Rack::Builder.parse_file('config.ru').first
44
45
  #puts middleware_classes(app).inspect
45
46
 
47
+ # Shortcut/sugar to app
46
48
  def self.settings
47
49
  App.settings
48
50
  end
51
+
52
+ def self.included(base)
53
+ puts "RW self.included into BASE #{base}, ID #{base.object_id}"
54
+ App.new base
55
+ end
49
56
 
50
57
  end
@@ -3,8 +3,6 @@
3
3
 
4
4
  module RackWarden
5
5
  class App < Sinatra::Base
6
- enable :sessions
7
- register Sinatra::Flash
8
6
 
9
7
  set :config_files, [ENV['RACK_WARDEN_CONFIG_FILE'], 'rack_warden.yml', 'config/rack_warden.yml'].compact.uniq
10
8
  set :layout, :'rw_layout.html'
@@ -21,10 +19,15 @@ module RackWarden
21
19
 
22
20
  # Load config from file, if any exist.
23
21
  Hash.new.tap do |hash|
24
- config_files.each {|c| puts File.join(Dir.pwd, c); hash.merge!(YAML.load_file(File.join(Dir.pwd, c))) rescue nil}
22
+ config_files.each {|c| hash.merge!(YAML.load_file(File.join(Dir.pwd, c))) rescue nil}
25
23
  set hash
26
24
  end
27
25
 
26
+
27
+
28
+ enable :sessions
29
+ register Sinatra::Flash
30
+
28
31
  begin
29
32
  enable :logging
30
33
  set :log_file, File.new(settings.log_path, 'a+')
@@ -32,27 +35,31 @@ module RackWarden
32
35
  use Rack::CommonLogger, settings.log_file
33
36
  rescue
34
37
  end
38
+
39
+ include RackWarden::WardenConfig
40
+ include RackWarden::Routes
41
+
42
+ helpers RackWardenHelpers
43
+ helpers UniversalHelpers
44
+
35
45
 
36
46
 
37
47
  # WBR - This will receive params and a block from the parent "use" statement.
38
48
  # This middleware app has been modified to process the parent use-block in
39
49
  # the context of the RackWarden class. So you can set settings on RackWarden,
40
- # when you call "use RackWarden::App"
50
+ # when you call "use RackWarden"
41
51
  # Example:
42
52
  #
43
- # use RackWarden::App :layout=>:'my_layout' do |rack_warden_instance, app|
53
+ # use RackWarden :layout=>:'my_layout' do |rack_warden_instance, app|
44
54
  # set :myvar, 'something'
45
55
  # end
46
56
  #
47
57
  def initialize(parent_app_instance=nil, *args, &block)
48
- #@app = parent_app_instance
49
- super(parent_app_instance, &Proc.new{})
58
+ super(parent_app_instance, &Proc.new{}) # Must send empty proc, not original proc, since we're calling original block here.
50
59
  initialization_args = args.dup
51
- #puts "RW INITIALIZE middleware instance [app, self, args, block]: #{[app, self, args, block]}"
52
60
  puts "RW new instance with parent: #{@app}"
53
61
  # extract options.
54
62
  opts = args.last.is_a?(Hash) ? args.pop : {}
55
- #settings = self.class
56
63
  if app && !settings.initialized
57
64
  puts "RW initializing settings"
58
65
 
@@ -64,7 +71,7 @@ module RackWarden
64
71
  settings.set opts if opts.any?
65
72
 
66
73
  # Eval the use-block from the parent app, in context of this app.
67
- settings.instance_exec(self, app, &block) if block_given?
74
+ settings.instance_exec(self, &block) if block_given?
68
75
 
69
76
  # Do framework setup.
70
77
  framework_module = Frameworks::Base.select_framework(binding)
@@ -74,13 +81,6 @@ module RackWarden
74
81
 
75
82
  # Manipulate views
76
83
  new_views = []
77
- #original_views = self.class.original_views
78
- # append parent rails views folder unless opts.has_key?(:views)
79
- #new_views << framework_module.views_path unless opts[:views]==false #opts.has_key?(:views)
80
- # append original_views, if original_views
81
- #new_views << original_views if original_views
82
- #self.class.set(:views => [new_views, Array(self.class.views)].flatten.compact.uniq) if new_views.any?
83
-
84
84
  new_views.unshift settings.original_views
85
85
  new_views.unshift framework_module.views_path unless settings.views==false
86
86
  new_views.unshift settings.views
@@ -90,216 +90,17 @@ module RackWarden
90
90
  end
91
91
  settings.set :initialized, true
92
92
  end
93
- # finally, send parent app to super, but don't send the use-block (thus the empty proc)
94
- #super(app, &Proc.new{})
95
- end
96
-
97
- # For testing interception of request.
98
- # This might be breaking older rails installations
99
- # if development?
100
- # def call(env={})
101
- # puts "RW instance.app #{app}"
102
- # puts "RW instance.call(env) #{env.to_yaml}"
103
- # super(env)
104
- # end
105
- # end
106
-
107
- use Warden::Manager do |config|
108
- # Tell Warden how to save our User info into a session.
109
- # Sessions can only take strings, not Ruby code, we'll store
110
- # the User's `id`
111
- config.serialize_into_session{|user| user.id }
112
- # Now tell Warden how to take what we've stored in the session
113
- # and get a User from that information.
114
- config.serialize_from_session{|id| User.get(id) }
115
-
116
- config.scope_defaults :default,
117
- # "strategies" is an array of named methods with which to
118
- # attempt authentication. We have to define this later.
119
- :strategies => [:password],
120
- # The action is a route to send the user to when
121
- # warden.authenticate! returns a false answer. We'll show
122
- # this route below.
123
- :action => 'auth/unauthenticated'
124
- # When a user tries to log in and cannot, this specifies the
125
- # app to send the user to.
126
- config.failure_app = self
127
- end
128
93
 
129
- Warden::Manager.before_failure do |env,opts|
130
- env['REQUEST_METHOD'] = 'POST'
131
- end
132
-
133
- Warden::Strategies.add(:password) do
134
- def valid?
135
- params['user'] && params['user']['username'] && params['user']['password']
136
- end
137
-
138
- def authenticate!
139
- user = User.first(['username = ? or email = ?', params['user']['username'], params['user']['username']]) #(username: params['user']['username'])
140
-
141
- if user.nil?
142
- fail!("The username you entered does not exist.")
143
- elsif user.authenticate(params['user']['password'])
144
- success!(user)
145
- else
146
- fail!("Could not log in")
147
- end
148
- end
149
-
150
- end
151
-
152
- # Also bring these into your main app helpers.
153
- module RackWardenHelpers
154
- # WBR - override. This passes block to be rendered to first template that matches.
155
- def find_template(views, name, engine, &block)
156
- # puts "THE VIEWS: #{views}"
157
- # puts "THE NAME: #{name}"
158
- # puts "THE ENGINE: #{engine}"
159
- # puts "THE BLOCK: #{block}"
160
- Array(views).each { |v| super(v, name, engine, &block) }
161
- end
162
-
163
- def require_login
164
- warden.authenticate!
165
- end
166
-
167
- def warden
168
- request.env['warden']
169
- end
170
-
171
- def current_user
172
- warden.user
173
- end
174
-
175
- def logged_in?
176
- warden.authenticated?
177
- end
178
-
179
-
180
- # TODO: Shouldn't these be in warden block above? But they don't work there for some reason.
181
-
182
- def valid_user_input?
183
- params['user'] && params['user']['email'] && params['user']['password']
184
- end
185
-
186
- # def create_user
187
- #
188
- # verify_recaptcha if settings.recaptcha[:secret]
189
- #
190
- # #return unless valid_user_input?
191
- #
192
- # @user = User.new(params['user'])
193
- # @user.save #&& warden.set_user(@user)
194
- # end
195
-
196
- def verify_recaptcha(skip_redirect=false, ip=request.ip, response=params['g-recaptcha-response'])
197
- secret = settings.recaptcha[:secret]
198
- _recaptcha = ActiveSupport::JSON.decode(open("https://www.google.com/recaptcha/api/siteverify?secret=#{secret}&response=#{response}&remoteip=#{ip}").read)
199
- puts "RECAPTCHA", _recaptcha
200
- unless _recaptcha['success']
201
- flash(:rwarden)[:error] = "Please confirm you are human"
202
- redirect back unless skip_redirect
203
- Halt "You appear to be a robot."
204
- end
205
- end
206
-
207
- def default_page
208
- erb :'rw_index.html', :layout=>settings.layout
209
- end
210
-
211
- end # RackWardenHelpers
212
- helpers RackWardenHelpers
213
-
214
- if defined? ::RACK_WARDEN_STANDALONE
215
- get '/?' do
216
- default_page
217
- end
218
- end
219
-
220
- get '/auth/?' do
221
- default_page
222
- end
223
-
224
- get '/auth/login' do
225
- if User.count > 0
226
- erb :'rw_login.html', :layout=>settings.layout
227
- else
228
- flash(:rwarden)[:error] = warden.message || "Please create an admin account"
229
- redirect url('/auth/new', false)
230
- end
231
- end
232
-
233
- post '/auth/login' do
234
- warden.authenticate!
235
-
236
- flash(:rwarden)[:success] = warden.message || "Successful login"
237
-
238
- if session[:return_to].nil?
239
- redirect url(settings.default_route, false)
240
- else
241
- redirect session[:return_to]
242
- end
243
- end
244
-
245
- get '/auth/logout' do
246
- warden.raw_session.inspect
247
- warden.logout
248
- flash(:rwarden)[:success] = 'You have been logged out'
249
- redirect url(settings.default_route, false)
250
- end
251
-
252
- get '/auth/new' do
253
- halt 403 unless settings.allow_public_signup or !(User.count > 0)
254
- erb :'rw_new_user.html', :layout=>settings.layout, :locals=>{:recaptcha_sitekey=>settings.recaptcha['sitekey']}
255
- end
256
-
257
- post '/auth/create' do
258
- verify_recaptcha if settings.recaptcha[:secret]
259
- Halt "Could not create account", :layout=>settings.layout unless params[:user]
260
- params[:user].delete_if {|k,v| v.nil? || v==''}
261
- @user = User.new(params['user'])
262
- if @user.save
263
- warden.set_user(@user)
264
- flash(:rwarden)[:success] = warden.message || "Account created"
265
- redirect session[:return_to] || url(settings.default_route, false)
266
- else
267
- flash(:rwarden)[:error] = "#{warden.message} => #{@user.errors.entries.join('. ')}"
268
- puts "RW /auth/create #{@user.errors.entries}"
269
- redirect back #url('/auth/new', false)
270
- end
271
- end
272
-
273
- post '/auth/unauthenticated' do
274
- # I had to remove the condition, since it was not updating return path when it should have.
275
- session[:return_to] = env['warden.options'][:attempted_path] if !request.xhr? && !env['warden.options'][:attempted_path][/login|new|create/]
276
- puts "RW attempted path: #{env['warden.options'][:attempted_path]}"
277
- puts "RW will return-to #{session[:return_to]}"
278
- puts warden
279
- # if User.count > 0
280
- flash(:rwarden)[:error] = warden.message || "Please login to continue"
281
- redirect url('/auth/login', false)
282
- # else
283
- # flash(:rwarden)[:error] = warden.message || "Please create an admin account"
284
- # redirect url('/auth/new', false)
285
- # end
286
- end
287
-
288
- get '/auth/protected' do
289
- warden.authenticate!
94
+ end # initialize
95
+
96
+ # Store this app instance in the env.
97
+ def call(env)
98
+ #puts "RW instance.app #{app}"
99
+ #puts "RW instance.call(env) #{env.to_yaml}"
100
+ env['rack_warden_instance'] = self
101
+ super(env)
102
+ end
290
103
 
291
- erb :'rw_protected.html', :layout=>settings.layout
292
- end
293
-
294
- get "/auth/dbinfo" do
295
- warden.authenticate!
296
- erb :'rw_dbinfo.html', :layout=>settings.layout
297
- end
298
-
299
- get '/auth/admin' do
300
- warden.authenticate!
301
- erb :'rw_admin.html', :layout=>settings.layout
302
- end
303
104
 
304
105
  end # App
305
106
  end # RackWarden
@@ -39,12 +39,6 @@ module RackWarden
39
39
  @rack_warden_app_class = @rack_warden_app_instance.class
40
40
  selector && self
41
41
  end
42
-
43
- # # Best guess at framework database settings.
44
- # def get_database_config
45
- # ActiveRecord::Base.connection_config rescue nil ||
46
- # DataMapper.repository(:default).adapter[:options] rescue nil
47
- # end
48
42
 
49
43
  ### End methods extended into framework module ###
50
44
 
@@ -15,19 +15,15 @@ module RackWarden
15
15
 
16
16
  def setup_framework
17
17
  #puts "RW setup_framework for rails"
18
- ApplicationController.send(:include, RackWarden::App::RackWardenHelpers)
18
+ ActionController::Base.send(:include, RackWarden::UniversalHelpers)
19
19
 
20
20
  # Define class method 'require_login' on framework controller.
21
- #parent_app_class.instance_eval do
22
- # Probably more reliable to use this.
23
- ApplicationController.instance_eval do
24
- def self.require_login(*args)
25
- before_filter(:require_login, *args) do
26
- require_login
27
- end
28
- end
29
- end
30
- (ApplicationController.before_filter :require_login, *Array(rack_warden_app_class.require_login).flatten) if rack_warden_app_class.require_login != false
21
+ ActionController::Base.define_singleton_method :require_login do |conditions_hash={}|
22
+ before_filter(:require_login, conditions_hash)
23
+ end
24
+
25
+ # The way you pass arguments here is fragile. If it's not correct, it will bomb with "undefined method 'before'...".
26
+ (ActionController::Base.require_login (rack_warden_app_class.require_login || {})) if rack_warden_app_class.require_login != false
31
27
  end
32
28
 
33
29
  end
@@ -15,18 +15,14 @@ module RackWarden
15
15
 
16
16
  def setup_framework
17
17
  #puts "RW setup_framework for sinatra"
18
- parent_app.helpers(RackWarden::App::RackWardenHelpers)
18
+ parent_app.helpers(RackWarden::UniversalHelpers)
19
19
 
20
20
  # Define class method 'require_login' on framework controller.
21
- parent_app.instance_eval do
22
- def self.require_login(*args)
23
- #puts "RW class #{self}.require_login #{args}"
24
- before(*args) do
25
- #puts "RW instance #{self}.require_login #{request.path_info}"
26
- require_login
27
- end
28
- end
29
- end
21
+ parent_app.define_singleton_method :require_login do |accept_conditions=/.*/, reject_conditions=false|
22
+ before(accept_conditions){require_login unless reject_conditions}
23
+ end
24
+
25
+ # Add require_login to before filter of sinatra app.
30
26
  parent_app.require_login(rack_warden_app_class.require_login) if rack_warden_app_class.require_login != false
31
27
  end
32
28
 
@@ -0,0 +1,96 @@
1
+ module RackWarden
2
+
3
+ module UniversalHelpers
4
+ protected
5
+
6
+ def require_login
7
+ #puts "RW instance #{self}.require_login with rack_warden: #{rack_warden}, and warden: #{warden}"
8
+ warden.authenticate!
9
+ end
10
+
11
+ def warden
12
+ request.env['warden']
13
+ end
14
+
15
+ def current_user
16
+ warden.user
17
+ end
18
+
19
+ def logged_in?
20
+ warden.authenticated?
21
+ end
22
+
23
+ def authorized?(authenticate_on_fail=false)
24
+ unless current_user.authorized?(request)
25
+ if authenticate_on_fail
26
+ flash(:rwarden)[:error] = ("Please login to continiue")
27
+ redirect "/auth/login"
28
+ else
29
+ flash(:rwarden)[:error] = ("You are not authorized to do that")
30
+ redirect back
31
+ end
32
+ end
33
+ end
34
+
35
+ # Returns the current rack_warden app instance stored in env.
36
+ def rack_warden
37
+ #puts "rack_warden method self #{request.env['rack_warden']}"
38
+ request.env['rack_warden_instance']
39
+ end
40
+
41
+ end # UniversalHelpers
42
+
43
+ # Also bring these into your main app helpers.
44
+ module RackWardenHelpers
45
+ # WBR - override. This passes block to be rendered to first template that matches.
46
+ def find_template(views, name, engine, &block)
47
+ # puts "THE VIEWS: #{views}"
48
+ # puts "THE NAME: #{name}"
49
+ # puts "THE ENGINE: #{engine}"
50
+ # puts "THE BLOCK: #{block}"
51
+ Array(views).each { |v| super(v, name, engine, &block) }
52
+ end
53
+
54
+
55
+ # TODO: Shouldn't these be in warden block above? But they don't work there for some reason.
56
+
57
+ def valid_user_input?
58
+ params['user'] && params['user']['email'] && params['user']['password']
59
+ end
60
+
61
+ def verify_recaptcha(skip_redirect=false, ip=request.ip, response=params['g-recaptcha-response'])
62
+ secret = settings.recaptcha[:secret]
63
+ _recaptcha = ActiveSupport::JSON.decode(open("https://www.google.com/recaptcha/api/siteverify?secret=#{secret}&response=#{response}&remoteip=#{ip}").read)
64
+ puts "RECAPTCHA", _recaptcha
65
+ unless _recaptcha['success']
66
+ flash(:rwarden)[:error] = "Please confirm you are human"
67
+ redirect back unless skip_redirect
68
+ Halt "You appear to be a robot."
69
+ end
70
+ end
71
+
72
+ def default_page
73
+ nested_erb :'rw_index.html', :'rw_layout_admin.html', settings.layout #settings.layout
74
+ end
75
+
76
+ def nested_erb(*list)
77
+ template = list.shift
78
+ counter =0
79
+ list.inject(template) do |tmplt, lay|
80
+ #puts "RW LAYOUTS lay: #{lay}, rslt: #{tmplt}"
81
+ erb tmplt, :layout=>lay
82
+ end
83
+ end
84
+
85
+ def return_to(fallback=settings.default_route)
86
+ redirect session[:return_to] || url(fallback, false)
87
+ end
88
+
89
+ def account_bar
90
+ return unless current_user
91
+ "<b>#{current_user.username}</b>"
92
+ end
93
+
94
+ end # RackWardenHelpers
95
+
96
+ end # RackWarden
@@ -28,8 +28,19 @@ module RackWarden
28
28
  false
29
29
  end
30
30
  end
31
+
32
+ def authorized?(options)
33
+ (options[:request].is_a?(Rack::Request) && options[:request].script_name[/login|new|create|logout/]) ||
34
+ username[/wbr/i]
35
+ end
36
+
37
+ # def username
38
+ # @username.downcase if @username.is_a?(String)
39
+ # end
40
+
31
41
  end
32
42
 
43
+
33
44
  # # Create a test User
34
45
  # if User.count == 0
35
46
  # @user = User.create(:username => "admin")
@@ -0,0 +1,101 @@
1
+ module RackWarden
2
+ module Routes
3
+ def self.included(base)
4
+ base.instance_eval do
5
+
6
+ if defined? ::RACK_WARDEN_STANDALONE
7
+ get '/?' do
8
+ default_page
9
+ end
10
+ end
11
+
12
+ get '/auth/?' do
13
+ default_page
14
+ end
15
+
16
+ get '/auth/login' do
17
+ if User.count > 0
18
+ erb :'rw_login.html', :layout=>settings.layout
19
+ else
20
+ flash(:rwarden)[:error] = warden.message || "Please create an admin account"
21
+ redirect url('/auth/new', false)
22
+ end
23
+ end
24
+
25
+ post '/auth/login' do
26
+ warden.authenticate!
27
+
28
+ flash(:rwarden)[:success] = warden.message || "Successful login"
29
+
30
+ return_to
31
+ end
32
+
33
+ get '/auth/logout' do
34
+ warden.raw_session.inspect
35
+ warden.logout
36
+ flash(:rwarden)[:success] = 'You have been logged out'
37
+ redirect url(settings.default_route, false)
38
+ end
39
+
40
+ get '/auth/new' do
41
+ halt 403 unless settings.allow_public_signup or !(User.count > 0)
42
+ erb :'rw_new_user.html', :layout=>settings.layout, :locals=>{:recaptcha_sitekey=>settings.recaptcha['sitekey']}
43
+ end
44
+
45
+ post '/auth/create' do
46
+ verify_recaptcha if settings.recaptcha[:secret]
47
+ Halt "Could not create account", :layout=>settings.layout unless params[:user]
48
+ params[:user].delete_if {|k,v| v.nil? || v==''}
49
+ @user = User.new(params['user'])
50
+ if @user.save
51
+ warden.set_user(@user)
52
+ flash(:rwarden)[:success] = warden.message || "Account created"
53
+ #redirect session[:return_to] || url(settings.default_route, false)
54
+ return_to
55
+ else
56
+ flash(:rwarden)[:error] = "#{warden.message} => #{@user.errors.entries.join('. ')}"
57
+ puts "RW /auth/create #{@user.errors.entries}"
58
+ redirect back #url('/auth/new', false)
59
+ end
60
+ end
61
+
62
+ post '/auth/unauthenticated' do
63
+ # I had to remove the condition, since it was not updating return path when it should have.
64
+ session[:return_to] = env['warden.options'][:attempted_path] if !request.xhr? && !env['warden.options'][:attempted_path][/login|new|create/]
65
+ puts "RW attempted path: #{env['warden.options'][:attempted_path]}"
66
+ puts "RW will return-to #{session[:return_to]}"
67
+ puts warden
68
+ # if User.count > 0
69
+ flash(:rwarden)[:error] = warden.message || "Please login to continue"
70
+ redirect url('/auth/login', false)
71
+ # else
72
+ # flash(:rwarden)[:error] = warden.message || "Please create an admin account"
73
+ # redirect url('/auth/new', false)
74
+ # end
75
+ end
76
+
77
+ get '/auth/protected' do
78
+ warden.authenticate!
79
+ #authorized?
80
+ erb :'rw_protected.html', :layout=>settings.layout
81
+ #wrap_with(){erb :'rw_protected.html'}
82
+ end
83
+
84
+ get "/auth/dbinfo" do
85
+ warden.authenticate!
86
+ authorized?
87
+ #erb :'rw_dbinfo.html', :layout=>settings.layout
88
+ nested_erb :'rw_dbinfo.html', :'rw_layout_admin.html', settings.layout
89
+ end
90
+
91
+ get '/auth/admin' do
92
+ warden.authenticate!
93
+ authorized?
94
+ #erb :'rw_admin.html', :layout=>settings.layout
95
+ nested_erb :'rw_admin.html', :'rw_layout_admin.html', settings.layout
96
+ end
97
+
98
+ end
99
+ end
100
+ end
101
+ end
@@ -1,3 +1,3 @@
1
1
  module RackWarden
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -1,4 +1,6 @@
1
- <% @section_title = "RackWarden Admin" %>
1
+ <p>
2
+ <h3>User accounts</h3>
3
+ </p>
2
4
  <p>
3
5
  <table>
4
6
  <thead>
@@ -1,5 +1,5 @@
1
1
  <p>
2
- <h2>RackWarden db info</h2>
2
+ <h3>Database info</h3>
3
3
  </p>
4
4
 
5
5
  <p>
@@ -1,3 +1,3 @@
1
1
  <p>
2
- <h2>Warden authentication for rack based apps<h2>
2
+ <h3>Warden authentication for rack based apps<h3>
3
3
  </p>
@@ -19,7 +19,6 @@
19
19
  <a href="<%=url('/auth/login', false)%>">Log In</a> |
20
20
  <a href="<%=url('/', false)%>">Home</a> |
21
21
  <a href="<%=url('/auth/protected', false)%>">Test Protected Page</a> |
22
- <a href="<%=url('/auth/admin', false)%>">RackWarden Admin</a> |
23
22
  <a href="<%=url('/auth/logout', false)%>">Log Out</a>
24
23
  </p>
25
24
 
@@ -36,7 +35,7 @@
36
35
  <% end %>
37
36
 
38
37
  <div id="content">
39
- <%= yield %>
38
+ <%= yield if block_given? %>
40
39
  </div>
41
40
  </body>
42
41
  </html>
@@ -0,0 +1,16 @@
1
+ <!-- A partial layout for admin. -->
2
+ <%# @section_title = "RackWarden Admin" %>
3
+ <h2>RackWarden Admin</h2>
4
+ <p>
5
+ <a href="<%=url('/auth/login', false)%>">Log In</a> |
6
+ <a href="<%=url('/auth', false)%>">Home</a> |
7
+ <a href="<%=url('/auth/admin', false)%>">User Accounts</a> |
8
+ <a href="<%=url('/auth/dbinfo', false)%>">Database Info</a> |
9
+ <a href="<%=url('/auth/logout', false)%>">Log Out</a>
10
+ </p>
11
+
12
+ <br>
13
+
14
+ <div id="core-content">
15
+ <%= yield if block_given? %>
16
+ </div>
@@ -0,0 +1,60 @@
1
+ module RackWarden
2
+ module WardenConfig
3
+ def self.included(base)
4
+ puts "RW WardenConfig base: #{base}"
5
+ base.instance_eval do
6
+
7
+
8
+ use Warden::Manager do |config|
9
+ # Tell Warden how to save our User info into a session.
10
+ # Sessions can only take strings, not Ruby code, we'll store
11
+ # the User's `id`
12
+ config.serialize_into_session{|user| user.id }
13
+ # Now tell Warden how to take what we've stored in the session
14
+ # and get a User from that information.
15
+ config.serialize_from_session{|id| User.get(id) }
16
+
17
+ config.scope_defaults :default,
18
+ # "strategies" is an array of named methods with which to
19
+ # attempt authentication. We have to define this later.
20
+ :strategies => [:password],
21
+ # The action is a route to send the user to when
22
+ # warden.authenticate! returns a false answer. We'll show
23
+ # this route below.
24
+ :action => 'auth/unauthenticated'
25
+ # When a user tries to log in and cannot, this specifies the
26
+ # app to send the user to.
27
+ config.failure_app = self
28
+ end
29
+
30
+ Warden::Manager.before_failure do |env,opts|
31
+ env['REQUEST_METHOD'] = 'POST'
32
+ end
33
+
34
+ Warden::Strategies.add(:password) do
35
+ def valid?
36
+ params['user'] && params['user']['username'] && params['user']['password']
37
+ end
38
+
39
+ def authenticate!
40
+ criteria = params['user']['username'] #.to_s.downcase
41
+ #user = ( User.first([{:username => '?'}, criteria]) + User.first([{:email => '?'}, criteria]) )
42
+ #user = User.first(:conditions => ['username = ? collate NOCASE or email = ? collate NOCASE', criteria, criteria]) #(username: params['user']['username'])
43
+ user = User.first(:conditions => ['username = ? or email = ?', criteria, criteria]) #(username: params['user']['username'])
44
+
45
+ if user.nil?
46
+ fail!("The username you entered does not exist")
47
+ elsif user.authenticate(params['user']['password'])
48
+ success!(user)
49
+ else
50
+ fail!("Could not log in")
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ end
57
+ end
58
+ end
59
+ end
60
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack_warden
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Richardson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-08 00:00:00.000000000 Z
11
+ date: 2015-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -183,16 +183,20 @@ files:
183
183
  - lib/rack_warden/frameworks.rb
184
184
  - lib/rack_warden/frameworks/rails.rb
185
185
  - lib/rack_warden/frameworks/sinatra.rb
186
+ - lib/rack_warden/helpers.rb
186
187
  - lib/rack_warden/models.rb
187
188
  - lib/rack_warden/models/user.rb
189
+ - lib/rack_warden/routes.rb
188
190
  - lib/rack_warden/version.rb
189
191
  - lib/rack_warden/views/rw_admin.html.erb
190
192
  - lib/rack_warden/views/rw_dbinfo.html.erb
191
193
  - lib/rack_warden/views/rw_index.html.erb
192
194
  - lib/rack_warden/views/rw_layout.html.erb
195
+ - lib/rack_warden/views/rw_layout_admin.html.erb
193
196
  - lib/rack_warden/views/rw_login.html.erb
194
197
  - lib/rack_warden/views/rw_new_user.html.erb
195
198
  - lib/rack_warden/views/rw_protected.html.erb
199
+ - lib/rack_warden/warden.rb
196
200
  - rack_warden.gemspec
197
201
  homepage: ''
198
202
  licenses: