WIP: Keycloak mail pass integration
Description
Enable Keycloak mail pass integration.
Resolves #217
TODOs
-
Modify theme to add a custom attribute "mail_password_hash" to the account management console -
Implement a domain extension to provide custom REST endpoint for bcrypt with cost 12 and 2b variant -
Implement an add "password-validate" REST endpoint which use the internal Keycloak API -
Ensure the password hash attribute in Keycloak can be modified (via the templating engine) -
Update mail credential syncer script to use 2b variant
To Verify
-
Code building and testing process (maven, gradle etc) - currently gradle
is being used -
Package naming scheme - currently org.archlinux.keycloak.mailpass.rest
-
JAR naming scheme - currently keycloak-mailpass-rest-{x.x.x}.jar
-
Endpoint naming scheme - currently using /mailpass/hashify
and/mailpass/validate
(not included yet) -
Whether or not to use the same JAR for both generating hashes and validating -
Code quality, comments, styling linting etc - currently using Google standards
-
Source placement such as which repository and which directory - currently deployment is assumed to take place via Ansible so data was placed in Keycloak role files directory under providers (similar to theme deployment)
Status Updates:
08/12/2020: A custom REST endpoint has been implemented to compute bcrypt hash for user provided passwords (no auth required)
15/12/2020: The custom REST endpoint for computing the password hashes has been converted to a domain extension that requires authentication for request
❯ . ./invoke-authenticated.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2354 100 2285 100 69 21157 638 --:--:-- --:--:-- --:--:-- 21796
SENT RESOURCE-OWNER-PASSWORD-CREDENTIALS-REQUEST. OUTPUT IS:
HTTP/1.1 200 OK
Cache-Control: no-store
Set-Cookie: KEYCLOAK_LOCALE=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/auth/realms/master/; HttpOnly
Set-Cookie: KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/auth/realms/master/; HttpOnly
X-XSS-Protection: 1; mode=block
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Referrer-Policy: no-referrer
Date: Tue, 15 Dec 2020 06:52:40 GMT
Connection: keep-alive
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Content-Type: application/json
Content-Length: 2285
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJFYjZhV3ExSXhHbm5wMVBYSTlSUVVWRm96Tm1hWVFLSGlfX3pqb1pEclFBIn0.eyJleHAiOjE2MDgwMTUyMjAsImlhdCI6MTYwODAxNTE2MCwianRpIjoiODE1ZDBhMzMtYjJjOC00MWIwLTg4MjktMmEwODM0Y2M5ZmI4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6Im1hc3Rlci1yZWFsbSIsInN1YiI6ImRmZDYxMWM0LTk0NDEtNGE0MC1hZjE3LTRhNTkzZjQxM2FkYyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJmNGU1OGYzMy1kZTBkLTQ4YjgtYjBhOS1iZjY5ZDA5ZDg4ZjciLCJhY3IiOiIxIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImNyZWF0ZS1yZWFsbSIsImFkbWluIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsibWFzdGVyLXJlYWxtIjp7InJvbGVzIjpbInZpZXctaWRlbnRpdHktcHJvdmlkZXJzIiwidmlldy1yZWFsbSIsIm1hbmFnZS1pZGVudGl0eS1wcm92aWRlcnMiLCJpbXBlcnNvbmF0aW9uIiwiY3JlYXRlLWNsaWVudCIsIm1hbmFnZS11c2VycyIsInF1ZXJ5LXJlYWxtcyIsInZpZXctYXV0aG9yaXphdGlvbiIsInF1ZXJ5LWNsaWVudHMiLCJxdWVyeS11c2VycyIsIm1hbmFnZS1ldmVudHMiLCJtYW5hZ2UtcmVhbG0iLCJ2aWV3LWV2ZW50cyIsInZpZXctdXNlcnMiLCJ2aWV3LWNsaWVudHMiLCJtYW5hZ2UtYXV0aG9yaXphdGlvbiIsIm1hbmFnZS1jbGllbnRzIiwicXVlcnktZ3JvdXBzIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.KdW29aewp8401Yuusr_cQ6bsrUFadbKzGb18-Oi0A0dQ69PqCLYCWwgCQIhBKBHIPPZ9ilWaAn7Yk5eumf_Yua0cKZfWGLG0_tDuwLjhGJCTcxXVXd42K9cKMnmox2MwuKuY_hRtvPjzBH44taeIZ8GUbF6ZNSzj792G8Fj9j5WBq-SCeVkDABC9idjkYDB4sGt-Rl5ZAdNqieuJVQ8h7KIk2eLarbHGHdo3jSRpHpaxh04g930uoU1ZXVga5GUiUetBpJLN5ud2e29JX_VuwE2SzAHojgzv6xNT9LfurpemPU0Ub0AQZDuiNYfYgBtjAfV793k5us9pmeBlOrvRkg","expires_in":60,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1OTRhOGM1ZS1iYTBiLTQ0ZGUtYmNhOS1kYzUyZGY2MTk0MWEifQ.eyJleHAiOjE2MDgwMTY5NjAsImlhdCI6MTYwODAxNTE2MCwianRpIjoiMWZlMGY0YjctMTVjOS00ZGZiLWI1ZDYtMTY2ZmFlZWU0ODIwIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9hdXRoL3JlYWxtcy9tYXN0ZXIiLCJzdWIiOiJkZmQ2MTFjNC05NDQxLTRhNDAtYWYxNy00YTU5M2Y0MTNhZGMiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiYWRtaW4tY2xpIiwic2Vzc2lvbl9zdGF0ZSI6ImY0ZTU4ZjMzLWRlMGQtNDhiOC1iMGE5LWJmNjlkMDlkODhmNyIsInNjb3BlIjoiZW1haWwgcHJvZmlsZSJ9.jQD11JsimjSwVC-t3kBv6oMYBdyEguh-4UiuG3NB-vI","token_type":"bearer","not-before-policy":0,"session_state":"f4e58f33-de0d-48b8-b0a9-bf69d09d88f7","scope":"email profile"}
ACCESS TOKEN IS "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJFYjZhV3ExSXhHbm5wMVBYSTlSUVVWRm96Tm1hWVFLSGlfX3pqb1pEclFBIn0.eyJleHAiOjE2MDgwMTUyMjAsImlhdCI6MTYwODAxNTE2MCwianRpIjoiODE1ZDBhMzMtYjJjOC00MWIwLTg4MjktMmEwODM0Y2M5ZmI4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6Im1hc3Rlci1yZWFsbSIsInN1YiI6ImRmZDYxMWM0LTk0NDEtNGE0MC1hZjE3LTRhNTkzZjQxM2FkYyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJmNGU1OGYzMy1kZTBkLTQ4YjgtYjBhOS1iZjY5ZDA5ZDg4ZjciLCJhY3IiOiIxIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImNyZWF0ZS1yZWFsbSIsImFkbWluIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsibWFzdGVyLXJlYWxtIjp7InJvbGVzIjpbInZpZXctaWRlbnRpdHktcHJvdmlkZXJzIiwidmlldy1yZWFsbSIsIm1hbmFnZS1pZGVudGl0eS1wcm92aWRlcnMiLCJpbXBlcnNvbmF0aW9uIiwiY3JlYXRlLWNsaWVudCIsIm1hbmFnZS11c2VycyIsInF1ZXJ5LXJlYWxtcyIsInZpZXctYXV0aG9yaXphdGlvbiIsInF1ZXJ5LWNsaWVudHMiLCJxdWVyeS11c2VycyIsIm1hbmFnZS1ldmVudHMiLCJtYW5hZ2UtcmVhbG0iLCJ2aWV3LWV2ZW50cyIsInZpZXctdXNlcnMiLCJ2aWV3LWNsaWVudHMiLCJtYW5hZ2UtYXV0aG9yaXphdGlvbiIsIm1hbmFnZS1jbGllbnRzIiwicXVlcnktZ3JvdXBzIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.KdW29aewp8401Yuusr_cQ6bsrUFadbKzGb18-Oi0A0dQ69PqCLYCWwgCQIhBKBHIPPZ9ilWaAn7Yk5eumf_Yua0cKZfWGLG0_tDuwLjhGJCTcxXVXd42K9cKMnmox2MwuKuY_hRtvPjzBH44taeIZ8GUbF6ZNSzj792G8Fj9j5WBq-SCeVkDABC9idjkYDB4sGt-Rl5ZAdNqieuJVQ8h7KIk2eLarbHGHdo3jSRpHpaxh04g930uoU1ZXVga5GUiUetBpJLN5ud2e29JX_VuwE2SzAHojgzv6xNT9LfurpemPU0Ub0AQZDuiNYfYgBtjAfV793k5us9pmeBlOrvRkg"
SENDING UN-AUTHENTICATED REQUEST. THIS SHOULD FAIL WITH 401:
HTTP/1.1 401 Unauthorized
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Referrer-Policy: no-referrer
Date: Tue, 15 Dec 2020 06:52:40 GMT
Connection: keep-alive
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Content-Type: application/json
Content-Length: 33
{"error":"HTTP 401 Unauthorized"}
SENDING AUTHENTICATED REQUEST. THIS SHOULD SUCCESSFULY CREATE PASSWORD HASH AND SUCCESS WITH 201:
HTTP/1.1 201 Created
Connection: keep-alive
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Content-Type: application/octet-stream
Referrer-Policy: no-referrer
Content-Length: 60
Date: Tue, 15 Dec 2020 06:52:40 GMT
$2b$12$qoWlJZiAo7C54Ud1.2of0egEk790NhhGyVoprw4gdtuCSA1/Y7gA6%
Edited by Ira ¯\_(ツ)_/¯