Mathieu Legrand
Mathieu Legrand

Reputation: 162

Stacking database_authenticatable and ldap_authenticatable with devise

I am able to configure independently either :database_authenticatable or :ldap_authenticatable; the first one authenticating against my Rails SQLite development database, and the other against my company's LDAP/Active Directory server.

What I'd like to be able to do now is to stack both authentications. If the user is authenticated against the database, then fine; if it is not then check LDAP (and eventually create the user). I've tried the obvious:

devise :database_authenticatable, :ldap_authenticatable, :rememberable, :trackable

The user is first authenticated against the database as expected:

User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."login" = '[email protected]' LIMIT 1

The query returns one line for the user '[email protected]' (ignore the login column for an email field discrepancy). The problem is that devise then proceeds with the LDAP authentication that fails. How would I tell devise to accept the first successful authentication strategy and stop there?

Upvotes: 3

Views: 1183

Answers (1)

danpalmer
danpalmer

Reputation: 2173

I realise this is an old question, but it came up in a Google Search, so I'll answer it for others who might reach it.

I don't think it is possible do two types of authentication like this through one user model. The way I've done it is with Single Table Inheritance on a User model.

class User < ActiveRecord::Base
end

class LdapUser < User
  devise :ldap_authenticatable, :rememberable, :trackable
end

class LocalUser < User
  devise :database_authenticatable, :registerable, :confirmable, :recoverable, :trackable
end

Only User is created in the database, but it is created with all the fields present in both inheriting models. It also needs an extra column type which is a string. This allows Rails/ActiveRecord to infer the model and inheritance structure, and for it to all work properly.

After this, you can then set up Devise to provide the routes required for each model. This however results in having two login forms. The user shouldn't have to know what type of user they are really, so it's best to combine these into one system.

I asked a question about this previously, but eventually managed to work out a solution, so I recommend reading my answer to this question: https://stackoverflow.com/a/21175515/166210

Upvotes: 3

Related Questions