# encoding: UTF-8 module Vines class Storage # Authenticates usernames and passwords against an LDAP directory. This can # provide authentication logic for the other, full-featured Storage # implementations while they store and retrieve the rest of the user # information. class Ldap @@required = [:host, :port] %w[tls dn password basedn object_class user_attr name_attr groupdn].each do |name| @@required << name.to_sym unless name == 'groupdn' define_method name do |*args| @config[name.to_sym] = args.first end end def initialize(host='localhost', port=636, &block) @config = {host: host, port: port} instance_eval(&block) @@required.each {|key| raise "Must provide #{key}" if @config[key].nil? } end # Validates a username and password by binding to the LDAP instance with # those credentials. If the bind succeeds, the user's attributes are # retrieved. def authenticate(username, password) username = JID.new(username).to_s rescue nil return if [username, password].any? {|arg| (arg || '').strip.empty? } ldap = connect(@config[:dn], @config[:password]) entries = ldap.search( attributes: [@config[:name_attr], 'mail'], filter: filter(username)) return unless entries && entries.size == 1 user = if connect(entries.first.dn, password).bind name = entries.first[@config[:name_attr]].first User.new(jid: username, name: name.to_s, roster: []) end user end # Return an LDAP search filter for a user optionally belonging to the # group defined by the groupdn config attribute. def filter(username) clas = Net::LDAP::Filter.eq('objectClass', @config[:object_class]) uid = Net::LDAP::Filter.eq(@config[:user_attr], username) filter = clas & uid if group = @config[:groupdn] memberOf = Net::LDAP::Filter.eq('memberOf', group) isMemberOf = Net::LDAP::Filter.eq('isMemberOf', group) filter = filter & (memberOf | isMemberOf) end filter end private def connect(dn, password) options = [:host, :port, :base].zip( @config.values_at(:host, :port, :basedn)) Net::LDAP.new(Hash[options]).tap do |ldap| ldap.encryption(:simple_tls) if @config[:tls] ldap.auth(dn, password) end end end end end