Skip to content

Commit 69aae35

Browse files
authored
Merge pull request #28 from bskinny/introduce-bind-to-api
Introduce bind function based on @yogthos PR
2 parents 2b5a832 + 6975185 commit 69aae35

File tree

8 files changed

+219
-142
lines changed

8 files changed

+219
-142
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ pom.xml.asc
1313
.idea
1414
clj-ldap.iml
1515
test-resources/access
16-
test-resources/access.lck
16+
test-resources/access.*

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [0.0.17]
6+
This release adds the following:
7+
- A `bind` function which behaves similarly to `bind?` except that it throws `LDAPException` on failure. Thanks to @yogthos and @sumbach.
8+
- A bump of the ldap-sdk to 5.1.1.
9+
510
## [0.0.16]
611
This release adds the following:
712
- A lazy-seq returned by `search-all-results` using SimplePagedResults control. Thanks to @jindrichmynarz.

README.md

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
clj-ldap is a thin layer on the [unboundid sdk](http://www.unboundid.com/products/ldap-sdk/) and allows clojure programs to talk to ldap servers. This library is available on [clojars.org](http://clojars.org/search?q=clj-ldap)
55
```clojure
6-
:dependencies [[org.clojars.pntblnk/clj-ldap "0.0.16"]]
6+
:dependencies [[org.clojars.pntblnk/clj-ldap "0.0.17"]]
77
```
88
# Example
99

@@ -30,7 +30,7 @@ clj-ldap is a thin layer on the [unboundid sdk](http://www.unboundid.com/product
3030

3131
## connect [options]
3232

33-
Connects to an ldap server and returns a, thread safe, [LDAPConnectionPool](http://www.unboundid.com/products/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/LDAPConnectionPool.html).
33+
Connects to an ldap server and returns a thread safe [LDAPConnectionPool](http://www.unboundid.com/products/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/LDAPConnectionPool.html).
3434
Options is a map with the following entries:
3535

3636
:host Either a string in the form "address:port"
@@ -83,32 +83,69 @@ a connection is expected. Using a pool in this manner aleviates the caller from
8383
release connections. It will still be necessary to get and release a connection if a single
8484
connection is needed to process a sequence of operations. See the following bind? example.
8585

86-
## bind? [connection bind-dn password] [connection-pool bind-dn password]
86+
## bind [connection bind-dn password] [connection-pool bind-dn password]
8787

8888
Usage:
8989
```clojure
90-
(ldap/bind? pool "cn=dude,ou=people,dc=example,dc=com" "somepass")
90+
;; Authenticate user with given dn but the pool retains the previous identity on the connection
91+
(try
92+
(ldap/bind pool "cn=dude,ou=people,dc=example,dc=com" "somepass")
93+
(catch LDAPException e
94+
(if (= 49 (.intValue (.getResultCode e)))
95+
(prn "Password invalid")
96+
(throw e))))
9197

9298
(let [conn (ldap/get-connection pool)
9399
user-dn "uid=user.1,ou=people,dc=example,dc=com"
94100
user-password "password"]
95101
(try
102+
;; Passed a connection, a successful authentication changes the authorization identity of the connection
96103
(when (ldap/bind? conn user-dn user-password)
97104
(ldap/modify conn user-dn {:replace {:description "On sabatical"}}))
98105
(finally (ldap/release-connection pool conn))))
99106
```
100107
Performs a bind operation using the provided connection, bindDN and
101-
password. Returns true if successful.
108+
password. Returns true if successful and false otherwise.
109+
110+
When an LDAP connection object is used as the connection argument the
111+
bind? function will attempt to change the identity of that connection
112+
to that of the provided DN. Subsequent operations on that connection
113+
will be done using the bound identity.
102114

103-
If an LDAPConnectionPool object is passed as the connection argument
115+
If an LDAP connection pool object is passed as the connection argument
104116
the bind attempt will have no side-effects, leaving the state of the
105117
underlying connections unchanged.
106118

119+
Throws a [LDAPException](http://www.unboundid.com/products/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/LDAPException.html) on unsuccessful authentication or other error.
120+
121+
## bind? [connection bind-dn password] [connection-pool bind-dn password]
122+
123+
Usage:
124+
```clojure
125+
;; Authenticate user with given dn but the pool retains the previous identity on the connection
126+
(ldap/bind? pool "cn=dude,ou=people,dc=example,dc=com" "somepass")
127+
128+
(let [conn (ldap/get-connection pool)
129+
user-dn "uid=user.1,ou=people,dc=example,dc=com"
130+
user-password "password"]
131+
(try
132+
;; Passed a connection, a successful authentication changes the authorization identity of the connection
133+
(when (ldap/bind? conn user-dn user-password)
134+
(ldap/modify conn user-dn {:replace {:description "On sabatical"}}))
135+
(finally (ldap/release-connection pool conn))))
136+
```
137+
Performs a bind operation using the provided connection, bindDN and
138+
password. Returns true if successful and false otherwise.
139+
107140
When an LDAP connection object is used as the connection argument the
108141
bind? function will attempt to change the identity of that connection
109142
to that of the provided DN. Subsequent operations on that connection
110143
will be done using the bound identity.
111144

145+
If an LDAP connection pool object is passed as the connection argument
146+
the bind attempt will have no side-effects, leaving the state of the
147+
underlying connections unchanged.
148+
112149
## get [connection dn] [connection dn attributes]
113150

114151
If successful, returns a map containing the entry for the given DN.

project.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
(defproject org.clojars.pntblnk/clj-ldap "0.0.16"
1+
(defproject org.clojars.pntblnk/clj-ldap "0.0.17"
22
:description "Clojure ldap client."
33
:url "https://github.com/pauldorman/clj-ldap"
44
:dependencies [[org.clojure/clojure "1.8.0"]
5-
[com.unboundid/unboundid-ldapsdk "4.0.4"]]
5+
[com.unboundid/unboundid-ldapsdk "5.1.1"]]
66
:profiles {:test {:dependencies [[lein-clojars "0.9.1"]]}}
77
:aot [clj-ldap.client]
88
:license {:name "Eclipse Public License - v 1.0"

src/clj_ldap/client.clj

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
Control
2929
StartTLSPostConnectProcessor
3030
CompareRequest
31-
CompareResult])
31+
CompareResult BindResult])
3232
(:import [com.unboundid.ldap.sdk.extensions
3333
PasswordModifyExtendedRequest
3434
PasswordModifyExtendedResult
@@ -93,7 +93,7 @@
9393
adding the DN. We pass along the byte-valued collection to properly
9494
return binary data."
9595
([byte-valued]
96-
(entry-as-map byte-valued true))
96+
(entry-as-map byte-valued true))
9797
([byte-valued dn?]
9898
(fn [entry]
9999
(let [attrs (seq (.getAttributes entry))]
@@ -109,10 +109,10 @@
109109
(condp instance? control
110110
PreReadResponseControl
111111
(update-in m [:pre-read] merge ((entry-as-map [] false)
112-
(.getEntry control)))
112+
(.getEntry control)))
113113
PostReadResponseControl
114114
(update-in m [:post-read] merge ((entry-as-map [] false)
115-
(.getEntry control)))
115+
(.getEntry control)))
116116
m))
117117

118118
(defn- add-response-controls
@@ -192,6 +192,17 @@
192192
conn)
193193
:else (LDAPConnection. opt host ldap-port))))
194194

