Skip to content

Instantly share code, notes, and snippets.

@jarrad
Last active January 1, 2016 15:49
Show Gist options
  • Save jarrad/8167062 to your computer and use it in GitHub Desktop.
Save jarrad/8167062 to your computer and use it in GitHub Desktop.
Needed to extend Devise to integrate and authenticate with a legacy app. Stitched this solution together after reading multiple articles and trying various combinations therein.
# config/initializers/devise.rb
require 'devise/models/remote_authenticatable'
require 'remote_auth_strategy'
Devise.setup do |config|
# all the other shenanigans...
config.warden do |manager|
manager.intercept_401 = false
manager.default_strategies(:scope => :user).unshift :remote
end
# and any more shenanigans...
end
# inform Warden about our custom auth strategy
Warden::Strategies.add(:remote, RemoteAuthStrategy)
# lib/remote_auth_strategy.rb
class RemoteAuthStrategy < Warden::Strategies::Base
def valid?
Rails.logger.info '[INFO] remote strategy valid?'
params['user'] && (params['user'].fetch('email') || params['user'].fetch('password'))
end
def authenticate!
Rails.logger.info '[INFO] remote strategy authenticate'
# assuming we submitted from a devise form...
user = params[:user]
u = User.new
# use our custom model to authentication the given credentials
u = u.remote_authentication( :email => user[:email], :password => user[:password] )
u.nil? or u.eql? false ? fail!('unauthorized') : success!(u)
end
end
# lib/devise/models/remote_authenticatable.rb
module Devise
module Models
module RemoteAuthenticatable
extend ActiveSupport::Concern
#
# Here you do the request to the external app using an
# ActiveResource model
#.
# If the authentication is successful, you should return
# a resource instance.
#
# If the authentication fails, you should return false.
#
def remote_authentication(authentication_hash)
begin
# invoke /users/sign_in on other app
# ensure you use SSL :-)
response = MyRemoteService::User.get(:sign_in, {:email => authentication_hash[:email], :password => authentication_hash[:password]})
rescue
return false
end
return false if response.nil?
# create our local (PORO) User model to hold the details
user = User.new
user.id = response['id']
user.email = response['email']
user
end
module ClassMethods
####################################
# Overriden methods from Devise::Models::Authenticatable
####################################
#
# This method is called from:
# Warden::SessionSerializer in devise
#
# It takes as many params as elements had the array
# returned in serialize_into_session
#
# Recreates a resource from session data
#
def serialize_from_session(id,email)
resource = self.new
resource.id = 1
resource.email = email
resource
end
#
# Here you have to return and array with the data of your resource
# that you want to serialize into the session
#
# You might want to include some authentication data
#
def serialize_into_session(record)
[record.id, record.email]
end
end
end
end
end
# app/models/user.rb
# PORO User object...
class User
include ActiveModel::Validations #required because some before_validations are defined in devise
extend ActiveModel::Callbacks #required to define callbacks
extend Devise::Models
attr_accessor :email, :password, :id
define_model_callbacks :validation #required by Devise
# because we include our custom model in the devise/models directory,
# devise will use it with no further action required
devise :remote_authenticatable
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment