Project

lom

0.0
No release in over a year
Creation of mapping between ldap entry and ruby object. Allowing easy retrieval of information, building of search filter, and updating ldap.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 13
~> 0

Runtime

 Project Readme

LDAP Object Mapper

Allow to map LDAP object to ruby object.

It is best used with dry-struct and dry-struct-setters libraries

Examples

require 'net/ldap'
require 'lom/ldap'

using LOM::LDAP::Extensions

# Define LDAP handler used by LOM
LH = Net::LDAP.connect('ldap://127.0.0.1')
LH.auth 'uid=root,ou=Admins,dc=example,dc=com', 'foobar'
# Defining mapping between LDAP and ruby using Dry::Struct
#
class User < Dry::Struct
    include Dry::Struct::Setters
    using LOM::LDAP::Extensions
    
    ADMINS_BRANCH     = 'ou=Admins,dc=example,dc=com'
    TEAMS_BRANCH      = 'ou=Team,dc=example,dc=com'
    
    #
    # Defining LDAP mapping
    # 
    extend LOM::Mapper

    ldap_branch  "ou=People,dc=example,dc=com"
    ldap_filter  '(objectClass=inetOrgPerson)'
    ldap_attrs   '*', '+'
    ldap_prefix  :uid
    
    ldap_from   do
        {
            :firstname       => first(:givenName,             String   ),
            :lastname        => first(:sn,                    String   ),
            :email           => first(:mail,                  String   ),
            :homepage        => first(:labeledURI,            String   ),
            :address         => first(:postalAddress,         String   ),
            :title           => first(:title,                 String   ),
            :type            =>   all(:objectClass,           String   )
                                    .map(&:downcase)
                                    .include?('posixaccount') ? :full : :minimal,
            :login           => first(:uid,                   String   ),
            :password        => nil,
            :managers        =>   all(:manager,               String   )
                                    .map {|m| User.ldap_dn_to_id(m) },
            :locked          => first(:pwdAccountLockedTime,  Time     ),
            :uid             => first(:uidNumber,             Integer  ),
            :gid             => first(:gidNumber,             Integer  ),
            :home            => first(:homeDirectory,         String   ),
            :teams           =>   all(:memberOf,              String   ).map{|m|
                    LOM.id_from_dn(m, TEAMS_BRANCH, :cn)
                }.compact,
        }.compact
    end

    ldap_to do
        oclass = [ 'inetOrgPerson' ]
        if type == :full
            oclass += [ 'posixAccount', 'sambaSamAccount', 'pwdPolicy' ]
            { :gecos      => fullname,
              :loginShell => '/bin/bash'
            }
        end
        
        { :givenName        => firstname,
          :sn               => lastname,
          :cn               => fullname,
          :mail             => email,
          :labeledURI       => homepage,
          :postalAddress    => address,
          :title            => title,
          :uid              => login,
          :manager          => managers.map {|m| User.ldap_dn_from_id(m) },
          :pwdAccountLockedTime => locked,
          :uidNumber        => uid,
          :gidNumber        => gid,
          :homeDirectory    => home.to_s,
        }
    end

    ldap_list    :locked,  ->(predicate=true) do
        Filtered.exists(:pwdAccountLockedTime, predicate: predicate)
    end

    ldap_list   :manager,  ->(manager) do
        Filtered.has(:manager, manager) {|m|
            case m
            when true,  nil   then Filtered::ANY
            when false, :none then Filtered::NONE
            else User.ldap_dn_from_id(m.to_str)
            end
        }
    end
    
    ldap_list    :query,    ->(str) do
        Filtered.match(:uid, str) |
        Filtered.match(:cn,  str) |
        Filtered.match(:givenName, str) | Filtered.match(:sn, str)
    end
    

    #
    # Object structure
    #
    
    transform_keys(&:to_sym)
    
    attribute  :firstname,       Types::String
    attribute  :lastname,        Types::String
    attribute  :email,           Types::EMail
    attribute? :homepage,        Types::WebPage.optional
    attribute? :address,         Types::String.optional
    attribute  :title,           Types::String
    attribute  :type,            Types::Symbol.enum(:minimal, :full)
    attribute  :login,           Types::Login
    attribute? :password,        Types::Password.optional
    attribute? :managers,        Types::Array.of(Types::Login)
    attribute? :locked,          Types::Time.optional
    attribute? :uid,             Types::Integer
    attribute? :gid,             Types::Integer
    attribute? :home,            Types::Pathname
    attribute  :teams,           Types::Array.of(Types::Team)

    # Various User representation that can be used in processing
    # as string, in sql statement, as JSON
    def to_s            ; self.login                       ; end
    def to_str          ; self.login                       ; end
    def sql_literal(ds) ; ds.literal(self.login)           ; end
    def to_json(*a)     ; self.to_hash.compact.to_json(*a) ; end
   
    # User full name.
    def fullname
        [ firstname, lastname ].join(' ')
    end
end
# Return user id of users for which account has been locked and 
# with "John Doe" as manager 
User.locked(true).manager('jdoe').list

# Return list of users (as User instance)  without managers
User.manager(false).all