INF-162 - Configure keycloak client setting via built-in Ansible plugin

Change-Id: Ifd6b43d148a52727e2044c0c4314203fa7711286
diff --git a/README.md b/README.md
index bf177be..29133b7 100644
--- a/README.md
+++ b/README.md
@@ -19,11 +19,55 @@
 ```yaml
 - hosts: all
   vars:
+    keycloak_admin_password: changeme
+    keycloak_client_settings:
+      - name: ...
   roles:
     - keycloak
 
 ```
 
+
+The `keycloak_client_settings` is used to define client setting on the keycloak server. This is a list
+of all required options:
+
+Reference:
+1. https://gist.github.com/PhilipSchmid/506b33cd74ddef4064d30fba50635c5b
+2. https://docs.ansible.com/ansible/latest/collections/community/general/index.html#plugin-index
+
+``` yaml
+keycloak_client_settings:
+  - name: rancher_staging #name of the server
+    client_id: https://staging.aether.onlab.us/v1-saml/keycloak/saml/metadata #URL of Rancher server
+    auth_realm: master #relam of keycloak, default is master
+    protocol: saml #SAML protocol for Rancher (<v2.6)
+    description: "Staging Rancher server"
+    attributes:
+      saml.client.signature: false
+      saml.assertion.signature: true
+      saml_idp_initiated_sso_url_name: "IdPSSOName"
+      saml.server.signature: true
+      saml_name_id_format: "username"
+    redirect_uris: #List of redirect URIs, is related to Rancher server
+      - https://staging.aether.onlab.us/v1-saml/keycloak/saml/acs
+    protocol_mappers: #User and Group mappers, indicate how to map user/group field from Keycloak to client
+      - config:
+          attribute.name: "uid"
+          attribute.nameformat: "Basic"
+          user.attribute: "username"
+        name: "x509 username"
+        protocol: "saml"
+        protocolMapper: "saml-user-property-mapper"
+      - config:
+          attribute.name: "member"
+          attribute.nameformat: "Basic"
+          full.path: "false"
+          single: "true"
+        name: "groups"
+        protocol: "saml"
+        protocolMapper: "saml-group-membership-mapper"
+```
+
 ## License and Author
 
 © 2021 Open Networking Foundation <support@opennetworking.org>
diff --git a/defaults/main.yml b/defaults/main.yml
index 10b0988..ba627dd 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -25,3 +25,6 @@
 keycloak_admin_password: "changeme"
 
 keycloak_listen_address: "0.0.0.0"
+
+# client_settings is a list of Keycloak client to configure - see README.md
+keycloak_client_settings: []
diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml
index 08b9c30..5796c8d 100644
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -21,5 +21,35 @@
       debian-11-priv:
         keycloak_admin_username: "admin"
         keycloak_admin_password: "changeme"
+        keycloak_client_settings:
+          - name: client_testing
+            client_id: https://testing.client.site/v1-saml/keycloak/saml/metadata
+            auth_realm: master
+            protocol: saml
+            description: "Testing Server"
+            attributes:
+              saml.client.signature: false
+              saml.assertion.signature: true
+              saml_idp_initiated_sso_url_name: "IdPSSOName"
+              saml.server.signature: true
+              saml_name_id_format: "username"
+            redirect_uris:
+              - https://testing.client.site/v1-saml/keycloak/saml/acs
+            protocol_mappers:
+              - config:
+                  attribute.name: "uid"
+                  attribute.nameformat: "Basic"
+                  user.attribute: "username"
+                name: "x509 username"
+                protocol: "saml"
+                protocolMapper: "saml-user-property-mapper"
+              - config:
+                  attribute.name: "member"
+                  attribute.nameformat: "Basic"
+                  full.path: "false"
+                  single: "true"
+                name: "groups"
+                protocol: "saml"
+                protocolMapper: "saml-group-membership-mapper"
 verifier:
   name: ansible
diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml
index f05340a..74ba85a 100644
--- a/molecule/default/verify.yml
+++ b/molecule/default/verify.yml
@@ -7,11 +7,34 @@
 - name: Verify
   hosts: all
   tasks:
-  - name: Check that Keycloak is running with configured username/password
-    community.general.keycloak_client:
-      auth_keycloak_url: http://localhost:8080/auth
-      auth_realm: master
-      auth_username: "{{ keycloak_admin_username }}"
-      auth_password: "{{ keycloak_admin_password }}"
-      client_id: test
-      state: present
+  - name: "Create Token for service Keycloak"
+    uri:
+      url: http://localhost:8080/auth/realms/master/protocol/openid-connect/token
+      method: POST
+      body_format: form-urlencoded
+      body:
+        username: "{{ keycloak_admin_username }}"
+        password: "{{ keycloak_admin_password }}"
+        grant_type: "password"
+        client_id: "admin-cli"
+    register: keycloak_token
+
+  - name: "Get Client List"
+    uri:
+      url: http://localhost:8080/auth/admin/realms/master/clients
+      method: GET
+      headers:
+        Accept: "application/json"
+        Authorization: "Bearer {{ keycloak_token.json.access_token }}"
+    register: keycloak_userlist
+
+  - name: Check if the Keycloak client json output contains our client
+    set_fact:
+      find: true
+    with_items: "{{ keycloak_userlist.json }}"
+    when: item.name == keycloak_client_settings[0].name
+
+  - name: Fail if our client isn't installed correctly
+    assert:
+      that:
+        - find is defined
diff --git a/tasks/main.yml b/tasks/main.yml
index 0df97e8..5722125 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -75,3 +75,35 @@
   notify:
     - "start-keycloak"
     - "restart-keycloak"
+- name: Flush handlers to start keycloak server before configuring it via API
+  meta: flush_handlers
+
+- name: Wait for Keycloak to be ready
+  uri:
+    url: "http://localhost:9990/health"
+    method: GET
+    return_content: "yes"
+    timeout: 5
+    body_format: raw
+    follow_redirects: "no"
+    status_code: 200
+  register: result
+  until: result.status == 200
+  retries: 60
+  delay: 5
+
+- name: Configure Keycloak client
+  community.general.keycloak_client:
+    auth_keycloak_url: http://localhost:8080/auth
+    auth_realm: "{{ item.auth_realm }}"
+    auth_username: "{{ keycloak_admin_username }}"
+    auth_password: "{{ keycloak_admin_password }}"
+    client_id: "{{ item.client_id }}"
+    name: "{{ item.name }}"
+    protocol: "{{ item.protocol }}"
+    description: "{{ item.description }}"
+    attributes: "{{ item.attributes }}"
+    redirect_uris: "{{ item.redirect_uris }}"
+    protocol_mappers: "{{ item.protocol_mappers }}"
+    state: present
+  with_items: "{{ keycloak_client_settings }}"