Ruby on Rails 3: ошибка неопределенного метода Devise :: LdapAdapter.get_ldap_param - PullRequest
6 голосов
/ 16 ноября 2011

Я бегу: Ruby 1.9.3p0, Рельсы 3.1.1, Разработать 1.4.9, Devise_ldap_authenticatable 0.4.10

Я использую Devise для аутентификации моего Rails-приложения через ldap-сервер. Я использую имя пользователя вместо электронной почты для аутентификации, поэтому, естественно, поле электронной почты в моей таблице пустое.

Чтобы запросить 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"=>"<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

И гемфайл:

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 - это правильное имя поля у пользователей. Есть ли ошибка в этом методе? Может ли быть несовместимость версий? Я не совсем уверен, что еще нужно проверить, и рельсы не дают мне ничего нового для начинающих. Я хотел бы помочь с этим.

Ответы [ 4 ]

2 голосов
/ 21 сентября 2012

Итак, вот проблема и потенциальное решение.

ldap_get_param предполагает, что анонимный доступ на чтение к серверу LDAP разрешен, и, таким образом, пытался связать и прочитать с {:method => :anonymous}. Если ваш сервер не разрешает анонимный поиск и т. Д. Active Directory по умолчанию не работает, тогда ваш вызов завершится с ошибочным сообщением об ошибке выше, которое на самом деле пытается сказать «нет подходящих результатов».

К сожалению, devise_ldap_authenticable не позволяет вам требовать аутентификацию для операций чтения, поэтому я пошел и раздвоил копию, которая делает. Чтобы использовать его вместо этого, вставьте его в свой 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)

Обратите внимание на третий параметр там. Я также отправил запрос мастеру на откат, и вы можете отследить проблему здесь: https://github.com/cschiewek/devise_ldap_authenticatable/issues/94

2 голосов
/ 02 декабря 2011

У меня также есть эта проблема - мое текущее временное решение состоит в том, чтобы получать данные самостоятельно, используя Net::LDAP вместо ldap_authenticatable классов. Конечно, более постоянное решение будет заключаться в исправлении ldap_authenticatable, что я могу попробовать сделать дальше.

Проблема (по крайней мере для меня) заключалась в следующем: после просмотра кода ldap_authenticatable (а именно ldap_adapter.rb) я обнаружил, что метод get_ldap_param не аутентифицируется на сервере при попытке извлечь параметры, если только admin_user и admin_password указаны в ldap.yml. Таким образом, если ваш сервер LDAP позволяет анонимное чтение данных, get_ldap_param будет работать так, как объявлено. В OpenLDAP (это то, что я использую для локального тестирования), анонимный доступ на чтение устанавливается со свойством «access to» в slapd.conf:

access to *
  by anonymous auth

Но мой корпоративный LDAP не позволяет этого.

Экземпляр Net :: LDAP в ldap_authenticatable необходимо создавать с параметрами auth, когда он используется для выборки параметров, но это не так. Параметры аутентификации не указываются, поэтому результаты не возвращаются.

Итак, временно, в моей модели User есть следующий код, вызывающий 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

Изменить в соответствии с вашими потребностями. Это не идеально, но пока работает, пока не разветвляется / исправляется ldap_authenticatable для учета этого варианта использования.

1 голос
/ 10 февраля 2012

Возможно, это связано с версией, которую вы используете.

Изучая git-репозиторий проекта, я вижу, что метод get_ldap_param был введен в версии 0.4.7.

Убедитесь, что у вас нет ограничений на версию гема devise_ldap_authenticatable в вашем Gemfile, и удалите их в случае, затем запустите

$ bundle update devise_ldap_authenticatable

, он должен обновить ваш гем до версии 0.6.0 (сdevise 2.0.1), и метод присутствует и работает.

Вы также можете указать минимальную версию в Gemfile, если считаете, что это так:

gem 'devise_ldap_authenticatable', '~> 0.4.7'
1 голос
/ 16 ноября 2011

Боюсь, у меня нет ответа для вас, но я могу вам сказать, что я получаю ту же самую ошибку, что и вы.

Я сделал несколько постов здесь, в StackOverflow, но не получил ни одного ответа.У меня все работает нормально, пока я не попытаюсь получить дополнительные атрибуты и: before_save.Я проследил свой сервер eDir с помощью ndstrace, и он говорит, что вопрос, который он получает, пуст?Таким образом, кажется, что мой выбранный атрибут не передается на сервер ldap.

...