Multiple groups in ldap device authenticatable - ruby-on-rails

I am trying to allow users to login who are present in group1 or group2
but during LDAP authorization it is checking in both groups.
If user is present in either group1 or group2 i need to allow them to login.
Can anybody assist on this?
In devise.rb
config.ldap_check_group_membership = true
In ldap.yml
authorizations: &AUTHORIZATIONS
group_base: ou=groups,dc=test,dc=com
required_groups:
cn=admins,ou=groups,dc=test,dc=com -----group1
cn=users,ou=groups,dc=test,dc=com ----- group2
require_attribute:
# objectClass: inetOrgPerson
# authorizationRole: postsAdmin
development:
host: # ip address is to be filled in here..
port: # port number goes here..
attribute: cn
base: # my tree base details go in here..
admin_user: cn=admin_name,dc=test,dc=com
admin_password: # password goes in here..
ssl: true
<<: *AUTHORIZATIONS

/devise_ldap_authenticatable-0.8.3/lib/devise_ldap_authenticatable/ldap/connection.rb
def in_required_groups?
return true unless #check_group_membership
## FIXME set errors here, the ldap.yml isn't set properly.
return false if #required_groups.nil?
arr_res = []
for group in #required_groups
if group.is_a?(Array)
res = in_group?(group[1],group[0])
arr_res << res
# return false unless in_group?(group[1], group[0])
else
return false unless in_group?(group)
end
end
DeviseLdapAuthenticatable::Logger.send(arr_res)
return true if arr_res.include? true
# return true
end

Only 4 months late but for anyone still facing this, you can monkey patch a single method in the gem
module Devise
module LDAP
class Connection
def in_required_groups?
found = false
return true unless #check_group_membership
return false if #required_groups.nil?
for group in #required_groups
if group.is_a?(Array)
found = true if in_group?(group[1], group[0])
# return false unless in_group?(group[1], group[0])
else
found = true if in_group?(group)
# found = true if in_group?(group[1], group[0])
end
end
return found
end
end
end
end

Related

Existence of ActiveModel::SecurePassword authenticate method (Rails 6)

The "authenticate" method can only be found here: https://apidock.com/rails/ActiveModel/SecurePassword/InstanceMethodsOnActivation/authenticate
, with version 6.0.0 being grayed out. So this seems to be outdated.
I have searched the Rails 6 documentation for the authenticate method, and found no record of it under https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html.
Yet in the code snippet on the same page
# Schema: User(name:string, password_digest:string, recovery_password_digest:string)
class User < ActiveRecord::Base
has_secure_password
has_secure_password :recovery_password, validations: false
end
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save # => true
user.recovery_password = "42password"
user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
user.save # => true
user.authenticate('notright') # => false
user.authenticate('mUc3m00RsqyRe') # => user
user.authenticate_recovery_password('42password') # => user
User.find_by(name: 'david')&.authenticate('notright') # => false
User.find_by(name: 'david')&.authenticate('mUc3m00RsqyRe') # => user
The authenticate method is still used (user.authenticate). Where does this method come from if I can't find it in the latest documentation?
Edit:
A related question regarding differences in documentation: I am able to find ActionDispatch::Request::Session on rubydocs but not on api.rubyonrails.
https://www.rubydoc.info/docs/rails/ActionDispatch/Request/Session
https://api.rubyonrails.org/classes/ActionDispatch/Request.html
Now I am not certain where I should be looking when searching for methods. Is api.rubyonrails not the "definitive" place to look for documentation?
It looks like they forgot to mention it in the documentation for has_secure_password. If you look into source code of ActiveModel::SecurePassword. You will find
# Returns +self+ if the password is correct, otherwise +false+.
#
# class User < ActiveRecord::Base
# has_secure_password validations: false
# end
#
# user = User.new(name: 'david', password: 'mUc3m00RsqyRe')
# user.save
# user.authenticate_password('notright') # => false
# user.authenticate_password('mUc3m00RsqyRe') # => user
define_method("authenticate_#{attribute}") do |unencrypted_password|
attribute_digest = public_send("#{attribute}_digest")
BCrypt::Password.new(attribute_digest).is_password?(unencrypted_password) && self
end
alias_method :authenticate, :authenticate_password if attribute == :password
You can se it is now defined as dynamic method based on the parametr name provided to has_secure_password method. So they implemented it in more general way. And to be more friendly with backwards compatibility the implemented the alias authenticate for authenticate_password which was the original implementation.
Unfortunately these dynamic methods are not very well documented in the rails API docs.

