Подтвердить что ты не робот

Аутентификация на одном сервере в Ruby/Rack

Я пишу и размещаю веб-приложения на серверах Windows для использования внутри сети. В моем стеке сервера используется Sinatra (который использует Rack), Thin и (в некоторых случаях) Apache для обратного проксирования.

Я хочу поддерживать Single Sign-on (используя NTLM или Kerberos) в нашем домене с поддержкой ActiveDirectory. Я видел, что я могу использовать mod_ntlm или mod_auth_kerb, когда я за Apache выполняю свою аутентификацию NTLM. Я еще не пробовал это, но я предполагаю, что это сработает.

Мой вопрос касается проверки подлинности NTLM или Kerberos, когда я не отстаю от Apache, используя только Thin и Sinatra. Я видел rack-ntlm, но детали использования там чрезвычайно разрежены.

Предоставьте известный рабочий код под Sinatra или Rack, который показывает, как использовать NTLM или Kerberos на стороне сервера, аутентифицироваться с помощью ActiveDirectory (предположительно через net-ldap).

Изменить. Подчеркнул желаемые ответы, так как пока ответы не доходят до предоставления явной помощи, которую задает этот вопрос. Пользователи должны иметь возможность найти этот ответ и иметь рабочее решение, а не указатели на внешние библиотеки, которые они должны выяснить, как использовать.

4b9b3361

Ответ 1

Я написал модуль Rack::Auth, который реализует SSO NTLM. Это может быть немного грубо, но это работает для меня. Он делает все, что требует/реагирует на материал, необходимый для NTLM, и устанавливает REMOTE_USER независимо от того, что отправил браузер.

Здесь код.

Чтобы сделать эту работу, необходимо настроить браузер для отправки файлов NTLM на сервер. В моей среде это произошло только тогда, когда адрес сервера был в списке доверенных доменов. Для Firefox домен должен быть добавлен в список, назначенный клавише network.automatic-ntlm-auth.trusted-uris, к которому можно получить доступ через about:config.

Ответ 2

Пока у меня нет кода для совместного использования и у меня нет сервера AD для тестирования, я опубликую некоторую общую информацию, которую другие могут найти полезной при использовании rack-ntlm (что было бы лучшим путем в эта точка).

Первое, что нужно понять, - это то, что NTLM никогда не дает вам пароль пользователя. Вам НЕ НУЖНО проверять подлинность пользователя внутри вашего приложения. NTLM уже это сделала. Что даст вам стойка-ntlm - это домен + пользователь, с которым вы можете работать.

rack-ntlm выполняет некоторую дополнительную работу с этой информацией, которая может быть или не быть ценной для вас. Вы предоставляете ему сервер AD, порт и набор учетных данных. Это приведет к тому, что пользовательский объект (из-за отсутствия лучшего слова) и просмотрит их в AD с помощью вызова LDAP.

Учетные данные, запрашиваемые в установках rack-ntlm, будут ВАШИМИ учетными данными (или, точнее, учетными данными для конкретного приложения в домене с ограниченным доступом к запросу). С помощью этого запроса вы получите информацию об этом пользователе от AD (членство в группах, адреса электронной почты и т.д.). Вы можете использовать это для дальнейшего заполнения базы данных деталями пользователя.

Следует отметить, что если вы используете какой-либо браузер, отличный от IE (и в некоторых случаях даже с IE), ваши пользователи получат диалоговое окно проверки подлинности HTTP. В зависимости от того, находится ли ваш сайт в "интрасети" или нет, IE автоматически выполнит учетные данные NTLM. Это контролируется на основе браузера, поэтому вы можете не иметь никакого контроля. В firefox есть параметр "about: config", который позволит вам заполнять доверенные сайты.

Итак, если мы вернемся к rack-ntlm, поток будет выглядеть примерно так:

  • браузер → приложение для синатры
  • (работа с вызовом/ответный вызов в ручном режиме
    здесь)
  • rack-ntlm теперь ищет пользователя в AD через LDAP
  • Приложение synatra теперь имеет пользовательские данные от LDAP в некоторых хеш файлах
  • Приложение synatra создает базового пользователя
  • сохранить имя пользователя (без пароля
    потому что у вас его нет) с некоторыми базовый набор способностей в локальном хранилище данных
  • sinatra устанавливает cookie для "входа в систему" ​​или любой

Если бы вы захотели, вы могли бы сопоставить группы AD с ролями приложений в некоторой емкости, чтобы, скажем, администраторы домена автоматически добавлялись к вашей роли администратора.

Ответ 3

Есть люди, которые отвечают на этот вопрос по аутентификации/безопасности, которые дают полностью ложную и вводящую в заблуждение информацию, что потенциально очень опасно. NTLM является двухфазным процессом. У вас есть согласование между клиентом и веб-сервером, которое получает детали от клиента, такие как имя пользователя и токен, зашифрованный хэшем пароля пользователя. Многие люди думают, пока вы можете говорить с NTLM с клиентом, как-то аутентификация произошла. Я понятия не имею, почему люди делают это предположение, может быть, потому, что процесс ручного тряски NTLM относительно запутан.

