Skip to content

Commit

Permalink
Fix the keycloak.user/user-id behavior with now an exact match #29
Browse files Browse the repository at this point in the history
  • Loading branch information
jgrodziski committed Sep 3, 2021
1 parent 6ef6be4 commit 32955ae
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 29 deletions.
1 change: 1 addition & 0 deletions src/keycloak/starter.clj
Expand Up @@ -324,6 +324,7 @@
:loginTheme "keycloak",
:accountTheme "keycloak"},
:login {:resetPasswordAllowed true, :bruteForceProtected true, :rememberMe true},
:admin-user {:username "admin" :first-name "John" :last-name "Doe" :email "admin@example.com"}
:smtp {:starttls true, :password "", :port 587, :auth true, :host "smtp.eu.mailgun.org", :replyTo "example", :from "admin@example.com", :user "postmaster@mg.example.com"},
:tokens {:ssoSessionIdleTimeoutRememberMe 172800, :ssoSessionMaxLifespanRememberMe 172800}},
:roles #{"org-admin" "example-admin" "group-admin" "api-consumer" "employee" "manager"},
Expand Down
54 changes: 39 additions & 15 deletions src/keycloak/user.clj
Expand Up @@ -58,18 +58,37 @@
(-> keycloak-client (.realm realm-name) (.users) (.search username first-name last-name email (int 0) (int 10)))
(catch javax.ws.rs.NotFoundException nfe nil))))

(defn- exact-match
([users attr]
(some (fn [user]
(when (or (= (.getUsername user) attr)
(= (.getFirstName user) attr)
(= (.getLastName user) attr)
(= (.getEmail user) attr)) user)) users))
([users username-in first-name-in last-name-in email-in]
(some (fn [user]
(when (and (= (.getUsername user) username-in)
(= (.getFirstName user) first-name-in)
(= (.getLastName user) last-name-in)
(= (.getEmail user) email-in)) user)) users)))

