Module: Treequel

Extended by:
Loggability
Includes:
Constants
Defined in:
lib/treequel.rb,
lib/treequel/utils.rb,
lib/treequel/mixins.rb,
lib/treequel/exceptions.rb

Overview

A library for interacting with LDAP modelled after Sequel.

Defined Under Namespace

Modules: ANSIColorUtilities, ArrayUtilities, AttributeDeclarations, Constants, ContentSyncControl, Control, DateExtensions, Delegation, HashUtilities, LDAPControlExtensions, LDAPModExtensions, Loggable, Normalization, PagedResultsControl, SortedResultsControl, TimeExtensions Classes: BeforeHookFailed, Branch, BranchCollection, Branchset, ColorLogFormatter, ControlError, Directory, Error, ExpressionError, Filter, HtmlLogFormatter, LogFormatter, Model, ModelError, ParseError, Schema, UnsupportedControl, ValidationFailed

Constant Summary collapse

VERSION =

Library version

'1.12.0'
REVISION =

VCS revision

%q$Revision: 1b4652c824aa $
COMMON_LDAP_CONF_PATHS =

Common paths for ldap.conf

%w[
  ./ldaprc
  ~/.ldaprc
  ~/ldaprc
  /etc/ldap/ldap.conf
  /etc/openldap/ldap.conf
  /etc/ldap.conf
  /usr/local/etc/openldap/ldap.conf
  /usr/local/etc/ldap.conf
  /opt/local/etc/openldap/ldap.conf
  /opt/local/etc/ldap.conf
]

Constants included from Constants

Constants::CONTROL_NAMES, Constants::CONTROL_OIDS, Constants::EXTENSION_NAMES, Constants::EXTENSION_OIDS, Constants::FEATURE_NAMES, Constants::FEATURE_OIDS, Constants::MINIMAL_OPERATIONAL_ATTRIBUTES, Constants::SCOPE, Constants::SCOPE_NAME

Class Method Summary collapse

Class Method Details

.directory(*args) ⇒ Object

:call-seq:

Treequel.directory( uri )
Treequel.directory( options )

Create a Treequel::Directory object, either from an LDAP URL or a Hash of connection options. The valid options are:

:host

The LDAP host to connect to; default is ‘localhost’.

:port

The port number to connect to; defaults to LDAP::LDAP_PORT.

:connect_type

The type of connection to establish; :tls, :ssl, or :plain. Defaults to :tls.

:base_dn

The base DN of the directory.

:bind_dn

The DN of the user to bind as.

:pass

The password to use when binding.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/treequel.rb', line 92

def self::directory( *args )
  options = {}

  args.each do |arg|
    case arg
    when String, URI
      options.merge!( self.make_options_from_uri(arg) )
    when Hash
      options.merge!( arg )
    else
      raise ArgumentError, "unknown directory option %p: expected URL or Hash" % [ arg ]
    end
  end

  return Treequel::Directory.new( options )
end

.directory_from_config(configfile = nil) ⇒ Object

Read the configuration from the specified configfile and/or values in ENV and return a Treequel::Directory for the resulting configuration. Supports OpenLDAP and nss-style configuration-file directives, and honors the various OpenLDAP environment variables; see ldap.conf(5) for details.



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/treequel.rb', line 114

def self::directory_from_config( configfile=nil )
  configfile ||= self.find_configfile or
    raise ArgumentError, "No configfile specified, and no defaults present."

  # Read options from ENV and the config file
  fileopts    = self.read_opts_from_config( configfile )
  envopts     = self.read_opts_from_environment

  # Now merge all the options together with env > file > default
  options = Treequel::Directory::DEFAULT_OPTIONS.merge( fileopts.merge(envopts) )

  return Treequel::Directory.new( options )
end

.find_configfileObject

Find a valid ldap.conf config file by first looking in the LDAPCONF and LDAPRC environment variables, then searching the list of default paths in Treequel::COMMON_LDAP_CONF_PATHS.



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/treequel.rb', line 158

def self::find_configfile
  # LDAPCONF may be set to the path of a configuration file. This path can
  # be absolute or relative to the current working directory.
  if configfile = ENV['LDAPCONF']
    Treequel.log.info "Using LDAPCONF environment variable for path to ldap.conf"
    configpath = Pathname( configfile ).expand_path
    raise "Config file #{configfile}, specified in the LDAPCONF environment variable, " +
      "does not exist or isn't readable." unless configpath.readable?
    return configpath

  # The LDAPRC, if defined, should be the basename of a file in the current working
  # directory or in the user's home directory.
  elsif rcname = ENV['LDAPRC']
    Treequel.log.info "Using LDAPRC environment variable for path to ldap.conf"
    rcpath = Pathname( rcname ).expand_path
    return rcpath if rcpath.readable?
    rcpath = Pathname( "~" ).expand_path + rcname
    return rcpath if rcpath.readable?

    raise "Config file '#{rcname}', specified in the LDAPRC environment variable, does not " +
      "exist or isn't readable."
  else
    Treequel.log.info "Searching common paths for ldap.conf"
    return COMMON_LDAP_CONF_PATHS.collect {|path| Pathname(path) }.
      find {|path| path.readable? }
  end
end

.make_options_from_uri(uri) ⇒ Object

Make an options hash suitable for passing to Treequel::Directory.new from the given uri.

