Skip to content

Instantly share code, notes, and snippets.

@spullen
Created November 8, 2012 20:43
Show Gist options
  • Save spullen/4041453 to your computer and use it in GitHub Desktop.
Save spullen/4041453 to your computer and use it in GitHub Desktop.
HybridAuthenticatable 2
# db/migrate/<timestamp>_devise_create_user.rb
# This is pretty much stock rails g devise User
# with the only exception being t.boolean :override_ldap, :default => false
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :username, :null => false, :default => ""
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
t.boolean :override_ldap, :default => false
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
## Token authenticatable
# t.string :authentication_token
t.timestamps
end
add_index :users, :username, :unique => true
add_index :users, :reset_password_token, :unique => true
# add_index :users, :confirmation_token, :unique => true
# add_index :users, :unlock_token, :unique => true
# add_index :users, :authentication_token, :unique => true
end
end
# lib/hybrid_authenticatable/models/hybrid_authenticatable.rb
require 'devise'
require 'strategy'
require 'models/hybrid_authenticatable'
require 'models/password_encryptable'
module HybridAuthenticatable
end
Devise.add_module(:hybrid_authenticatable,
:route => :session,
:strategy => true,
:controller => :sessions,
:model => 'models/hybrid_authenticatable')
Devise.add_module(:password_encryptable,
:route => :session,
:strategy => false,
:controller => :sessions,
:model => 'models/password_encryptable')
# lib/hybrid_authenticatable/models/hybrid_authenticatable.rb
require 'strategy'
module Devise
module Models
module HybridAuthenticatable
extend ActiveSupport::Concern
end
end
end
# lib/hybrid_authenticatable/models/password_encryptable.rb
require 'bcrypt'
module Devise
module Models
module PasswordEncryptable
extend ActiveSupport::Concern
included do
attr_reader :password, :current_password
attr_accessor :password_confirmation
end
def self.required_fields(klass)
[:encrypted_password] + klass.authentication_keys
end
# Generates password encryption based on the given value.
def password=(new_password)
@password = new_password
self.encrypted_password = password_digest(@password) if @password.present?
end
# A reliable way to expose the salt regardless of the implementation.
def authenticatable_salt
encrypted_password[0,29] if encrypted_password
end
protected
# Digests the password using bcrypt.
def password_digest(password)
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
end
module ClassMethods
Devise::Models.config(self, :pepper, :stretches)
end
end
end
end
# lib/hybrid_authenticatable/strategy.rb
require 'devise/strategies/authenticatable'
module Devise
module Strategies
class HybridAuthenticatable < Authenticatable
def authenticate!
resource = mapping.to.find_for_authentication(authentication_hash)
return fail(:invalid) if resource.nil? || !valid_password?
if resource.override_ldap == true
mapping.to.send(:extend, Devise::Models::DatabaseAuthenticatable::ClassMethods)
mapping.to.send(:include, Devise::Models::DatabaseAuthenticatable)
return fail(:invalid) unless resource.valid_password?(password)
else
mapping.to.send(:include, Devise::Models::LdapAuthenticatable)
return fail(:invalid) unless resource.valid_ldap_authentication?(password)
end
if validate(resource)
success!(resource)
else
return fail(:invalid)
end
end
end
end
end
Warden::Strategies.add(:hybrid_authenticatable, Devise::Strategies::HybridAuthenticatable)
# app/models/user.rb
class User < ActiveRecord::Base
devise :hybrid_authenticatable, :password_encryptable, :rememberable, :trackable
attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :override_ldap
validates :username, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true
validates :password, :presence => true, :if => lambda { |user| user.override_ldap == true }
end
@spullen
Copy link
Author

spullen commented Nov 9, 2012

Don't mind the other two devise_create_user migration files, Github Gist is being wonky. The one with the comment text at the top is the correct one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment