Skip to content

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)

image

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 ¯\_(ツ)_/¯

Merge request reports