Rails LDAP login using net/ldap - ruby-on-rails

I am trying to get LDAP authentication to work under Rails.
I have chosen net/ldap since it's a native Ruby LDAP library.
I have tried all possible stuff, specially examples from http://net-ldap.rubyforge.org/classes/Net/LDAP.html but still unable to get it work.
Any ideas?

The best solution I managed to reach is a Model with the following:
require 'net/ldap'
class User < ActiveRecord::Base
def after_initialize
#config = YAML.load(ERB.new(File.read("#{Rails.root}/config/ldap.yml")).result)[Rails.env]
end
def ldap_auth(user, pass)
ldap = initialize_ldap_con
result = ldap.bind_as(
:base => #config['base_dn'],
:filter => "(#{#config['attributes']['id']}=#{user})",
:password => pass
)
if result
# fetch user DN
get_user_dn user
sync_ldap_with_db user
end
nil
end
private
def initialize_ldap_con
options = { :host => #config['host'],
:port => #config['port'],
:encryption => (#config['tls'] ? :simple_tls : nil),
:auth => {
:method => :simple,
:username => #config['ldap_user'],
:password => #config['ldap_password']
}
}
Net::LDAP.new options
end
def get_user_dn(user)
ldap = initialize_ldap_con
login_filter = Net::LDAP::Filter.eq #config['attributes']['id'], "#{user}"
object_filter = Net::LDAP::Filter.eq "objectClass", "*"
ldap.search :base => #config['base_dn'],
:filter => object_filter & login_filter,
:attributes => ['dn', #config['attributes']['first_name'], #config['attributes']['last_name'], #config['attributes']['mail']] do |entry|
logger.debug "DN: #{entry.dn}"
entry.each do |attr, values|
values.each do |value|
logger.debug "#{attr} = #{value}"
end
end
end
end
end

I work on a Devise plugin for Rails 3 that uses LDAP for authentication, you can look at the source to get some ideas, it currently uses net-ldap 0.1.1:
http://github.com/cschiewek/devise_ldap_authenticatable
The actual connecting and authenticating to the LDAP sever is done at:
http://github.com/cschiewek/devise_ldap_authenticatable/blob/master/lib/devise_ldap_authenticatable/ldap_adapter.rb
Lastly, you can look at the sample LDAP server config and Rails 3 app I use to run the tests against:
App: http://github.com/cschiewek/devise_ldap_authenticatable/tree/master/test/rails_app/
Server: http://github.com/cschiewek/devise_ldap_authenticatable/tree/master/test/ldap/

Related

Ruby on Rails, Zendesk API integration not loading the client

I am trying to set up the Zendesk API in my app, I have decided to go with the API that was built by Zendesk
I have set up the initializer object to load the client.
config/initializers/zendesk.rb
require 'zendesk_api'
client = ZendeskAPI::Client.new do |config|
# Mandatory:
config.url = Rails.application.secrets[:zendesk][:url]
# Basic / Token Authentication
config.username = Rails.application.secrets[:zendesk][:username]
config.token = Rails.application.secrets[:zendesk][:token]
# Optional:
# Retry uses middleware to notify the user
# when hitting the rate limit, sleep automatically,
# then retry the request.
config.retry = true
# Logger prints to STDERR by default, to e.g. print to stdout:
require 'logger'
config.logger = Logger.new(STDOUT)
# Changes Faraday adapter
# config.adapter = :patron
# Merged with the default client options hash
# config.client_options = { :ssl => false }
# When getting the error 'hostname does not match the server certificate'
# use the API at https://yoursubdomain.zendesk.com/api/v2
end
This is pretty much copy paste from the site, but I have decided on using the token + username combination.
I then created a service object that I pass a JSON object and have it construct tickets. This service object is called from a controller.
app/services/zendesk_notifier.rb
class ZendeskNotifier
attr_reader :data
def initialize(data)
#data = data
end
def create_ticket
options = {:comment => { :value => data[:reasons] }, :priority => "urgent" }
if for_operations?
options[:subject] = "Ops to get additional info for CC"
options[:requester] = { :email => 'originations#testing1.com' }
elsif school_in_usa_or_canada?
options[:subject] = "SRM to communicate with student"
options[:requester] = { :email => 'srm#testing2.com' }
else
options[:subject] = "SRM to communicate with student"
options[:requester] = { :email => 'srm_row#testing3.com' }
end
ZendeskAPI::Ticket.create!(client, options)
end
private
def for_operations?
data[:delegate] == 1
end
def school_in_usa_or_canada?
data[:campus_country] == "US" || "CA"
end
end
But now I am getting
NameError - undefined local variable or method `client' for #<ZendeskNotifier:0x007fdc7e5882b8>:
app/services/zendesk_notifier.rb:20:in `create_ticket'
app/controllers/review_queue_applications_controller.rb:46:in `post_review'
I thought that the client was the same one defined in my config initializer. Somehow I think this is a different object now. I have tried looking at their documentation for more information but I am lost as to what this is?
If you want to use the client that is defined in the initializer you would need to make it global by changing it to $client. Currently you have it setup as a local variable.
I used a slightly different way of initializing the client, copying from this example rails app using the standard Zendesk API gem:
https://github.com/devarispbrown/zendesk_help_rails/blob/master/app/controllers/application_controller.rb
As danielrsmith noted, the client variable is out of scope. You could instead have an initializer like this:
config/initializers/zendesk_client.rb:
class ZendeskClient < ZendeskAPI::Client
def self.instance
#instance ||= new do |config|
config.url = Rails.application.secrets[:zendesk][:url]
config.username = Rails.application.secrets[:zendesk][:username]
config.token = Rails.application.secrets[:zendesk][:token]
config.retry = true
config.logger = Logger.new(STDOUT)
end
end
end
Then return the client elsewhere by client = ZendeskClient.instance (abridged for brevity):
app/services/zendesk_notifier.rb:
class ZendeskNotifier
attr_reader :data
def initialize(data)
#data = data
#client = ZendeskClient.instance
end
def create_ticket
options = {:comment => { :value => data[:reasons] }, :priority => "urgent" }
...
ZendeskAPI::Ticket.create!(#client, options)
end
...
end
Hope this helps.

Listing all OU's in LDAP with Rails

I am trying to list all Organizational Units (OU) from my LDAP directory. I am using the "devise_ldap_authenticatable" gem to authenticate my users. The LDAP sign in works fine. I am trying to get all the OU's now.
I'm new to LDAP, please let me know if my search query is wrong here.
ldap = Net::LDAP.new
ldap.host = "192.168.0.100"
ldap.port = 389
ldap.auth "cn=admin,dc=company,dc=com", "password"
treebase = "dc=company,dc=com"
filter = Net::LDAP::Filter.eq( "objectClass=organizationalUnit","company.com" )
attrs = ["*"]
ldap.search( :base => treebase, :filter => filter, :attributes => attrs, :return_result => false ) do |entry|
puts entry
end
When I ran this, I got nothing returned. I have two OU's in my LDAP, DevOps and Development. There are 5 test users in each.
I'm not sure if this is the right way to do it, but it got me what I wanted and I'm happy with that.
I just removed the filter and retrieved the ou from the entry directly.
ldap.search( :base => treebase, :attributes => attrs, :return_result => false ) do |entry|
puts entry["ou"]
end

Using Ruby Webrick HTTPAuth with LDAP

The app I am writing has the ability to have a login popup appear and it authenticates against a hard coded username/password constant pair. I would like to authenticate against our central LDAP server. the we dont have a base however we do have a bind_dn string of "cn=USERFOO,ou=it,o=corporate". The variables user/pass are passed in through the basic login box.
I am trying to do this through ActiveLdap however I dont mind using any other library as long as I can validate the credentials through a single sign on against our LDAP server using the HTTPAuth since is written completely in Webrick Ruby. Below is a sample of the function I am calling.
Does anyone have any idea how to do this?
Thanks in advance.
def authenticate_ldap(req,res)
authlabel = "LDAP Authentication"
HTTPAuth.basic_auth(req, res, authlabel) { |user, pass|
ActiveLdap::Base.setup_connection(
:host => 'ldap.internalserver.com',
:port => 389,
:bind_dn => "cn=#{user},ou=it,o=corporate",
:password_block => Proc.new { pass },
)
}
return
end
I figured out a solution. The person who manages our LDAP server provided the incorrect ldap connection string, but even with that it still didn't work.
The solution I discovered that did indeed make a connection with very basic validation is something to this effect for anyone else interested in a very simple ldap authentication popup in pure Ruby.
def authenticate(req,res)
authlabel = 'LDAP Authentication'
HTTPAuth.basic_auth(req, res, authlabel) { |user, pass|
if pass.to_s != ''
ldap = Net::LDAP.new
ldap.host = "ldap.serverfoo.com"
ldap.port = 389
result = ldap.bind_as(
:base => "t=basetreefoo",
:filter => "uid=#{user}",
:password => pass
)
if result
ldap = Net::LDAP.new :host => "ldap.serverfoo.com",
:port => "389",
:auth => {
:method => :simple,
:username => "",
:password => ""
}
group_name = Net::LDAP::Filter.eq("cn", "#{user}")
group_type = Net::LDAP::Filter.eq("groupmembership", "cn=infra,ou=IT,o=Corporate")
filter = group_name & group_type
treebase = "t=basetreefoo"
ldap.search(:base => treebase, :filter => filter) do |entry|
if entry.dn.to_s != ""
puts 'success'
return
end
end
end
end
puts 'fail'
}
end

Is there a way to test an email connection with the email gem?

My rails application uses a Ruby script retrieve an object from my database.
This objet is made of six fields that are:
login
password
server
port
event_type_id
active
Using the mail gem, I'm using these informations to create a new Mail connection using Mail.defaults, like this in my MailConnection model:
def check
begin
puts("Attempting to connect to the specified email server...")
Mail.defaults do
retriever_method :pop3, :address => :server,
:port => :port,
:user_name => :login,
:password => :password,
:enable_ssl => false
end
rescue Exception => msg
puts("Unconnected : #{msg}")
false
else
puts("Connected")
true
end
end
I'm using this method in the Ruby script to check if the connection can be etablished before doing anything, but if I'm using invalid datas, it's still returning 'true' even if the network is unreachable.
I'm all new to Ruby and, I would like to know what's wrong with my function;
Thanks in advance.
I'm a beginner myself but have just been having a look at this.
With net/pop
require 'net/pop'
pop = Net::POP3.new('your.mail.server', optional_port)
pop.start('your_username', 'your_password') #should return an error if it fails
pop.started? #if you want to double check
With the Mail gem
If you'd rather use the Mail gem itself, the connection method in the POP3 retriever lets you get at those same methods by yielding a POP3 object to a block:
Mail.defaults do
retriever_method :pop3, :address => :server,
:port => :port,
:user_name => :login,
:password => :password,
:enable_ssl => false
end
Mail.connection {|pop3| pop3.active? }
You might notice I used started? and active? interchangeably: they are the same POP3 instance method. One is simply aliased to the other.

ActiveMerchant's support for determining the account status (verified/unverified) of a PayPal Express Checkout customer/buyer

I am currently working on a Ruby-on-Rails web-application that accepts PayPal payments through PayPal's Express Checkout and ActiveMerchant. I have done several research on ActiveMerchant's support for determining if a customer/buyer has paid using either a verified or unverified PayPal account but I got no luck on finding a helpful guide.
I find it also that ActiveMerchant is currently not well-documented so it's not that helpful at all.
Below are the relevant codes that my project is currently using. On PaymentsController#purchase, I temporarily used the #params['protection_eligibility'] and the #params['protection_eligibility_type'] methods of the ActiveMerchant::Billing::PaypalExpressResponse object that is returned by the EXPRESS_GATEWAY.purchase method call, to assess if a PayPal customer/buyer has a verified/unverified PayPal account. Later I found out that this is not a reliable basis for knowing the customer's account status.
I hope somebody can give me a wisdom on knowing whether a PayPal customer/buyer has a verified/unverified account using Ruby-on-Rails' ActiveMerchant or using other alternatives on Rails.
# config/environments/development.rb
config.after_initialize do
ActiveMerchant::Billing::Base.mode = :test
paypal_options = {
# credentials removed for this StackOverflow question
:login => "",
:password => "",
:signature => ""
}
::EXPRESS_GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
end
# app/models/payment.rb
class Payment < ActiveRecord::Base
# ...
PAYPAL_CREDIT_TO_PRICE = {
# prices in cents(US)
1 => 75_00,
4 => 200_00,
12 => 550_00
}
STATUSES = ["pending", "complete", "failed"]
TYPES = ["paypal", "paypal-verified", "paypal-unverified", "wiretransfer", "creditcard"]
# ...
end
# app/controllers/payments_controller.rb
class PaymentsController < ApplicationController
# ...
def checkout
session[:credits_qty] = params[:credit_qty].to_i
total_as_cents = Payment::PAYPAL_CREDIT_TO_PRICE[session[:credits_qty]]
setup_purchase_params = {
:allow_guest_checkout => true,
:ip => request.remote_ip,
:return_url => url_for(:action => 'purchase', :only_path => false),
:cancel_return_url => url_for(:controller => 'payments', :action => 'new', :only_path => false),
:items => [{
:name => pluralize(session[:credits_qty], "Credit"),
:number => 1,
:quantity => 1,
:amount => Payment::PAYPAL_CREDIT_TO_PRICE[session[:credits_qty]]
}]
}
setup_response = EXPRESS_GATEWAY.setup_purchase(total_as_cents, setup_purchase_params)
redirect_to EXPRESS_GATEWAY.redirect_url_for(setup_response.token)
end
def purchase
if params[:token].nil? or params[:PayerID].nil?
redirect_to new_payment_url, :notice => I18n.t('flash.payment.paypal.error')
return
end
total_as_cents = Payment::PAYPAL_CREDIT_TO_PRICE[session[:credits_qty]]
purchase_params = {
:ip => request.remote_ip,
:token => params[:token],
:payer_id => params[:PayerID],
:items => [{
:name => pluralize(session[:credits_qty], "Credit"),
:number => 1,
:quantity => 1,
:amount => Payment::PAYPAL_CREDIT_TO_PRICE[session[:credits_qty]]
}]
}
purchase = EXPRESS_GATEWAY.purchase total_as_cents, purchase_params
if purchase.success?
payment = current_user.payments.new
payment.paypal_params = params
payment.credits = session[:credits_qty]
payment.amount = Payment::PAYPAL_CREDIT_TO_PRICE[session[:credits_qty]]
payment.currency = "USD"
payment.status = "complete"
if(purchase.params["receipt_id"] && (purchase.params["success_page_redirect_requested"] == "true"))
payment.payment_type = "creditcard"
else
if purchase.params['protection_eligibility'] == 'Eligible' && purchase.params['protection_eligibility_type'] == 'ItemNotReceivedEligible,UnauthorizedPaymentEligible'
payment.payment_type = 'paypal-verified'
else
payment.payment_type = 'paypal-unverified'
end
end
payment.ip_address = request.remote_ip.to_s
payment.save!
SiteMailer.paypal_payment(payment).deliver
SiteMailer.notice_payment(payment).deliver
notice = I18n.t('flash.payment.status.thanks')
redirect_to profile_url, :notice => notice
else
notice = I18n.t('flash.payment.status.failed', :message => purchase.message)
redirect_to new_payment_url, :notice => notice
end
end
# ...
end
I used PayPal's paypal-sdk-merchant gem to do the job ActiveMerchant wasn't able to help me with (getting the status of a payer's account: verified/unverified PayPal account. I followed the installation of paypal-sdk-merchant on https://github.com/paypal/merchant-sdk-ruby
gem 'paypal-sdk-merchant'
bundle install
rails generate paypal:sdk:install
Then I set-up their samples https://github.com/paypal/merchant-sdk-ruby#samples. After setting-up the samples, go to /samples of your Rails app and you will find a lot of code generator for what ever function you need from PayPal's API. Don't forget to configure your config/paypal.yml. I configured the username, password and signature (can be obtained from your PayPal sandbox specifically your test seller account) and removed the app_id in my case.
I obtained the following code for getting a PayPal payer's account status (verified/unverified) using PayPal's samples (/samples) and placed it on a class method of a model in my app:
def self.get_paypal_payer_status(transaction_id)
require 'paypal-sdk-merchant'
api = PayPal::SDK::Merchant::API.new
get_transaction_details = api.build_get_transaction_details({
:Version => "94.0",
:TransactionID => transaction_id
})
get_transaction_details_response = api.get_transaction_details(get_transaction_details)
get_transaction_details_response.payment_transaction_details.payer_info.payer_status
end
I'm not familiar with ActiveMerchant so I can't tell you specific to that, but with any Express Checkout implementation you can use GetExpressCheckoutDetails to obtain the payers information which will include a PAYERSTATUS parameter with a value of "verified" or "unverified".
It's an optional call, but I would assume ActiveMerchant is probably including it so you just need to track that down and pull that parameter accordingly.
Alternatively, you can use Instant Payment Notification (IPN) to receive transaction information and you will get back a payer_status parameter here as well.

Resources