ruby-on-rails - Ruby on Rails 3: Devise::LdapAdapter.get_ldap_param 未定义方法错误

标签 ruby-on-rails ruby devise ldap

我正在运行: ruby 1.9.3p0, rails 3.1.1, 设计 1.4.9, Devise_ldap_authenticatable 0.4.10

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

在ldap中查询email,官方的做法是在用户模型中加入这段代码:

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"=>"<hidden>=", "user"=>{"username"=>"<hidden>", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
User Load (0.9ms)  SELECT "users".* FROM "users" WHERE "users"."username" = '<hidden>' LIMIT 1
  LDAP: LDAP dn lookup: uid=<hidden>
  LDAP: LDAP search for login: uid=<hidden>
  LDAP: Authorizing user <hidden>
  LDAP: LDAP dn lookup: uid=<hidden>
  LDAP: LDAP search for login: <hidden>
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 成功验证,与电子邮件查询无关。

我上周才开始学习 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'


<... unrelated ...>

gem 'therubyracer', :platforms => :ruby
gem "devise"
gem "devise_ldap_authenticatable"

我已尝试重新启动服务器,并在上次 GemFile 更新后完成了捆绑安装。我的配置有 ldap_create_user = true 并且 username 是用户中的正确字段名称。那个方法有错误吗?会不会是版本不兼容?我不太确定还有什么要检查的,而且 Rails 没有给我任何适合初学者的东西。我希望得到一些帮助。

最佳答案

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

问题(至少对我而言)是这样的:在仔细研究了 ldap_authenticatable 代码(即 ldap_adapter.rb)后,我发现 get_ldap_param 方法未通过身份验证服务器在尝试获取参数时,除非在 ldap.yml 中指定了 admin_useradmin_password。因此,如果您的 LDAP 服务器允许匿名读取数据,则 get_ldap_param 将如宣传的那样工作。在 OpenLDAP(这是我用于本地测试的)上,匿名读取访问是使用 slapd.conf 中的“访问”属性设置的:

access to *
  by anonymous auth

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

ldap_authenticatable 中的Net::LDAP 实例在用于取参时需要使用auth 参数创建,但事实并非如此。未提供身份验证参数,因此不会返回任何结果。

所以,暂时,我的用户模型中有以下代码,调用 get_ldap_data 作为 before_save 过滤器:

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

根据您的特定需求进行修改。这并不理想,但目前可以使用,直到 fork /修补 ldap_authenticatable 以解决此用例。

关于ruby-on-rails - Ruby on Rails 3: Devise::LdapAdapter.get_ldap_param 未定义方法错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8142587/

相关文章:

ruby-on-rails - 避免在 root_path 设计验证闪现消息

ruby-on-rails - 设计在身份验证失败时使用 JSON 请求登录不起作用

ruby-on-rails - 使用 Rails 远程设计 ajax 登录/注册 : true

ruby-on-rails - 如果我有 IDEA,我需要 ruby​​mine 来开发 ruby​​ 还是两者兼而有之?

ruby-on-rails - 如何在 ruby​​ on rails 中创建向导表单

mysql - azk - 如何设置测试数据库?

ruby-on-rails - Ruby on Rails 教程第 5 章 Failure/Error it {should have_selector

ruby-on-rails - 为什么工厂女孩没有对独特的属性进行排序?

ruby - Ruby 中 (a == 0 || a == foo) 的任何捷径?

ruby - 如何在 Rails 中使用不同的 Webrick(不是当前 Ruby 的版本)