Devise LDAP can't find user, but logs in fine

So when I authorize a user with the devise_ldap_authenticatable gem, I get the following logged information:
LDAP: LDAP dn lookup: sAMAccountName=john.smith
LDAP: LDAP search for login: sAMAccountName=john.smith
LDAP: LDAP search yielded 0 matches
LDAP: Authorizing user lt\john.smith
As I understand it, the search fails to return a user, which I would like to find so I could set other attributes based off of LDAP fields (mainly department).
I've checked that this search should work with the following rake task:
desc "LDAP Test"
task ldap: :environment do
ldap = Net::LDAP.new :host => ENV['LDAP_IP'],
:port => ENV['LDAP_PORT'],
:encryption => :simple_tls,
:base => ENV['LDAP_BASE'],
:auth => {
:method => :simple,
:username => ENV['LDAP_LOGIN'],
:password => ENV['LDAP_PASSWORD']
}
if ldap.bind
ldap.search(:base => ENV['LDAP_BASE'], :filter => Net::LDAP::Filter.eq("sAMAccountName", "john.smith"), :attributes => ["sAMAccountName", "department"], :return_result => false) do |entry|
entry.each do |attr, values|
puts "#{attr}: #{values.first}"
end
end
else
puts "Connection failed! Code: #{ldap.get_operation_result.code}, message: #{ldap.get_operation_result.message}"
end
end
Which returns:
dn: CN=John Smith,OU=Temporary Staff,OU=Users,DC=lt,DC=local
department: Bioinformatics
samaccountname: Johh.Smith
Does anyone know why the login search could be failing? My config files are as follows:
devise.rb:
# ==> LDAP Configuration
config.ldap_logger = true
config.ldap_create_user = true
config.ldap_update_password = false
# config.ldap_config = "#{Rails.root}/config/ldap.yml"
config.ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "lt\\#{login}"}
# config.ldap_check_group_membership = false
# config.ldap_check_attributes = false
config.ldap_use_admin_to_bind = true
ldap.yml:
development:
host: <%= ENV['LDAP_IP'] %>
port: <%= ENV['LDAP_PORT'] %>
attribute: sAMAccountName
base: <%= ENV['LDAP_BASE'] %>
admin_user: <%= ENV['LDAP_LOGIN'] %>
admin_password: <%= ENV['LDAP_PASSWORD'] %>
ssl: true
# <<: *AUTHORIZATIONS
I would use a packet sniffer like Wireshark to see the difference between the LDAP requests in the rake task vs. devise. The UnboundID LDAP SDK for Java also ships with a tool called LDAPDebugger that you can use as a proxy between your app and Active Directory to decode the traffic.
I hope this helps.

Using ldap to connect to ad with devise ruby on rails

