I'm authenticating against LDAP server in my rails application,
the code below is working locally but not on the server.
On the server it throws Net::LDAP::BindingInformationInvalidError (Invalid binding information) when trying to login in the app but works through the console
I'm pretty new to Ruby and can't figure out the proper way to debug it... I know the LDAP configuration is right because i can authenticate and bind from the console or on my local development environment.. I tried to pass :verbose => true to the LDAP constructor but without effect...
require 'net/ldap'
require 'devise/strategies/authenticatable'
module Devise
module Strategies
class LdapAuthenticatable < Authenticatable
def authenticate!
if params[:user]
ldap = Net::LDAP.new :host => 'XX.XX.XX.XX',
:port => 636,
:connect_timeout => 5,
:base => 'CN=Configuration,DC=internal,DC=XX,DC=XX',
:encryption => {
:method => :simple_tls
},
:auth => {
:method => :simple,
:username => ENV['LDAP_USER'],
:password => ENV['LDAP_PASSWORD']
}
result = ldap.bind_as(:base => "OU=Users,OU=XX,DC=XX,DC=XX,DC=XX",
:filter => "(userPrincipalName=#{email})",
:password => password,
)
if result
user = User.find_by(email: email)
success!(user)
else
return fail(:invalid_login)
end
end
end
def email
params[:user][:email]
end
def password
params[:user][:password]
end
end
end
end
Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
SOLVED
turned out it was the ENV variables that were not read.
Maybe that account is not authorized? Sounds like the problem is in the binding configuration: base => "OU=Users,OU=XX,DC=XX,DC=XX,DC=XX"
More information from other users who encountered this error:
https://gitlab.com/gitlab-org/gitlab-ce/issues/21937
LDAP groups authentication fails: Invalid Binding Information
Related
Environment
Ruby 2.7.4 (Rails API only)
Rails 6.0.4.1
Devise 4.8.0
Omniauth1.8.1
Current behavior
Getting omniauth missing_credentials? error. The request.params is always an empty hash even though I provide username and password in the request body via POST method. I can see the body params when debugging actual controller, but it looks like those params are not passed to omniauth request.
Controller:
module Api
module V1
module Auth
class OmniauthCallbacksController < Devise::OmniauthCallbacksController #< ApplicationController#
include ActionController::Cookies
def ldap
puts request.env['omniauth.auth'] # => NULL
end
def failure
puts "request.env['omniauth.auth']: #{request.env['omniauth.auth']}" # => NULL
puts "request.env['omniauth.params']: #{request.env['omniauth.params']}" # => {}
puts "params: #{params}" # => { "username": "myusername", "password": "mypassword" }
render json: { status: "fail" }
end
end
end
end
end
Application.rb:
config.api_only = true
config.session_store :cookie_store, key: '_interslice_session'
config.middleware.use ActionDispatch::Cookies
config.middleware.use config.session_store, config.session_options
Routes.rb:
devise_for :users, controllers: { omniauth_callbacks: 'api/v1/auth/omniauth_callbacks' }
Devise.rb:
config.omniauth :ldap, :host => 'XXX.com',
:port => 389,
:method => :plain,
:base => 'cn=accounts,dc=int,dc=dostack,dc=io',
:uid => 'uid',
:try_sasl => false,
:bind_dn => "uid=XXX,cn=users,cn=accounts,dc=int,dc=dostack,dc=io",
:password => "xxxxxxxx"
Response:
Expected behavior
Authenticate using omniauth (LDAP or using any other omniauth provider)
I want to use seperate admin login for my application using idenity provider.
I have written this in config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :identity, :model => Credential, :on_failed_registration =>SessionsController.action(:register)
provider :identity, :model => Credential, :name => 'admin', :on_failed_registration => SessionsController.action(:login_admin)
provider :google_oauth2, '000000000.apps.googleusercontent.com', '00000000000'
end
In config/routes.rb
match '/auth/admin/callback', :to => 'sessions#authenticate_admin'
In app/controllers/sessions_controller.rb
def authenticate_admin
auth_hash = request.env['omniauth.auth']
session[:admin_user] = auth_hash['user_info']['email']
if admin?
redirect_to '/'
else
render :text => '401 Unauthorized', :status => 401
end
end
But when i try to access request.env['omniauth.auth'], it always gets nil. While it is accessible when using default callback for normal users at sessison#create action. I just want to know if there is anything that has been missed in this code. I am following this blog http://www.intridea.com/blog/2011/1/31/easy-rails-admin-login-with-google-apps-and-omniauth.
I have the following simple script, which checks an email account and if there is new mail it forwards the email and sends an SMS. This happens as expected when the script is run without Process.daemon. When it is added, and email is received at the email account, nothing happens (nothing is forwarded and no SMS is sent) and there are no error messages in the console. Any suggestions?
#!/usr/bin/env ruby
require "bundler/setup"
require "mailman"
require "twilio-ruby"
Mailman.config.pop3 = {
:username => 'address#gmail.com',
:password => 'password',
:server => 'pop.gmail.com',
:port => 995,
:ssl => true
}
Mailman.config.poll_interval = 60
Mailman::Application.run do
default do
begin
Ticket.receive_mail(message)
MailForwarder.forwarded_email(message).deliver
#account_sid = 'xxxxxxxxxxx'
#auth_token = 'xxxxxxxxxx'
#client = Twilio::REST::Client.new(#account_sid, #auth_token)
#account = #client.account
#sms = #account.sms.messages.create(
:from => '+1111111111',
:to => '+122222222',
:body => message.subject
)
puts #sms
puts "#{message.subject}"
rescue Exception => e
Mailman.logger.error "Exception occurred whle receiving message:\n#{message}"
Mailman.logger.error [e, *e.backtrace].join("\n")
end
end
Process.daemon
end
I believe you need to set up your script as a daemon before you start up the mailman application. I did a bit of testing, and it worked fine if I called Process.daemon before calling the Mailman::Application.run but it didn't work if I put it where you had it.
So I had it as:
....
Mailman.config.poll_interval = 15
Process.daemon
Mailman::Application.run do
default do
end
end
I am trying to rewrite an older app that was created with PHP/MySQL.
The authentication system used has a users table in the database that stores username, email etc... but NOT passwords.
Whenever the user logs in it first checks the database to see if the user exists if not then returns a login error. If the user exists in the local database then it tries to bind to the active directory using the username/password combination entered by the user and creates a session if successful.
What is the best way to accomplish this using Rails?
Ruby's Net::LDAP library is pretty good.
Here's a simplified version of what I've been using for years:
# sessions_controller.rb
def create
user = User.find_by_login(params[:login])
if user && Ldap.authenticate(params[:login], params[:password])
self.current_user = user
Rails.logger.info "Logged in #{user.name}"
flash[:notice] = "Successfully Logged In!"
redirect_back_or_default root_url
else
flash[:alert] = "Invalid User credentials"
render :new
end
end
# lib/ldap.rb
# Ldap.authenticate('user','password')
# Returns true if validated
# Returns false if invalidated
# Returns nil if LDAP unavailable
require 'net/ldap'
class Ldap
def self.config
# this is actually loaded from a yaml config file
{
:domain => 'YOURDOMAIN',
:host => '10.10.10.100'
}
end
def self.authenticate(login, password)
conn = Net::LDAP.new(
:host => config[:host],
:port => 636,
:base => "dc=#{config[:domain]}, dc=local",
:encryption => :simple_tls,
:auth => {
:username => "#{login}##{config[:domain]}.local",
:password => password,
:method => :simple
}
)
Timeout::timeout(15) do
return conn.bind ? true : false
end
rescue Net::LDAP::LdapError => e
notify_ldap_admin(config[:host],'Error',e)
nil
rescue Timeout::Error => e
notify_ldap_admin(config[:host],'Timeout',e)
nil
end
def self.notify_ldap_admin(host,error_type,error)
msg = "LDAP #{error_type} on #{host}"
RAILS_DEFAULT_LOGGER.debug(msg)
DeveloperMailer.deliver_ldap_failure_msg(msg,error)
end
end
Check out the devise and devise_ldap_authenticatable libraries.
I'm struggling with Heroku sending gmail with actionmailer in my Rails app.
I've got my gmail username and password correctly set as Heroku config vars, but I still get authentication errors. I finally discovered that I need to create an initializer but I'm having trouble hooking everything together. The following code brings up the correct username and password in the heroku logs, but with a NoMethodError. Not sure where to put the method to make it all work. I've tried putting it in my users_controller but that makes the whole thing crash.
I'm planning to add my S3 stuff to this initializer once I get this working.
my initializers/heroku.rb
GMAIL_CREDENTIALS = { :username => ENV['GMAIL_USERNAME'],
:password => ENV['GMAIL_PASSWORD'] }
my mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
default from: "mygmailaddress", :gmail_credentials => GMAIL_CREDENTIALS
def signup_confirmation(user)
#user = user
mail to: user.email, subject: "Sign Up Confirmation"
end
end
and create in my users_controller:
def create
#user = User.new(params[:user])
if #user.save
UserMailer.signup_confirmation(#user).deliver
sign_in #user
flash[:success] = "Welcome to Plain Vanilla!"
redirect_to #user
else
render 'new'
end
end
The error message in heroku logs:
Completed 500 Internal Server Error in 482ms
app/controllers/users_controller.rb:21:in `create'
NoMethodError (undefined method `encoding' for {:username=>"mygmailusername",
:password=>"mypassword"}:Hash):
Thanks for any help!
Charlie
I normally put my gmail credentials in an intializer called mailer.rb. It looks like this:
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "mail.google.com",
:user_name => ENV['MY_GMAIL_USER_NAME'],
:password => ENV['MY_GMAIL_PASSWORD'],
:authentication => "plain",
:enable_starttls_auto => true
}
Where did you get the code you're using? I'd try dropping the :gmail_credentials line from your user_mailer and using an initializer that's more like mine. Don't forget to restart your app if you change these files.
Hope this helps,