LDAP groups authentication fails: Invalid Binding Information - ruby-on-rails

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.

Related

How to use Rails 5.2 credentials in another .yml file?

I'm using the Cloudinary gem to allow a user to upload their avatar. In the docs, they offer a few ways to supply your api_key and api_secret, however I'm unable to get it work correctly with Rails credentials.
I've tried with the cloudinary.yml:
---
development:
cloud_name: test_cloud
api_key: <%= Rails.application.credentials.cloudinary[:api_key] %>
api_secret: <%= Rails.application.credentials.cloudinary[:api_secret] %>
enhance_image_tag: true
static_file_support: false
production:
cloud_name: test_cloud
api_key: <%= Rails.application.credentials.cloudinary[:api_key] %>
api_secret: <%= Rails.application.credentials.cloudinary[:api_secret] %>
enhance_image_tag: true
static_file_support: true
test:
cloud_name: test_cloud
api_key: <%= Rails.application.credentials.cloudinary[:api_key] %>
api_secret: <%= Rails.application.credentials.cloudinary[:api_secret] %>
enhance_image_tag: true
static_file_support: false
And I've also tried using a cloudinary.rb initializer:
Cloudinary.config do |config|
config.cloud_name = "test_cloud"
config.api_key = Rails.application.credentials.cloudinary[:api_key]
config.api_secret = Rails.application.credentials.cloudinary[:api_secret]
config.enhance_image_tag = true
config.static_file_support = false
end
When I attempt to upload the image, I receive a 500 error CloudinaryException (Must supply api_key). I know that the actual upload itself works because I hard-coded the values into the cloudinary.yml file to test it.
I've also tried using the .fetch function mentioned below, however I receive a key not found: :api_secret (KeyError)
How can I use Rails credentials within either of these files?

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.

Multiple groups in ldap device authenticatable

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

How to read ERb when importing a .yml file in an initializer?

I'm seeing behavior where an encrypted AD ID login works for a database, but not for an AD connection. Both are using the exact same code to decrypt before passing the passwords to their respective endpoints. The encryption itself is confirmed to be working.
Is the ruby <%= DM::Encryption.decrypt(:staging, 'nsad;nasdnvoasidnv;asoin') %> is not being evaluated before being assigned in adauth.rb?
config/database.yml:
#...
staging:
adapter: jdbcmssql
driver: net.sourceforge.jtds.jdbc.Driver
url: 'jdbc:jtds:sqlserver://server/db;domain=DM'
username: some_id
password: <%= DM::Encryption.decrypt(:staging, 'nsad;nasdnvoasidnv;asoin') %>
pool: 10
wait-timeout: 10
#...
config/ad.yml:
#...
staging:
<<: *default
ad.bind_id: some_id
ad.bind_password: <%= DM::Encryption.decrypt(:staging, 'nsad;nasdnvoasidnv;asoin') %>
#...
initializers/adauth.rb:
AD_CONF = YAML.load_file(Rails.root.join('config/ad.yml'))[Rails.env]
Adauth.configure do |c|
c.domain = AD_CONF["ad.domain"]
c.query_user = AD_CONF["ad.bind_id"]
c.query_password = AD_CONF["ad.bind_password"]
c.server = AD_CONF["ad.host"]
c.base = AD_CONF["ad.user_base"]
end
Your question is a little unclear, but it seems like you suspect the ERb (<%= ...) in your YAML file isn't being evaluated before the YAML is parsed in adauth.rb.
It would be easy enough to find out just by printing the value of AD_CONF["ad.bind_password"] in adauth.rb—but it does seem likely, since you're just calling YAML.load_file and never doing anything to parse the ERb. If you want to parse the ERb, you can see how Rails does it in Rails::Application::Configuration.database_configuration. The most important part is this:
yaml = Pathname.new(paths["config/database"].existent.first || "")
# ...snip...
YAML.load(ERB.new(yaml.read).result) || {}
Following this example, you would change the first line in adauth.rb to something like this:
ad_yaml_path = Rails.root.join('config/ad.yml') # The path to the .yml file
ad_yaml = ERB.new( ad_yaml_path.read ).result # Read the file and evaluate the ERB
ad_hash = YAML.load(ad_yaml) # Parse the resulting YAML
AD_CONF = ad_hash[Rails.env]
(The first line works because Rails.root is a Pathname object, and Pathname#join also returns a Pathname, and Pathname#read works like File#read, returning the contents of the file.)
Of course, this can be shortened (you could make it a one-liner but that'd be pretty hard to read):
ad_yaml = ERB.new( Rails.root.join('config/ad.yml').read ).result
AD_CONF = YAML.load(ad_yaml)[Rails.env]
One more thing: Rails 4.2, which is now in beta, has a config_for method that does exactly this. Instead of the above you would just do this:
AD_CONF = Rails.application.config_for(Rails.root + 'config/ad.yml')
So that's neat.

Symfony strange factories.yml

I needed to send an email through symfony but in my factories.yml it has something like this
all:
routing:
class: sfPatternRouting
param:
generate_shortest_url: true
extra_parameters_as_query_string: true
view_cache_manager:
class: sfViewCacheManager
param:
cache_key_use_vary_headers: true
cache_key_use_host_name: true
And I modify them to something like:
all:
mailer:
param:
transport:
class: Swift_SmtpTransport
param:
host: smtp.gmail.com
port: 465
encryption: ssl
username: myemail#gmail.com
password: password
will it effect anything ? or what's the original on top does?
Why remove the previous values? Just merge the two files, like this:
all:
routing:
class: sfPatternRouting
param:
generate_shortest_url: true
extra_parameters_as_query_string: true
view_cache_manager:
class: sfViewCacheManager
param:
cache_key_use_vary_headers: true
cache_key_use_host_name: true
mailer:
param:
transport:
class: Swift_SmtpTransport
param:
host: smtp.gmail.com
port: 465
encryption: ssl
username: myemail#gmail.com
password: password
otherwise the settings for the routing and the view_cache_manager will be the one you can find on that other factories.yml somewhere in lib/vendor/symfony

Resources