Created
October 26, 2011 14:35
-
-
Save mamantoha/1316534 to your computer and use it in GitHub Desktop.
Warden integration with Sinatra and DataMapper(w/ BCryptHash) - http://ruby-ua.blogspot.com/2011/10/user-datamapper-bcrypthash-warden.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- encoding: utf-8 -*- | |
require 'sinatra' | |
require 'slim' | |
require 'warden' | |
require 'dm-core' | |
require 'dm-migrations' | |
require 'dm-timestamps' | |
require 'dm-validations' | |
require 'dm-types' | |
DataMapper::Logger.new(STDOUT, :debug) | |
DataMapper.setup(:default, "sqlite:///#{Dir.pwd}/project.db") | |
Slim::Engine.set_default_options :pretty => true | |
# Model and database table to hold administrator's usernames and passwords | |
# | |
class User | |
include DataMapper::Resource | |
property :id, Serial | |
property :name, String | |
property :password, BCryptHash | |
timestamps :at | |
attr_accessor :password_confirmation | |
validates_presence_of :name | |
validates_uniqueness_of :name | |
validates_confirmation_of :password | |
validates_with_method :password_non_blank | |
# Public class method than returns a user object if the caller supplies the correct name and password | |
# | |
def self.authenticate(name, password) | |
user = first(:name => name) | |
if user | |
if user.password != password | |
user = nil | |
end | |
end | |
user | |
end | |
private | |
def password_non_blank | |
if password_confirmation.nil? || password_confirmation.empty? | |
[ false, 'Missing password'] | |
else | |
true | |
end | |
end | |
end | |
# finalize them after declaring all of the models | |
DataMapper.finalize | |
# wipes out existing data | |
DataMapper.auto_upgrade! | |
# create test user | |
#User.create(:name => 'user', :password => 'qwerty') | |
### Rack Setup | |
# | |
use Rack::Session::Cookie, :secret => "bla-bla-bla" | |
use Warden::Manager do |manager| | |
manager.default_strategies :password | |
manager.failure_app = FailureApp.new | |
end | |
### | |
### Session Setup | |
# Tell Warden how to serialize the user in and out of the session. | |
# | |
Warden::Manager.serialize_into_session do |user| | |
puts '[INFO] serialize into session' | |
user.id | |
end | |
Warden::Manager.serialize_from_session do |id| | |
puts '[INFO] serialize from session' | |
User.get(id) | |
end | |
### | |
### Declare Some Strategies | |
# | |
Warden::Strategies.add(:password) do | |
def valid? | |
puts '[INFO] password strategy valid?' | |
params['username'] || params['password'] | |
end | |
def authenticate! | |
puts '[INFO] password strategy authenticate' | |
u = User.authenticate(params['username'], params['password']) | |
u.nil? ? fail!('Could not login in') : success!(u) | |
end | |
end | |
### | |
class FailureApp | |
def call(env) | |
uri = env['REQUEST_URI'] | |
puts "failure #{env['REQUEST_METHOD']} #{uri}" | |
end | |
end | |
get '/' do | |
redirect '/login' unless env['warden'].user | |
slim :index | |
end | |
get '/login/?' do | |
slim :login | |
end | |
post '/login/?' do | |
if env['warden'].authenticate | |
redirect '/' | |
else | |
redirect '/login' | |
end | |
end | |
get '/logout/?' do | |
env['warden'].logout | |
redirect '/' | |
end | |
# index | |
get '/users/?' do | |
@users = User.all(:order => [ :name.asc ]) | |
slim :'/users/index' | |
end | |
# new | |
get '/users/new' do | |
@user = User.new | |
slim :'/users/new' | |
end | |
# show | |
get '/users/:id' do | |
@user = User.first(params[:id]) | |
slim :'/users/show' | |
end | |
# edit | |
get '/users/:id/edit' do | |
@user = User.first(params[:id]) | |
end | |
# create | |
post '/users' do | |
@user = User.create(:name => params[:name], :password => params[:password], :password_confirmation => params[:password_confirmation]) | |
if @user.save | |
redirect '/users' | |
else | |
slim :'/users/new' | |
end | |
end | |
# update | |
put '/users/:id' do | |
@user = User.first(params[:id]) | |
if @user.update(:name => params[:name], :password => params[:password], :password_confirmation => params[:password_confirmation]) | |
redirect '/users' | |
else | |
slim :'/users/edit' | |
end | |
end | |
# destroy | |
delete '/users/:id' do | |
@user = User.first(params[:id]) | |
@user.destroy! | |
redirect '/users' | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
p Welcome, #{env['warden'].user.name} | |
a href='/logout' Log out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form action='/login' method='post' | |
ul | |
li#username | |
label Username: | |
br | |
input name='username' type='text' | |
li#password | |
label Password: | |
br | |
input name='password' type='password' | |
input type='submit' value='Log in' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
h1 Listing users | |
table | |
tr | |
th Name | |
- @users.each do |user| | |
tr | |
td= user.name | |
td | |
a href="/users/#{user.id}" Show | |
td | |
a href="/users/#{user.id}/edit" Edit | |
br | |
a href="/users/new" New User |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
form method='post' action='/users' | |
fieldset | |
legend Enter User Details | |
div | |
label Name: | |
input type='text' name='name' | |
div | |
label Password: | |
input type='password' name='password' | |
div | |
label Confirm: | |
input type='password' name='password_confirmation' | |
input type='submit' value='Add User' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/test1.rb b/test2.rb | |
index d4e5d66..d901d7a 100644 | |
--- a/test1.rb | |
+++ b/test2.rb | |
@@ -8,7 +8,7 @@ require 'dm-core' | |
require 'dm-migrations' | |
require 'dm-timestamps' | |
require 'dm-validations' | |
-require 'digest/sha1' | |
+require 'dm-types' | |
DataMapper::Logger.new(STDOUT, :debug) | |
DataMapper.setup(:default, "sqlite:///#{Dir.pwd}/project.db") | |
@@ -22,8 +22,7 @@ class User | |
property :id, Serial | |
property :name, String | |
- property :hashed_password, String | |
- property :salt, String | |
+ property :password, BCryptHash | |
timestamps :at | |
@@ -40,44 +39,23 @@ class User | |
def self.authenticate(name, password) | |
user = first(:name => name) | |
if user | |
- expected_password = encrypted_password(password, user.salt) | |
- if user.hashed_password != expected_password | |
+ if user.password != password | |
user = nil | |
end | |
end | |
user | |
end | |
- def password | |
- @password | |
- end | |
- | |
- def password=(pwd) | |
- @password = pwd | |
- return if pwd.empty? | |
- create_new_salt | |
- self.hashed_password = User.encrypted_password(self.password, self.salt) | |
- end | |
- | |
private | |
def password_non_blank | |
- if hashed_password.nil? || hashed_password.empty? | |
+ if password_confirmation.nil? || password_confirmation.empty? | |
[ false, 'Missing password'] | |
else | |
true | |
end | |
end | |
- def create_new_salt | |
- self.salt = self.object_id.to_s + rand.to_s | |
- end | |
- | |
- def self.encrypted_password(password, salt) | |
- string_to_hash = password + "wibble" + salt | |
- Digest::SHA1.hexdigest(string_to_hash) | |
- end | |
- | |
end | |
# finalize them after declaring all of the models |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment