lib/net/ldap.rb in net-ldap-0.13.0 vs lib/net/ldap.rb in net-ldap-0.14.0
- old
+ new
@@ -262,18 +262,18 @@
include Net::LDAP::Instrumentation
SearchScope_BaseObject = 0
SearchScope_SingleLevel = 1
SearchScope_WholeSubtree = 2
- SearchScopes = [ SearchScope_BaseObject, SearchScope_SingleLevel,
- SearchScope_WholeSubtree ]
+ SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel,
+ SearchScope_WholeSubtree]
DerefAliases_Never = 0
DerefAliases_Search = 1
DerefAliases_Find = 2
DerefAliases_Always = 3
- DerefAliasesArray = [ DerefAliases_Never, DerefAliases_Search, DerefAliases_Find, DerefAliases_Always ]
+ DerefAliasesArray = [DerefAliases_Never, DerefAliases_Search, DerefAliases_Find, DerefAliases_Always]
primitive = { 2 => :null } # UnbindRequest body
constructed = {
0 => :array, # BindRequest
1 => :array, # BindResponse
@@ -321,20 +321,28 @@
context_specific = {
:primitive => primitive,
:constructed => constructed,
}
+ universal = {
+ constructed: {
+ 107 => :array, #ExtendedResponse (PasswdModifyResponseValue)
+ },
+ }
+
AsnSyntax = Net::BER.compile_syntax(:application => application,
+ :universal => universal,
:context_specific => context_specific)
DefaultHost = "127.0.0.1"
DefaultPort = 389
DefaultAuth = { :method => :anonymous }
DefaultTreebase = "dc=com"
DefaultForceNoPage = false
- StartTlsOid = "1.3.6.1.4.1.1466.20037"
+ StartTlsOid = '1.3.6.1.4.1.1466.20037'
+ PasswdModifyOid = '1.3.6.1.4.1.4203.1.11.1'
# https://tools.ietf.org/html/rfc4511#section-4.1.9
# https://tools.ietf.org/html/rfc4511#appendix-A
ResultCodeSuccess = 0
ResultCodeOperationsError = 1
@@ -379,18 +387,18 @@
ResultCodesNonError = [
ResultCodeSuccess,
ResultCodeCompareFalse,
ResultCodeCompareTrue,
ResultCodeReferral,
- ResultCodeSaslBindInProgress
+ ResultCodeSaslBindInProgress,
]
# nonstandard list of "successful" result codes for searches
ResultCodesSearchSuccess = [
ResultCodeSuccess,
ResultCodeTimeLimitExceeded,
- ResultCodeSizeLimitExceeded
+ ResultCodeSizeLimitExceeded,
]
# map of result code to human message
ResultStrings = {
ResultCodeSuccess => "Success",
@@ -428,11 +436,11 @@
ResultCodeNotAllowedOnNonLeaf => "Not Allowed On Non-Leaf",
ResultCodeNotAllowedOnRDN => "Not Allowed On RDN",
ResultCodeEntryAlreadyExists => "Entry Already Exists",
ResultCodeObjectClassModsProhibited => "ObjectClass Modifications Prohibited",
ResultCodeAffectsMultipleDSAs => "Affects Multiple DSAs",
- ResultCodeOther => "Other"
+ ResultCodeOther => "Other",
}
module LDAPControls
PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
SORT_REQUEST = "1.2.840.113556.1.4.473"
@@ -529,11 +537,11 @@
@hosts = args[:hosts]
@verbose = false # Make this configurable with a switch on the class.
@auth = args[:auth] || DefaultAuth
@base = args[:base] || DefaultTreebase
@force_no_page = args[:force_no_page] || DefaultForceNoPage
- @encryption = args[:encryption] # may be nil
+ @encryption = normalize_encryption(args[:encryption]) # may be nil
@connect_timeout = args[:connect_timeout]
if pr = @auth[:password] and pr.respond_to?(:call)
@auth[:password] = pr.call
end
@@ -581,11 +589,11 @@
def authenticate(username, password)
password = password.call if password.respond_to?(:call)
@auth = {
:method => :simple,
:username => username,
- :password => password
+ :password => password,
}
end
alias_method :auth, :authenticate
# Convenience method to specify encryption characteristics for connections
@@ -599,17 +607,11 @@
# This method is deprecated.
#
def encryption(args)
warn "Deprecation warning: please give :encryption option as a Hash to Net::LDAP.new"
return if args.nil?
- return @encryption = args if args.is_a? Hash
-
- case method = args.to_sym
- when :simple_tls, :start_tls
- args = { :method => method, :tls_options => {} }
- end
- @encryption = args
+ @encryption = normalize_encryption(args)
end
# #open takes the same parameters as #new. #open makes a network
# connection to the LDAP server and then passes a newly-created Net::LDAP
# object to the caller-supplied block. Within the block, you can call any
@@ -649,12 +651,15 @@
# Modified the implementation, 20Mar07. We might get a hash of LDAP
# response codes instead of a simple numeric code.
#++
def get_operation_result
result = @result
- result = result.result if result.is_a?(Net::LDAP::PDU)
os = OpenStruct.new
+ if result.is_a?(Net::LDAP::PDU)
+ os.extended_response = result.extended_response
+ result = result.result
+ end
if result.is_a?(Hash)
# We might get a hash of LDAP response codes instead of a simple
# numeric code.
os.code = (result[:resultCode] || "").to_i
os.error_message = result[:errorMessage]
@@ -762,14 +767,14 @@
return_result_set = args[:return_result] != false
result_set = return_result_set ? [] : nil
instrument "search.net_ldap", args do |payload|
@result = use_connection(args) do |conn|
- conn.search(args) { |entry|
+ conn.search(args) do |entry|
result_set << entry if result_set
yield entry if block_given?
- }
+ end
end
if return_result_set
unless @result.nil?
if ResultCodesSearchSuccess.include?(@result.result_code)
@@ -904,19 +909,19 @@
# else
# puts "Authentication FAILED."
# end
def bind_as(args = {})
result = false
- open { |me|
+ open do |me|
rs = search args
if rs and rs.first and dn = rs.first.dn
password = args[:password]
password = password.call if password.respond_to?(:call)
result = rs if bind(:method => :simple, :username => dn,
:password => password)
end
- }
+ end
result
end
# Adds a new entry to the remote LDAP server.
# Supported arguments:
@@ -1039,10 +1044,48 @@
end
@result.success?
end
end
+ # Password Modify
+ #
+ # Change existing password:
+ #
+ # dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
+ # auth = {
+ # method: :simple,
+ # username: dn,
+ # password: 'passworD1'
+ # }
+ # ldap.password_modify(dn: dn,
+ # auth: auth,
+ # old_password: 'passworD1',
+ # new_password: 'passworD2')
+ #
+ # Or get the LDAP server to generate a password for you:
+ #
+ # dn = 'uid=modify-password-user1,ou=People,dc=rubyldap,dc=com'
+ # auth = {
+ # method: :simple,
+ # username: dn,
+ # password: 'passworD1'
+ # }
+ # ldap.password_modify(dn: dn,
+ # auth: auth,
+ # old_password: 'passworD1')
+ #
+ # ldap.get_operation_result.extended_response[0][0] #=> 'VtcgGf/G'
+ #
+ def password_modify(args)
+ instrument "modify_password.net_ldap", args do |payload|
+ @result = use_connection(args) do |conn|
+ conn.password_modify(args)
+ end
+ @result.success?
+ end
+ end
+
# Add a value to an attribute. Takes the full DN of the entry to modify,
# the name (Symbol or String) of the attribute, and the value (String or
# Array). If the attribute does not exist (and there are no schema
# violations), #add_attribute will create it with the caller-specified
# values. If the attribute already exists (and there are no schema
@@ -1157,11 +1200,11 @@
:supportedCapabilities,
:supportedControl,
:supportedExtension,
:supportedFeatures,
:supportedLdapVersion,
- :supportedSASLMechanisms
+ :supportedSASLMechanisms,
])
(rs and rs.first) or Net::LDAP::Entry.new
end
# Return the root Subschema record from the LDAP server as a
@@ -1224,10 +1267,15 @@
inspected = super
inspected.gsub! @auth[:password], "*******" if @auth[:password]
inspected
end
+ # Internal: Set @open_connection for testing
+ def connection=(connection)
+ @open_connection = connection
+ end
+
private
# Yields an open connection if there is one, otherwise establishes a new
# connection, binds, and yields it. If binding fails, it will return the
# result from that, and :use_connection: will not yield at all. If not
@@ -1249,20 +1297,37 @@
end
end
# Establish a new connection to the LDAP server
def new_connection
- Net::LDAP::Connection.new \
+ connection = Net::LDAP::Connection.new \
:host => @host,
:port => @port,
:hosts => @hosts,
:encryption => @encryption,
:instrumentation_service => @instrumentation_service,
:connect_timeout => @connect_timeout
+
+ # Force connect to see if there's a connection error
+ connection.socket
+ connection
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Net::LDAP::ConnectionRefusedError => e
@result = {
:resultCode => 52,
- :errorMessage => ResultStrings[ResultCodeUnavailable]
+ :errorMessage => ResultStrings[ResultCodeUnavailable],
}
raise e
end
+
+ # Normalize encryption parameter the constructor accepts, expands a few
+ # convenience symbols into recognizable hashes
+ def normalize_encryption(args)
+ return if args.nil?
+ return args if args.is_a? Hash
+
+ case method = args.to_sym
+ when :simple_tls, :start_tls
+ { :method => method, :tls_options => {} }
+ end
+ end
+
end # class LDAP