Ruby on Rails 3:Devise :: LdapAdapter.get_ldap_param undefined方法错误

我正在运行:Ruby 1.9.3p0,Rails 3.1.1,Devise 1.4.9,Devise_ldap_authenticatable 0.4.10

我正在使用Devise通过ldap服务器validation我的Rails应用程序。 我使用用户名而不是电子邮件进行身份validation,因此我表中的电子邮件字段自然是空白的。

要查询ldap的电子邮件,官方方法是在用户模型中添加此代码:

before_save :get_ldap_email def get_ldap_email self.email = Devise::LdapAdapter.get_ldap_param(self.username,"mail") end 

这段代码失败了,没有尝试对ldap做任何事情,用这个:

 undefined method `mail' for nil:NilClass 

它指的是方法定义中的行。 日志输出不再有用:

 Started POST "/users/sign_in" for 10.50.1.96 at 2011-11-15 11:18:16 -0800 Processing by Devise::SessionsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"=", "user"=>{"username"=>"", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"} User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."username" = '' LIMIT 1 LDAP: LDAP dn lookup: uid= LDAP: LDAP search for login: uid= LDAP: Authorizing user  LDAP: LDAP dn lookup: uid= LDAP: LDAP search for login:  Completed 500 Internal Server Error in 251ms NoMethodError (undefined method `mail' for nil:NilClass): app/models/user.rb:14:in `get_ldap_email' 

500错误之前的所有行都是与电子邮件查询无关的正常LDAP成功身份validation。

我上周开始学习Ruby,Rails和Devise,所以我不确定哪些文件最有说服力,但这是我的user.rb模型和gemfile:

 class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable devise :ldap_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable before_save :get_ldap_email # Setup accessible (or protected) attributes for your model attr_accessible :email, :username, :password, :password_confirmation, :remember_me def get_ldap_email self.email = Devise::LdapAdapter.get_ldap_param(self.username,"mail") end end 

和gemfile:

 source 'http://rubygems.org' gem 'rails', '3.1.1' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' gem 'sqlite3'  gem 'therubyracer', :platforms => :ruby gem "devise" gem "devise_ldap_authenticatable" 

我已经尝试重新启动服务器,并且自上次GemFile更新以来已完成捆绑安装。 我的配置有ldap_create_user = true,用户名是用户中正确的字段名称。 该方法有错误吗? 可能存在版本不兼容吗? 我不确定还有什么要检查的,而且rails对我来说没什么好开始的。 我希望得到一些帮助。

我也有这个问题 – 我目前的临时解决方案是使用Net::LDAP而不是ldap_authenticatable类来自己获取数据。 当然,更永久的解决方案是修补ldap_authenticatable ,我可能会尝试下一步。

问题(至少对我来说)是这样的:在通过ldap_authenticatable代码(即ldap_adapter.rb)进行get_ldap_param研究后,我发现get_ldap_param方法在尝试获取params时没有通过服务器进行身份validation,除非在ldap中指定了admin_useradmin_password 。阳明海运。 因此,如果您的LDAP服务器允许匿名读取数据,那么get_ldap_param将按宣传的方式工作。 在OpenLDAP(我用于本地测试)中,使用slapd.conf中的“access to”属性设置匿名读取访问:

 access to * by anonymous auth 

但是,我的公司LDAP不允许这样做。

ldap_authenticatable的Net :: LDAP实例需要在用于参数获取时使用auth参数创建,但事实并非如此。 没有给出auth参数,因此不返回任何结果。

所以,暂时我在我的User模型中有以下代码,将get_ldap_data作为before_savefilter调用:

 def has_ldap_data? [self.email, self.first_name, self.last_name].none? {|v| v.nil?} end def get_ldap_data return true if has_ldap_data? or self.password.nil? ldap = create_ldap ldap.search( :base => ldap.base, :attributes => ['cn', 'sn', 'givenname', 'mail'], :filter => Net::LDAP::Filter.eq('cn', self.username), :return_result => true) do |entry| self.email = entry.mail.first self.first_name = entry.givenname.first self.last_name = entry.sn.first end has_ldap_data? end def create_ldap(password = nil) ldap_config = ldap_config = YAML.load(ERB.new(File.read(::Devise.ldap_config || "#{Rails.root}/config/ldap.yml")).result)[Rails.env] ldap_options = { :host => ldap_config["host"], :port => ldap_config["port"], :base => ldap_config["base"], :auth => { :method => :simple, :username => "cn=#{self.username},#{ldap_config['base']}", :password => password || self.password } } ldap_config["ssl"] = :simple_tls if ldap_config["ssl"] === true ldap_options[:encryption] = ldap_config["ssl"].to_sym if ldap_config["ssl"] Net::LDAP.new(ldap_options) end 

根据您的特定需求进行修改 它并不理想,但现在可以使用,直到分配/修补ldap_authenticatable来解释这个用例。

所以这是问题和潜在的解决方案。

ldap_get_param假定允许对LDAP服务器进行匿名读访问,因此尝试使用{:method => :anonymous}进行绑定和读取。 如果您的服务器不允许匿名搜索,例如。 默认情况下,Active Directory不会出现,因此您的调用将失败并显示上面的模糊错误消息,这实际上是在尝试说“没有匹配的结果”。

不幸的是, devise_ldap_authenticable不允许您要求对读取操作进行身份validation,所以我去分叉了一个副本。 要使用它,请将其插入Gemfile而不是原始文件:

 gem 'devise_ldap_authenticatable', :git => 'https://github.com/jpatokal/devise_ldap_authenticatable.git' 

然后像这样调用get_ldap_param:

 Devise::LdapAdapter.get_ldap_param(self.login,"mail",self.password) 

注意第3个参数。 我还提交了这个作为拉取请求给master,你可以在这里跟踪问题: https : //github.com/cschiewek/devise_ldap_authenticatable/issues/94

我担心我没有得到你的答案,但我可以告诉你,我得到了和你一样的错误。

我在StackOverflow上做了几个post,但没有得到任何答案。 一切正常,直到我尝试拉出额外的属性和:before_save。 我用ndstrace跟踪了我的eDir服务器,它说它得到的问题是空的?! 所以我的选择属性似乎没有传递给ldap服务器。

可能这与您使用的版本有关。

检查项目的git存储库,我看到方法get_ldap_param已经在0.4.7版本中引入。

检查您的devise_ldap_authenticatable中对devise_ldap_authenticatable gem的版本没有限制,并在这种情况下删除它们,然后运行

 $ bundle update devise_ldap_authenticatable 

它应该将你的gem更新到版本0.6.0(使用devise 2.0.1),并且该方法存在并且正常工作。

如果您认为是这种情况,您还可以在Gemfile中指定最低版本:

 gem 'devise_ldap_authenticatable', '~> 0.4.7'