195+
(defn- bind-based-on-connection
196+
"Common bind approach for the api:
197+
connection represents pool then authenticate and revert bind association on pool connection, or
198+
connection is plain then authenticate and remain bound.
199+
Note: There is a retainIdentity control (1.3.6.1.4.1.30221.2.5.3) which might also be useful option in the plain
200+
connection context but since we make this the default behavior of pool binds it is likely unnecessary."
201+
[connection bind-dn password]
202+
(if (instance? LDAPConnectionPool connection)
203+
(.bindAndRevertAuthentication connection bind-dn password nil)
204+
(.bind connection bind-dn password)))
205+
195206
(defn- bind-request
196207
"Returns a BindRequest object"
197208
[{:keys [bind-dn password]}]
@@ -462,8 +473,8 @@
462473
[(createServerSideSort server-sort)]
463474
[])
464475
proxied-auth-control (if (not-nil? proxied-auth)
465-
[(ProxiedAuthorizationV2RequestControl. proxied-auth)]
466-
[])]
476+
[(ProxiedAuthorizationV2RequestControl. proxied-auth)]
477+
[])]
467478
(merge original {:base base
468479
:scope (get-scope scope)
469480
:filter filter
@@ -524,23 +535,41 @@
524535
[pool connection]
525536
(.releaseAndReAuthenticateConnection pool connection))
526537

538+
(defn bind
539+
"Performs a bind operation using the provided connection or pool, bindDN and
540+
password. If the bind is unsuccessful LDAPException is thrown. Otherwise, a
541+
map is returned with :code, :name, and optional :diagnostic-message keys.
542+
The :diagnostic-message might contain password expiration warnings, for instance.
543+
544+
When an LDAP connection object is used as the connection argument the
545+
bind function will attempt to change the identity of that connection
546+
to that of the provided DN. Subsequent operations on that connection
547+
will be done using the bound identity.
548+
549+
If an LDAP connection pool object is passed as the connection argument
550+
the bind attempt will have no side-effects, leaving the state of the
551+
underlying connections unchanged."
552+
[connection bind-dn password]
553+
(let [^BindResult r (bind-based-on-connection connection bind-dn password)]
554+
(merge (ldap-result r)
555+
(when-let [diagnostic-message (.getDiagnosticMessage r)]
556+
{:diagnostic-message diagnostic-message}))))
557+
527558
(defn bind?
528559
"Performs a bind operation using the provided connection, bindDN and
529-
password. Returns true if successful.
560+
password. Returns true if successful and false otherwise.
530561
531-
When an LDAP connection object is used as the connection argument the
532-
bind? function will attempt to change the identity of that connection
533-
to that of the provided DN. Subsequent operations on that connection
534-
will be done using the bound identity.
562+
When an LDAP connection object is used as the connection argument the
563+
bind? function will attempt to change the identity of that connection
564+
to that of the provided DN. Subsequent operations on that connection
565+
will be done using the bound identity.
535566
536-
If an LDAP connection pool object is passed as the connection argument
537-
the bind attempt will have no side-effects, leaving the state of the
538-
underlying connections unchanged."
567+
If an LDAP connection pool object is passed as the connection argument
568+
the bind attempt will have no side-effects, leaving the state of the
569+
underlying connections unchanged."
539570
[connection bind-dn password]
540571
(try
541-
(let [r (if (instance? LDAPConnectionPool connection)
542-
(.bindAndRevertAuthentication connection bind-dn password nil)
543-
(.bind connection bind-dn password))]
572+
(let [r (bind-based-on-connection connection bind-dn password)]
544573
(= ResultCode/SUCCESS (.getResultCode r)))
545574
(catch Exception _ false)))
546575

@@ -583,7 +612,7 @@ underlying connections unchanged."
583612
"Adds an entry to the connected ldap server. The entry is assumed to be
584613
a map. The options map supports control :proxied-auth."
585614
([connection dn entry]
586-
(add connection dn entry nil))
615+
(add connection dn entry nil))
587616
([connection dn entry options]
588617
(let [entry-obj (Entry. dn)]
589618
(set-entry-map! entry-obj entry)
@@ -629,7 +658,7 @@ Where :add adds an attribute value, :delete deletes an attribute value and
629658
The entries :pre-read and :post-read specify attributes that have be read and
630659
returned either before or after the modifications have taken place."
631660
([connection dn modifications]
632-
(modify connection dn modifications nil))
661+
(modify connection dn modifications nil))
633662
([connection dn modifications options]
634663
(let [modify-obj (get-modify-request dn modifications)]
635664
(when options
@@ -662,7 +691,7 @@ returned either before or after the modifications have taken place."
662691
RDN value from the target entry. The options map supports pre/post-read
663692
and proxied-auth controls."
664693
([connection dn new-rdn delete-old-rdn]
665-
(modify-rdn connection dn new-rdn delete-old-rdn nil))
694+
(modify-rdn connection dn new-rdn delete-old-rdn nil))
666695
([connection dn new-rdn delete-old-rdn options]
667696
(let [request (ModifyDNRequest. dn new-rdn delete-old-rdn)]
668697
(when options

test-resources/server.keystore

1.27 KB
Binary file not shown.

0 commit comments

Comments
 (0)