Если вы остановитесь после первой фазы и не выполняете фактическую аутентификацию, вы доверяете клиенту/пользователю, и в этом случае вы также можете не проводить аутентификацию и просто ставить сообщение "Пожалуйста, не делайте этого используйте это веб-приложение, если вам не разрешено".

Вторая фаза - настоящая аутентификация. Веб-сервер отправляет данные, предоставленные клиентом (зашифрованный токен) контроллеру домена. Контроллер домена знает хэш пароля пользователя, используемого для шифрования токена, и поэтому выполняет такое же шифрование хэша пароля. Если он соответствует значению клиента, то мы знаем, что клиент использовал правильный хэш пароля. Веб-сервер никогда не видит хешированный пароль, он видит только маркер, который был зашифрован хешированным паролем в качестве ключа шифрования.

К сожалению, не так много библиотек LDAP, которые поддерживают возможности NETLOGON, необходимые для фактической аутентификации токена NTLM, возможно, потому что это нетривиальная собственная хрень. Samba (ну на самом деле winbind) - одна из немногих библиотек, которые могут это сделать. В настоящее время библиотека Ruby не поддерживает аутентификацию NTLM, хотя есть много библиотек, которые предоставят вам имя пользователя, сообщенное клиентом, хотя клиент может сообщить обо всем, что ему нравится.

Как правило, если вы являетесь библиотекой NTLM, вы не запрашиваете информацию о своем контроллере домена, то нет способа сделать какую-либо аутентификацию. Многие разработчики этих простых библиотек сами понятия не имеют, что они делают.

Ответ 4

Я использую OmniAuth, чтобы выполнить аутентификацию с интерфейса LDAP ActiveDirectory. Документация довольно хороша, и она легко втягивается в стойку.

Ответ 5

Я успешно использовал модуль Apache Kerberos, который вы упомянули (Http://modauthkerb.sourceforge.net/) Затем он представляет тот же API, что и базовый auth, предоставляя все преимущества Kerberos. Вам просто нужно использовать простой Rack:: Auth:: Basic и что он.

Для простой Rack auth вы, вероятно, можете использовать https://github.com/djberg96/rack-auth-kerberos, но я лично его не пробовал. Однако код выглядит прямо.

Очевидно, что в обоих случаях вам нужно ввести свой сервер в AD.

Ответ 6

У меня это работает без решений для стойки и NTLM.

Для проверки подлинности см. мой ответ здесь: есть способ прочитать имя входа в Windows клиентов, используя ruby ​​on rails

Затем авторизацию можно выполнить с помощью чипа net-ldap, проверив членство в группах безопасности.

Это запускается только один раз, когда запускается сервер/служба, только недостатком этого является необходимость перезапуска службы при изменении членов в группе. Конечно, вы можете сохранить авторизованных пользователей в таблице базы данных.

Вот мой код.

В приложении Sinatra

require 'net-ldap'

HOST     =   "XXXXXX"
PORT     =   389
LDAP = Net::LDAP.new(:host => HOST, :port => PORT)

# get account info somewhere safe
LDAP.auth(CONFIG.admin_user, CONFIG.admin_password)

if LDAP.bind
  log "ldap logged in"
else
  log "ldap login failed"
  abort
end

# CONFIG.permitted_users is the name of the apps security group
$members = get_members CONFIG.permitted_users

и в вспомогательном файле

def get_ldap_username cn
  treebase = "ou=xxxxxx,ou=xxxxxx,ou=xxxxxxx,ou=xxxxxx,dc=xxx,dc=xx"
  filter = Net::LDAP::Filter.eq("cn", cn)
  LDAP.search(:filter => filter, :base => treebase) do |item| 
    return item.sAMAccountName.first
  end
end

def get_members name, members = []
  treebase = "ou=xxxxxxx,ou=xxxxxxx,ou=xxxxxxx,ou=xxxxxx,dc=xxx,dc=xx"
  filter = Net::LDAP::Filter.eq("cn", name)
  LDAP.search(:filter => filter, :base => treebase) do |item| 
    item.each do |attribute, values|
      if attribute == :member
        values.each do |value|
          cn = value[/CN=([^,]+),/,1]

          # my groups all begin with a letter/number sequence
          # recurse this method if member is a group itself
          if cn[0..2].downcase == "xxx" # xxx something else of course
            get_members cn, members
          else
            members << get_ldap_username(cn)
          end

        end
      end
     end
  end
  members # an array of permitted usernames
end

before do
  # authentication code 
  # see /info/396732/is-there-a-way-to-read-a-clients-windows-login-name-using-ruby-on-rails/1802672#1802672

  # authorisation
  unless $members.include? @username
    halt "No access"
  end
end