(defn user-id
"Return a user-id from either one of (username|first-name|last-name|email) attributes that match exactly or all of these attributes to match"
([^org.keycloak.admin.client.Keycloak keycloak-client realm-name user-attribute]
(let [search-result (search-user keycloak-client realm-name user-attribute)]
(if (and search-result (> (count search-result) 0))
(let [^org.keycloak.representations.idm.UserRepresentation user (first search-result)]
(.getId user))
(let [users (search-user keycloak-client realm-name user-attribute)]
(if (and users (> (count users) 0))
(let [^org.keycloak.representations.idm.UserRepresentation user (exact-match users user-attribute)]
(if user
(.getId user)
(do (info "user with attribute"user-attribute"not found in realm"realm-name) nil)))
(do (info "user with attribute"user-attribute"not found in realm"realm-name) nil))))
([^org.keycloak.admin.client.Keycloak keycloak-client realm-name username first-name last-name email]
(let [search-result (search-user keycloak-client realm-name username first-name last-name email)]
(if (and search-result (> (count search-result) 0))
(let [^org.keycloak.representations.idm.UserRepresentation user (first search-result)]
(.getId user))
(let [users (search-user keycloak-client realm-name username first-name last-name email)]
(if (and users (> (count users) 0))
(let [^org.keycloak.representations.idm.UserRepresentation user (exact-match users username first-name last-name email)]
(if user
(.getId user)
(do (info "user with attributes username:"username ",first-name" first-name ",last-name:" last-name ",email:" email "not found in realm"realm-name) nil)))
(do (info "user with attributes username:"username ",first-name" first-name ",last-name:" last-name ",email:" email "not found in realm"realm-name) nil)))))

(defn delete-user!
Expand Down Expand Up @@ -195,14 +214,16 @@
:as person} realm-roles client-roles]
(info "create user" username "in realm" realm-name"with realm roles"realm-roles"client roles"client-roles". If user already exists, delete it and re-create it.")
(let [username-exists? (not (nil? (user-id keycloak-client realm-name username)))
email-exists? (not (nil? (user-id keycloak-client realm-name email)))
_ (if username-exists? (do (delete-user! keycloak-client realm-name username) (Thread/sleep 100)))
_ (if email-exists? (do (delete-user! keycloak-client realm-name email) (Thread/sleep 100)))
email-exists? (not (nil? (user-id keycloak-client realm-name email)))
_ (if username-exists?
(do (delete-user! keycloak-client realm-name username) (Thread/sleep 100)))
_ (if email-exists?
(do (delete-user! keycloak-client realm-name email) (Thread/sleep 100)))
response (-> keycloak-client (.realm realm-name) (.users) (.create (user-for-creation person)))
user-id (extract-id response)
_ (when (response) (.close response))
_ (check-user-properly-created keycloak-client realm-name username email)]
(when realm-roles (add-realm-roles! keycloak-client realm-name username realm-roles))
user-id (extract-id response)]
(when response (.close response))
(check-user-properly-created keycloak-client realm-name username email)
(when realm-roles (add-realm-roles! keycloak-client realm-name username realm-roles))
(when client-roles (add-client-roles! keycloak-client realm-name username client-roles))
(if user-id
(get-user keycloak-client realm-name user-id)
Expand Down Expand Up @@ -232,6 +253,9 @@
(get-user keycloak-client realm-name user-id)
(get-user-by-username keycloak-client realm-name username))))

(defn username-exists? [^org.keycloak.admin.client.Keycloak keycloak-client realm-name username]
(not (nil? (user-id keycloak-client realm-name username))))

(defn create-or-update-user!
^org.keycloak.representations.idm.UserRepresentation [^org.keycloak.admin.client.Keycloak keycloak-client realm-name {:keys [username first-name last-name email password] :as person} realm-roles client-roles]
(let [_ (info "Create or update user" username "in realm" realm-name "with realm roles" realm-roles "client roles"client-roles)
Expand Down
76 changes: 62 additions & 14 deletions test/keycloak/user_test.clj
Expand Up @@ -5,6 +5,7 @@
[clojure.java.shell :as shell]

[testit.core :refer [fact facts => truthy falsey]]
[sc.api :as sc]

[keycloak.deployment :as deployment :refer [deployment client-conf deployment-for-realms verify extract]]
[keycloak.bean :as bean]
Expand All @@ -29,19 +30,57 @@
(def integration-test-conf (deployment/client-conf auth-server-url "master" "admin-cli"))
(def admin-client (deployment/keycloak-client integration-test-conf admin-login admin-password))

(def keycloak-deployment (deployment (client-conf
{:auth-server-url auth-server-url
:admin-realm "master"
:realm "electre-devmachine"
:admin-username "admin"
:admin-password "secretadmin"
:client-admin-cli "admin-cli"
:client-id "bo-backend"
:client-secret "bc8205af-c056-4be6-97e0-9edc8e2c0eb3"})))

(def fake-user {:last-name "Carter", :email "bobcarter@acme.org" :group "Example", :realm-roles ["employee" "manager" "example-admin"], :password "secretstuff", :username "testaccount", :first-name "Bob", :attributes {"org-ref" ["Example"]}, :in-subgroups ["IT"]})
(def fake-user {:last-name "Carter", :email "bobcarter@acme.org" :group "Example", :realm-roles ["employee" "manager" "example-admin"], :password "secretstuff", :username "bcarter", :first-name "Bob", :attributes {"org-ref" ["Example"]}, :in-subgroups ["IT"]})
(def fake-user-2 {:last-name "Reagan", :email "ronalreagan@acme.org" :group "Example", :realm-roles ["employee" "manager" "example-admin"], :password "secretstuff", :username "rreagan", :first-name "Ronald", :attributes {"org-ref" ["Example"]}, :in-subgroups ["IT"]})

(deftest ^:integration user-creation-test

(deftest ^:integration user-id-testing
(let [admin-client (deployment/keycloak-client integration-test-conf admin-login admin-password)]
(testing "realm creation "
(let [realm-name (str "test-realm-" (rand-int 1000))
realm (create-realm! admin-client {:name realm-name
:themes {:defaultLocale "fr",
:emailTheme "keycloak",
:internationalizationEnabled true,
:adminTheme "keycloak",
:supportedLocales #{"en" "fr"},
:loginTheme "keycloak",
:accountTheme "keycloak"}
:accessTokenLifespan (Integer. 2)})]
(is (= realm-name (.getRealm realm)))
(log/info "realm created")
(testing "create two users with only username in the realm"
(let [username1 "user-100"
username2 "user-199"
password (str "pass" (rand-int 100))
user1 (create-user! admin-client realm-name username1 password)
user2 (create-user! admin-client realm-name username2 password)
user1-id (user/user-id admin-client realm-name username1)
user2-id (user/user-id admin-client realm-name username2)
user-id (user/user-id admin-client realm-name "user")]
(is (= username1 (.getUsername user1)))
(is (= username2 (.getUsername user2)))
(is (= (.getId user1) user1-id))
(is (= (.getId user2) user2-id))
(is (= nil user-id))))
(testing "create two users with username, first and last name + email in the realm"
(let [user1 (user/create-user! admin-client realm-name fake-user)
user2 (user/create-user! admin-client realm-name fake-user-2)
user1-id (user/user-id admin-client realm-name (:username fake-user) (:first-name fake-user) (:last-name fake-user) (:email fake-user))
user2-id (user/user-id admin-client realm-name (:username fake-user-2) (:first-name fake-user-2) (:last-name fake-user-2) (:email fake-user-2))
user-id (user/user-id admin-client realm-name "bcart")]
(is (= (:username fake-user) (.getUsername user1)))
(is (= (:username fake-user-2) (.getUsername user2)))
(is (= (.getId user1) user1-id))
(is (= (.getId user2) user2-id))
(is (= nil user-id))))
(testing "realm deletion"
(delete-realm! admin-client realm-name)
(is (thrown? javax.ws.rs.NotFoundException (get-realm admin-client realm-name)))
)))))

(deftest ^:integration user-test
(let [admin-client (deployment/keycloak-client integration-test-conf admin-login admin-password)]
(testing "realm creation "
(let [realm-name (str "test-realm-" (rand-int 1000))
Expand Down Expand Up @@ -72,17 +111,26 @@
access-token (verify deployments realm-name (:access_token token))
extracted-token (extract access-token)]
(is (= username (:username extracted-token)))))
(testing "disable user then re-enable it"
(testing "get user-id by exact match"
(let [username2 (str (rand-int 1000) "-user")
password2 (str "pass" (rand-int 100))
user2 (delete-and-create-user! admin-client realm-name {:username username2 :password password2})
user2-id (user/user-id admin-client realm-name username2)]
(sc/spy)
)
)
#_(testing "disable user then re-enable it"
(fact (.isEnabled (user/disable-user! admin-client realm-name username)) => false)
(fact (.isEnabled (user/enable-user! admin-client realm-name username)) => true))
(testing "Update the user with password provided should be ok"
(sc/spy)
(let [updated-user (user/update-user! admin-client realm-name (.getId user) (merge fake-user {:username username}))]
(fact updated-user => truthy)
(fact (.getEmail updated-user) => (:email fake-user))))
(testing "Update the user with NO password provided should also be ok"
(testing "Update the user with NO password provided should also be ok"
(let [updated-user (user/update-user! admin-client realm-name (.getId user) (dissoc (merge fake-user {:username username}) :password))]
(fact updated-user => truthy)))))))
(testing "realm deletion"
(delete-realm! admin-client realm-name)
;(delete-realm! admin-client realm-name)
(is (thrown? javax.ws.rs.NotFoundException (get-realm admin-client realm-name)))
)))))

0 comments on commit 32955ae

Please sign in to comment.