Skip to content

Commit

Permalink
Merge pull request #28 from bskinny/introduce-bind-to-api
Browse files Browse the repository at this point in the history
Introduce bind function based on @yogthos PR
  • Loading branch information
bskinny authored Nov 23, 2020
2 parents 2b5a832 + 6975185 commit 69aae35
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 142 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ pom.xml.asc
.idea
clj-ldap.iml
test-resources/access
test-resources/access.lck
test-resources/access.*
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [0.0.17]
This release adds the following:
- A `bind` function which behaves similarly to `bind?` except that it throws `LDAPException` on failure. Thanks to @yogthos and @sumbach.
- A bump of the ldap-sdk to 5.1.1.

## [0.0.16]
This release adds the following:
- A lazy-seq returned by `search-all-results` using SimplePagedResults control. Thanks to @jindrichmynarz.
Expand Down
49 changes: 43 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

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)
```clojure
:dependencies [[org.clojars.pntblnk/clj-ldap "0.0.16"]]
:dependencies [[org.clojars.pntblnk/clj-ldap "0.0.17"]]
```
# Example

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

## connect [options]

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).
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).
Options is a map with the following entries:

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

## bind? [connection bind-dn password] [connection-pool bind-dn password]
## bind [connection bind-dn password] [connection-pool bind-dn password]

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

(let [conn (ldap/get-connection pool)
user-dn "uid=user.1,ou=people,dc=example,dc=com"
user-password "password"]
(try
;; Passed a connection, a successful authentication changes the authorization identity of the connection
(when (ldap/bind? conn user-dn user-password)
(ldap/modify conn user-dn {:replace {:description "On sabatical"}}))
(finally (ldap/release-connection pool conn))))
```
Performs a bind operation using the provided connection, bindDN and
password. Returns true if successful.
password. Returns true if successful and false otherwise.

When an LDAP connection object is used as the connection argument the
bind? function will attempt to change the identity of that connection
to that of the provided DN. Subsequent operations on that connection
will be done using the bound identity.

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

Throws a [LDAPException](http://www.unboundid.com/products/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/LDAPException.html) on unsuccessful authentication or other error.

## bind? [connection bind-dn password] [connection-pool bind-dn password]

Usage:
```clojure
;; Authenticate user with given dn but the pool retains the previous identity on the connection
(ldap/bind? pool "cn=dude,ou=people,dc=example,dc=com" "somepass")