Question I am having issues connecting to my Microsoft Active Directory using the devise_ldap_authentication. For some reason I keep getting LDAP search yielded 0 matches when using it with devise and I am 100% certain I am using the correct credentials, so I wrote a test class using 'net/ldap' to see if I could yeild a correct match and presto it works with my test class but, I still can't authenticate with devise_ldap_auth. Any help would be greatly appreciated or help with setting up my config/ldap.yml to match my test class.
Here is my config/ldap.yml
#Environment
development:
host: myldap.mydomain.com
port: 389
attribute: sAMAccountname
base: dc=mydomain, dc=com
admin_user: cn=admin,dc=mydomain,dc=com
admin_password: password
#ssl: false
Here is my devise.rb
Devise.setup do |config|
# ==> LDAP Configuration
config.ldap_logger = true
# config.ldap_create_user = false
# config.ldap_update_password = true
config.ldap_config = "#{Rails.root}/config/ldap.yml"
# config.ldap_check_group_membership = false
# config.ldap_check_group_membership_without_admin = false
config.ldap_check_attributes = true
#config.ldap_use_admin_to_bind = true
# config.ldap_ad_group_check = false
this is what I get back when using ldap with devise.
D, [2016-06-24T07:01:30.558440 #42760] DEBUG -- : LDAP: LDAP dn lookup: sAMAccountName=snow
D, [2016-06-24T07:01:30.558507 #42760] DEBUG -- : LDAP: LDAP dn lookup: sAMAccountName=snow
D, [2016-06-24T07:01:30.558549 #42760] DEBUG -- : LDAP: LDAP search for login: sAMAccountName=snow
D, [2016-06-24T07:01:30.558579 #42760] DEBUG -- : LDAP: LDAP search for login: sAMAccountName=snow
D, [2016-06-24T07:01:30.594029 #42760] DEBUG -- : LDAP: LDAP search yielded 0 matches
D, [2016-06-24T07:01:30.594099 #42760] DEBUG -- : LDAP: LDAP search yielded 0 matches
D, [2016-06-24T07:01:30.594146 #42760] DEBUG -- : LDAP: Authorizing user sAMAccountName=snow,dc=mydomain, dc=com
D, [2016-06-24T07:01:30.594180 #42760] DEBUG -- : LDAP: Authorizing user sAMAccountName=snow,dc=mydomain, dc=com
D, [2016-06-24T07:01:30.611308 #42760] DEBUG -- : LDAP: Not authorized because not authenticated.
D, [2016-06-24T07:01:30.611377 #42760] DEBUG -- : LDAP: Not authorized because not authenticated.
Here is my test class that works to authenticate with ldap on my microsoft AD
require 'net/ldap' # gem install ruby-net-ldap
module Test
class PutAd
SERVER = 'myldap.mydomain.com'
PORT = 389
BASE = 'DC=mydomain,DC=com'
DOMAIN = 'mydomain.com'
ATTR_SV = {
:login => :samaccountname,
:first_name => :givenname,
:last_name => :sn,
:email => :mail
}
def self.authenticate(login, pass)
return nil if login.empty? or pass.empty?
conn = Net::LDAP.new :host => SERVER,
:port => PORT,
:base => BASE,
:auth => { :username => "#{login}##{DOMAIN}",
:password => pass,
:method => :simple }
if conn.bind and user = conn.search(:filter => "sAMAccountName=#{login}").first
return self.new(user)
else
return nil
end
rescue Net::LDAP::LdapError => e
return nil
end
end
end
^This will return my account information if it matches if not it will return nil.
Turns out my company has a different way of authorizing a user. I added the advanced flag to my devise ldap install, and set this accordingly and presto it worked.
==> Advanced LDAP Configuration
config.ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "#{login}#mydomain.com"}

LDAP groups authentication fails: Invalid Binding Information

I'm using devise_ldap_authenticatable to log in into my Rails app via LDAP. Log in works for user (with username), but does not work for groups: when I try to check if user is in a particular group I get:
'Net::LDAP::BindingInformationInvalidError in
Devise::SessionsController#create
Invalid binding information
Extracted source (around line #244):
raise Net::LDAP::BindingInformationInvalidError, "Invalid binding information" unless (user && psw)
I tried several suggested solutions but they all failed with the error mentioned above.
First attempted solution
I tried changing config.ldap_check_group_membership=false to config.ldap_check_group_membership=true in devise.rb:
config.ldap_create_user = true
config.ldap_check_group_membership = true
config.ldap_check_attributes = false
config.ldap_use_admin_to_bind = false
config.ldap_ad_group_check = true (also tried false with this one)
and setting groups in ldap.yml file like this:
authorizations: &AUTHORIZATIONS
group_base: OU=US,DC=um,DC=com #also tried without group_base, with group_base DC=um,DC=com
required_groups:
- CN=D US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com
- CN=B US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com
later like that:
authorizations: &AUTHORIZATIONS
#also tried without group_base, with group_base DC=um,DC=com
group_base: OU=US,DC=um,DC=com
required_groups:
["memberOf", "CN=D US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com;CN=B US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com"]
Second attempted solution
After this failed, I also tried changing ldap_check_attributes=false to ldap_check_attributes=true in devise.rb:
config.ldap_create_user = true
config.ldap_check_group_membership = false
config.ldap_check_attributes = true
config.ldap_use_admin_to_bind = false
and setting attribute in ldap.yml file like this:
authorizations: &AUTHORIZATIONS
require_attribute:
memberOf: CN=D US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com
development:
host: <%= ENV["LDAP_HOST"] %>
port: <%= ENV["LDAP_PORT"] %>
attribute: 'userprincipalname'
base: 'DC=um,DC=com'
ssl: <%= ENV["LDAP_SSL"] %>
<<: *AUTHORIZATIONS
I have access to AD, I know, that group is correct. When I look at my account there, I see something like this:
memberOf: CN=D US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com;CN=B US
Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com
What am I doing wrong?
Today I managed to find one solution that worked. I've changed devise.rb file like this:
config.ldap_create_user = true
config.ldap_check_group_membership = false
config.ldap_check_attributes = true
config.ldap_use_admin_to_bind = false
and ldap.yml like that:
authorizations: &AUTHORIZATIONS
#group_base:
#required_groups:
require_attribute:
memberOf: CN=D US Workers,OU=Workers,OU=abc,OU=US,DC=um,DC=com
development:
host: <%= ENV["LDAP_HOST"] %>
port: <%= ENV["LDAP_PORT"] %>
attribute: sAMAccountName
base: DC=um,DC=com
ssl: <%= ENV["LDAP_SSL"] %>
admin_user: <%= ENV["LDAP_ADMIN_USER"] %> # currently my own: CN=name surname,OU=Workers,OU=abc,OU=US,DC=um,DC=com
admin_password: <%= ENV["LDAP_ADMIN_PASSWORD"] %> currently my own password
<<: *AUTHORIZATIONS
If I find better solution, I'll post it. Feel free to suggest your way too.

Devise ldap authenticable does not lookup correctly

I am trying to get user properties from ldap on rails + devise_ldap_authenticatable
(devise_ldap_authenticatable 0.8.1, rails 3.2.14)
Blow is my configuration
devise.rb
config.ldap_logger = true
config.ldap_create_user = true
config.ldap_config = "#{Rails.root}/config/ldap.yml"
ldap.yml (./config/ldap.yml)
authorizations: &AUTHORIZATIONS
group_base: OU=Employee,OU=Person,DC=TEST,DC=AD
required_groups:
- CN=users,OU=Employee,OU=Person,DC=TEST,DC=AD
require_attribute:
objectClass: inetOrgPerson
authorizationRole: postsAdmin
development:
host: 192.168.1.10
port: 389
attribute: CN
base: OU=Employee,OU=Person,DC=TEST,DC=AD
ssl: false
user.rb
devise :ldap_authenticatable, :registerable, revoerable,
:rememberable, :trackable, :validatable
before_save :get_ldap_email
def get_ldap_email
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username, "mail")
end
and my LDAP(AD) status is
CN=12345678,OU=Employee,OU=Person,DC=TEST,DC=AD is exist
and it has mail attribute => "12345678#test.com"
The Login process was good
But It didn't get any properties
log is ...
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`username` = '12345678' ORDER BY created_at DESC LIMIT 1
LDAP: LDAP dn lookup: CN=12345678
LDAP: LDAP search for login: CN=12345678
LDAP: LDAP search yielded 0 matches
LDAP: Authorizing user 12345678#test.ad
LDAP: LDAP dn lookup: CN=12345678
LDAP: LDAP search for login: CN=12345678
LDAP: LDAP search yielded 0 matches
and
Devise::LDAP::Adapter.get_ldap_param(self.username, "mail")
#It returns nil
Maybe the lookup address is wrong...
(maybe CN=12345678,OU=Employee,OU=Person,DC=TEST,DC=AD is correct)
How can i fix it?
How can i get user properties? (ex: mail ...)
Try this:
def get_ldap_email
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first
end
before_save :get_ldap_email
admin_user: your correct root dn
admin_password: you correct pw
In devise.rb
config.ldap_use_admin_to_bind = true

Resources