Raises:

  • (ArgumentError)


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/treequel.rb', line 131

def self::make_options_from_uri( uri )
  uri = URI( uri ) unless uri.is_a?( URI )
  raise ArgumentError, "not an LDAP URL: %p" % [ uri ] unless
    uri.scheme =~ /ldaps?/
  options = {}

  # Use either the scheme or the port from the URI to set the port
  if uri.port
    options[:port] = uri.port
  elsif uri.scheme == 'ldaps'
    options[:port] = LDAP::LDAPS_PORT
  end

  # Set the connection type if the scheme dictates it
  options[:connect_type] = :ssl if uri.scheme == 'ldaps'

  options[:host]    = uri.host if uri.host
  options[:base_dn] = uri.dn unless uri.dn.nil? || uri.dn.empty?
  options[:bind_dn] = uri.user if uri.user
  options[:pass]    = uri.password if uri.password

  return options
end

.read_opts_from_config(configfile) ⇒ Object

Read the ldap.conf-style configuration from configfile and return it as a Hash suitable for passing to Treequel::Directory.new.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/treequel.rb', line 189

def self::read_opts_from_config( configfile )
  Treequel.log.info "Reading config options from %s..." % [ configfile ]
  opts = {}

  linecount = 0
  IO.foreach( configfile ) do |line|
    Treequel.log.debug "  line: %p" % [ line ]
    linecount += 1
    case line

    # URI <ldap[si]://[name[:port]] ...>
    # :TODO: Support multiple URIs somehow?
    when /^\s*URI\s+(\S+)/i
      Treequel.log.debug "  setting options from a URI: %p" % [ line ]
      uriopts = self.make_options_from_uri( $1 )
      opts.merge!( uriopts )

    # BASE <base>
    when /^\s*BASE\s+(\S+)/i
      Treequel.log.debug "  setting default base DN: %p" % [ line ]
      opts[:base_dn] = $1

    # BINDDN <dn>
    when /^\s*BINDDN\s+(\S+)/i
      Treequel.log.debug "  setting bind DN: %p" % [ line ]
      opts[:bind_dn] = $1

    # bindpw <bindpw> (ldap_nss only)
    when /^\s*bindpw\s+(\S+)/i
      Treequel.log.debug "  setting bind password from line %s" % [ linecount ]
      opts[:pass] = $1

    # HOST <name[:port] ...>
    when /^\s*HOST\s+(\S+)/i
      Treequel.log.debug "  setting host: %p" % [ line ]
      opts[:host] = $1

    # PORT <port>
    when /^\s*PORT\s+(\S+)/i
      Treequel.log.debug "  setting port: %p" % [ line ]
      opts[:port] = $1.to_i

    # SSL <on|off|start_tls>
    when /^\s*SSL\s+(\S+)/i
      mode = $1.downcase
      case mode
      when 'on'
        Treequel.log.debug "  enabling plain SSL: %p" % [ line ]
        opts[:port] = 636
        opts[:connect_type] = :ssl
      when 'off'
        Treequel.log.debug "  disabling SSL: %p" % [ line ]
        opts[:port] = 389
        opts[:connect_type] = :plain
      when 'start_tls'
        Treequel.log.debug "  enabling TLS: %p" % [ line ]
        opts[:port] = 389
        opts[:connect_type] = :tls
      else
        Treequel.log.error "Unknown 'ssl' setting %p in %s line %d" %
          [ mode, configfile, linecount ]
      end

    end
  end

  return opts
end

.read_opts_from_environmentObject

Read OpenLDAP-style connection options from ENV and return them as a Hash suitable for passing to Treequel::Directory.new.



261
262
263
264
265
266
267
268
269
270
271
# File 'lib/treequel.rb', line 261

def self::read_opts_from_environment
  opts = {}

  opts.merge!( self.make_options_from_uri(ENV['LDAPURI']) ) if ENV['LDAPURI']
  opts[:host]    = ENV['LDAPHOST']      if ENV['LDAPHOST']
  opts[:port]    = ENV['LDAPPORT'].to_i if ENV['LDAPPORT']
  opts[:bind_dn] = ENV['LDAPBINDDN']    if ENV['LDAPBINDDN']
  opts[:base_dn] = ENV['LDAPBASE']      if ENV['LDAPBASE']

  return opts
end

.reset_loggerObject

Reset the logger associated with Treequel. Backward-compatibility method.



275
276
277
278
279
280
# File 'lib/treequel.rb', line 275

def self::reset_logger
  Treequel.logger = Treequel.default_logger
  Treequel.logger.formatter = nil
  Treequel.logger.output_to( $stderr )
  Treequel.logger.level = :fatal
end

.using_default_logger?Boolean

Returns true if the current logger for Treequel is the default one. Backward-compatibility method.

Returns:

  • (Boolean)


285
286
287
# File 'lib/treequel.rb', line 285

def self::using_default_logger?
  return Loggability[ Treequel ] == Treequel.default_logger
end

.version_string(include_buildnum = false) ⇒ Object

Get the Treequel version.



61
62
63
64
65
# File 'lib/treequel.rb', line 61

def self::version_string( include_buildnum=false )
  vstring = "%s %s" % [ self.name, VERSION ]
  vstring << " (build %s)" % [ REVISION[/: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
  return vstring
end