(let [conn (ldap/get-connection pool)
user-dn "uid=user.1,ou=people,dc=example,dc=com"
user-password "password"]
(try
;; Passed a connection, a successful authentication changes the authorization identity of the connection
(when (ldap/bind? conn user-dn user-password)
(ldap/modify conn user-dn {:replace {:description "On sabatical"}}))
(finally (ldap/release-connection pool conn))))
```
Performs a bind operation using the provided connection, bindDN and
password. Returns true if successful and false otherwise.

When an LDAP connection object is used as the connection argument the
bind? function will attempt to change the identity of that connection
to that of the provided DN. Subsequent operations on that connection
will be done using the bound identity.

If an LDAP connection pool object is passed as the connection argument
the bind attempt will have no side-effects, leaving the state of the
underlying connections unchanged.

## get [connection dn] [connection dn attributes]

If successful, returns a map containing the entry for the given DN.
Expand Down
4 changes: 2 additions & 2 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
(defproject org.clojars.pntblnk/clj-ldap "0.0.16"
(defproject org.clojars.pntblnk/clj-ldap "0.0.17"
:description "Clojure ldap client."
:url "https://github.com/pauldorman/clj-ldap"
:dependencies [[org.clojure/clojure "1.8.0"]
[com.unboundid/unboundid-ldapsdk "4.0.4"]]
[com.unboundid/unboundid-ldapsdk "5.1.1"]]
:profiles {:test {:dependencies [[lein-clojars "0.9.1"]]}}
:aot [clj-ldap.client]
:license {:name "Eclipse Public License - v 1.0"
Expand Down
69 changes: 49 additions & 20 deletions src/clj_ldap/client.clj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
Control
StartTLSPostConnectProcessor
CompareRequest
CompareResult])
CompareResult BindResult])
(:import [com.unboundid.ldap.sdk.extensions
PasswordModifyExtendedRequest
PasswordModifyExtendedResult
Expand Down Expand Up @@ -93,7 +93,7 @@
adding the DN. We pass along the byte-valued collection to properly
return binary data."
([byte-valued]
(entry-as-map byte-valued true))
(entry-as-map byte-valued true))
([byte-valued dn?]
(fn [entry]
(let [attrs (seq (.getAttributes entry))]
Expand All @@ -109,10 +109,10 @@
(condp instance? control
PreReadResponseControl
(update-in m [:pre-read] merge ((entry-as-map [] false)
(.getEntry control)))
(.getEntry control)))
PostReadResponseControl
(update-in m [:post-read] merge ((entry-as-map [] false)
(.getEntry control)))
(.getEntry control)))
m))

(defn- add-response-controls
Expand Down Expand Up @@ -192,6 +192,17 @@
conn)
:else (LDAPConnection. opt host ldap-port))))

(defn- bind-based-on-connection
"Common bind approach for the api:
connection represents pool then authenticate and revert bind association on pool connection, or
connection is plain then authenticate and remain bound.
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
connection context but since we make this the default behavior of pool binds it is likely unnecessary."
[connection bind-dn password]
(if (instance? LDAPConnectionPool connection)
(.bindAndRevertAuthentication connection bind-dn password nil)
(.bind connection bind-dn password)))

(defn- bind-request
"Returns a BindRequest object"
[{:keys [bind-dn password]}]
Expand Down Expand Up @@ -462,8 +473,8 @@
[(createServerSideSort server-sort)]
[])
proxied-auth-control (if (not-nil? proxied-auth)
[(ProxiedAuthorizationV2RequestControl. proxied-auth)]
[])]
[(ProxiedAuthorizationV2RequestControl. proxied-auth)]
[])]
(merge original {:base base
:scope (get-scope scope)
:filter filter
Expand Down Expand Up @@ -524,23 +535,41 @@
[pool connection]
(.releaseAndReAuthenticateConnection pool connection))

(defn bind
"Performs a bind operation using the provided connection or pool, bindDN and
password. If the bind is unsuccessful LDAPException is thrown. Otherwise, a
map is returned with :code, :name, and optional :diagnostic-message keys.
The :diagnostic-message might contain password expiration warnings, for instance.
When an LDAP connection object is used as the connection argument the
bind function will attempt to change the identity of that connection
to that of the provided DN. Subsequent operations on that connection
will be done using the bound identity.
If an LDAP connection pool object is passed as the connection argument
the bind attempt will have no side-effects, leaving the state of the
underlying connections unchanged."
[connection bind-dn password]
(let [^BindResult r (bind-based-on-connection connection bind-dn password)]
(merge (ldap-result r)
(when-let [diagnostic-message (.getDiagnosticMessage r)]
{:diagnostic-message diagnostic-message}))))

(defn bind?
"Performs a bind operation using the provided connection, bindDN and
password. Returns true if successful.
password. Returns true if successful and false otherwise.
When an LDAP connection object is used as the connection argument the
bind? function will attempt to change the identity of that connection
to that of the provided DN. Subsequent operations on that connection
will be done using the bound identity.
When an LDAP connection object is used as the connection argument the
bind? function will attempt to change the identity of that connection
to that of the provided DN. Subsequent operations on that connection
will be done using the bound identity.
If an LDAP connection pool object is passed as the connection argument
the bind attempt will have no side-effects, leaving the state of the
underlying connections unchanged."
If an LDAP connection pool object is passed as the connection argument
the bind attempt will have no side-effects, leaving the state of the
underlying connections unchanged."
[connection bind-dn password]
(try
(let [r (if (instance? LDAPConnectionPool connection)
(.bindAndRevertAuthentication connection bind-dn password nil)
(.bind connection bind-dn password))]
(let [r (bind-based-on-connection connection bind-dn password)]
(= ResultCode/SUCCESS (.getResultCode r)))
(catch Exception _ false)))

Expand Down Expand Up @@ -583,7 +612,7 @@ underlying connections unchanged."
"Adds an entry to the connected ldap server. The entry is assumed to be
a map. The options map supports control :proxied-auth."
([connection dn entry]
(add connection dn entry nil))
(add connection dn entry nil))
([connection dn entry options]
(let [entry-obj (Entry. dn)]
(set-entry-map! entry-obj entry)
Expand Down Expand Up @@ -629,7 +658,7 @@ Where :add adds an attribute value, :delete deletes an attribute value and
The entries :pre-read and :post-read specify attributes that have be read and
returned either before or after the modifications have taken place."
([connection dn modifications]
(modify connection dn modifications nil))
(modify connection dn modifications nil))
([connection dn modifications options]
(let [modify-obj (get-modify-request dn modifications)]
(when options
Expand Down Expand Up @@ -662,7 +691,7 @@ returned either before or after the modifications have taken place."
RDN value from the target entry. The options map supports pre/post-read
and proxied-auth controls."
([connection dn new-rdn delete-old-rdn]
(modify-rdn connection dn new-rdn delete-old-rdn nil))
(modify-rdn connection dn new-rdn delete-old-rdn nil))
([connection dn new-rdn delete-old-rdn options]
(let [request (ModifyDNRequest. dn new-rdn delete-old-rdn)]
(when options
Expand Down
Binary file modified test-resources/server.keystore
Binary file not shown.
Loading

0 comments on commit 69aae35

Please sign in to comment.