diff --git a/ansible/roles/keycloak/defaults/main.yml b/ansible/roles/keycloak/defaults/main.yml
index 7836d421f75e657b80fafa8d76f940e88ed0333f..637f62a59acff16d05ef43d3472951ca86774526 100644
--- a/ansible/roles/keycloak/defaults/main.yml
+++ b/ansible/roles/keycloak/defaults/main.yml
@@ -57,11 +57,11 @@ wildfly_standalone_config_path: /opt/keycloak/keycloak/standalone/configuration/
 keycloak_ext:  <extension module="org.keycloak.keycloak-server-subsystem"/>
 #keycloak_subsystem:
 #keycloak_cache_container:
-#keycloak_default_ds: 
+#keycloak_default_ds:
 keycloak_download_file: keycloak-3.2.0.Final.tar.gz
 
 keycloak_ds_driver_url: https://jdbc.postgresql.org/download/postgresql-9.2.1212.jar
-#keycloak_ds_driver_path: 
+#keycloak_ds_driver_path:
 keycloak_ds_driver_name: "postgresql"
 keycloak_ds_driver_module: '
     <?xml version="1.0" ?>
@@ -106,3 +106,10 @@ theme: "sunrise.tar.gz"
 dest_theme: "/opt/keycloak/themes/"
 theme_file: sunrise
 keycloak_home: /opt/keycloak
+keycloak_realm_json_file_path: "roles/keycloak/files/python-keycloak-0.12.0/keycloak-realm.json"
+keycloak_user_manager_roles_json_file_path: "roles/keycloak/files/python-keycloak-0.12.0/roles.json"
+keycloak_api_management_username: ""
+keycloak_api_management_user_email: ""
+keycloak_api_management_user_first_name: ""
+keycloak_api_management_user_last_name: ""
+keycloak_api_management_user_password: ""
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/PKG-INFO b/ansible/roles/keycloak/files/python-keycloak-0.12.0/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..e71b54e3b995b675e7f81b254b207e43d625cd6a
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/PKG-INFO
@@ -0,0 +1,19 @@
+Metadata-Version: 1.1
+Name: python-keycloak
+Version: 0.12.0
+Summary: python-keycloak is a Python package providing access to the Keycloak API.
+Home-page: https://bitbucket.org/agriness/python-keycloak
+Author: Marcos Pereira
+Author-email: marcospereira.mpj@gmail.com
+License: GNU General Public License - V3
+Description-Content-Type: UNKNOWN
+Description: UNKNOWN
+Keywords: keycloak openid
+Platform: UNKNOWN
+Classifier: Programming Language :: Python :: 3
+Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
+Classifier: Development Status :: 3 - Alpha
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: Unix
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Topic :: Utilities
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/README.md b/ansible/roles/keycloak/files/python-keycloak-0.12.0/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c6b0940b0800fa091d58eaf2ac1b1103ae460878
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/README.md
@@ -0,0 +1,210 @@
+[![Documentation Status](https://readthedocs.org/projects/python-keycloak/badge/?version=latest)](http://python-keycloak.readthedocs.io/en/latest/?badge=latest)
+
+Python Keycloak
+====================
+
+For review- see https://bitbucket.org/agriness/python-keycloak
+
+**python-keycloak** is a Python package providing access to the Keycloak API.
+
+## Installation
+
+### Via Pypi Package:
+
+``` $ pip install python-keycloak ```
+
+### Manually
+
+``` $ python setup.py install ```
+
+## Dependencies
+
+python-keycloak depends on:
+
+* Python 3
+* [requests](http://docs.python-requests.org/en/master/)
+* [python-jose](http://python-jose.readthedocs.io/en/latest/)
+
+### Tests Dependencies
+
+* unittest
+* [httmock](https://github.com/patrys/httmock)
+
+## Bug reports
+
+Please report bugs and feature requests at
+https://bitbucket.org/agriness/python-keycloak/issues
+
+## Documentation
+
+The documentation for python-keycloak is available on [readthedocs](http://python-keycloak.readthedocs.io).
+
+## Contributors
+
+* [Agriness Team](http://www.agriness.com/pt/)
+* [Marcos Pereira](marcospereira.mpj@gmail.com)
+* [Martin Devlin](martin.devlin@pearson.com) 
+* [Shon T. Urbas](shon.urbas@gmail.com>)
+
+## Usage
+
+```python
+from keycloak import KeycloakOpenID
+
+# Configure client
+keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/auth/",
+                    client_id="example_client",
+                    realm_name="example_realm",
+                    client_secret_key="secret")
+
+# Get WellKnow
+config_well_know = keycloak_openid.well_know()
+
+# Get Token
+token = keycloak_openid.token("user", "password")
+
+# Get Userinfo
+userinfo = keycloak_openid.userinfo(token['access_token'])
+
+# Refresh token
+token = keycloak_openid.refresh_token(token['refresh_token'])
+
+# Logout
+keycloak_openid.logout(token['refresh_token'])
+
+# Get Certs
+certs = keycloak_openid.certs()
+
+# Get RPT (Entitlement)
+token = keycloak_openid.token("user", "password")
+rpt = keycloak_openid.entitlement(token['access_token'], "resource_id")
+
+# Instropect RPT
+token_rpt_info = keycloak_openid.introspect(keycloak_openid.introspect(token['access_token'], rpt=rpt['rpt'],
+                                     token_type_hint="requesting_party_token"))
+
+# Introspect Token
+token_info = keycloak_openid.introspect(token['access_token']))
+
+# Decode Token
+KEYCLOAK_PUBLIC_KEY = "secret"
+options = {"verify_signature": True, "verify_aud": True, "exp": True}
+token_info = keycloak_openid.decode_token(token['access_token'], key=KEYCLOAK_PUBLIC_KEY, options=options)
+
+# Get permissions by token
+token = keycloak_openid.token("user", "password")
+keycloak_openid.load_authorization_config("example-authz-config.json")
+policies = keycloak_openid.get_policies(token['access_token'], method_token_info='decode', key=KEYCLOAK_PUBLIC_KEY)
+permissions = keycloak_openid.get_permissions(token['access_token'], method_token_info='introspect')
+
+# KEYCLOAK ADMIN
+
+from keycloak import KeycloakAdmin
+
+keycloak_admin = KeycloakAdmin(server_url="http://localhost:8080/auth/",
+                               username='example-admin',
+                               password='secret',
+                               realm_name="example_realm",
+                               verify=True)
+        
+# Add user                       
+new_user = keycloak_admin.create_user({"email": "example@example.com",
+                    "username": "example@example.com",
+                    "enabled": True,
+                    "firstName": "Example",
+                    "lastName": "Example",
+                    "realmRoles": ["user_default", ],
+                    "attributes": {"example": "1,2,3,3,"}})  
+                    
+                    
+# Add user and set password
+new_user = keycloak_admin.create_user({"email": "example@example.com",
+                    "username": "example@example.com",
+                    "enabled": True,
+                    "firstName": "Example",
+                    "lastName": "Example",
+                    "credentials": [{"value": "secret","type": "password",}],
+                    "realmRoles": ["user_default", ],
+                    "attributes": {"example": "1,2,3,3,"}})                   
+
+# User counter
+count_users = keycloak_admin.users_count()
+
+# Get users Returns a list of users, filtered according to query parameters
+users = keycloak_admin.get_users({})
+
+# Get user ID from name
+user-id-keycloak = keycloak_admin.get_user_id("example@example.com")
+
+# Get User
+user = keycloak_admin.get_user("user-id-keycloak")
+
+# Update User
+response = keycloak_admin.update_user(user_id="user-id-keycloak", 
+                                      payload={'firstName': 'Example Update'})
+
+# Update User Password
+response = set_user_password(user_id="user-id-keycloak", password="secret", temporary=True)
+                                      
+# Delete User
+response = keycloak_admin.delete_user(user_id="user-id-keycloak")
+
+# Get consents granted by the user
+consents = keycloak_admin.consents_user(user_id="user-id-keycloak")
+
+# Send User Action
+response = keycloak_admin.send_update_account(user_id="user-id-keycloak", 
+                                              payload=json.dumps(['UPDATE_PASSWORD']))
+
+# Send Verify Email
+response = keycloak_admin.send_verify_email(user_id="user-id-keycloak")
+
+# Get sessions associated with the user
+sessions = keycloak_admin.get_sessions(user_id="user-id-keycloak")
+
+# Get themes, social providers, auth providers, and event listeners available on this server
+server_info = keycloak_admin.get_server_info()
+
+# Get clients belonging to the realm Returns a list of clients belonging to the realm
+clients = keycloak_admin.get_clients()
+
+# Get client - id (not client-id) from client by name
+client_id=keycloak_admin.get_client_id("my-client")
+
+# Get representation of the client - id of client (not client-id)
+client = keycloak_admin.get_client(client_id="client_id")
+
+# Get all roles for the realm or client
+realm_roles = keycloak_admin.get_realm_roles()
+
+# Get all roles for the client
+client_roles = keycloak_admin.get_client_roles(client_id="client_id")
+
+# Get client role
+role = keycloak_admin.get_client_role(client_id="client_id", role_name="role_name")
+
+# Warning: Deprecated
+# Get client role id from name
+role_id = keycloak_admin.get_client_role_id(client_id="client_id", role_name="test")
+
+# Create client role
+keycloak_admin.create_client_role(client_id, "test")
+
+# Assign client role to user. Note that BOTH role_name and role_id appear to be required.
+keycloak_admin.assign_client_role(client_id="client_id", user_id="user_id", role_id="role_id", role_name="test")
+
+# Create new group
+group = keycloak_admin.create_group(name="Example Group")
+
+# Get all groups
+groups = keycloak_admin.get_groups()
+
+# Get group 
+group = keycloak_admin.get_group(group_id='group_id')
+
+# Get group by name
+group = keycloak_admin.get_group_by_name(name_or_path='group_id', search_in_subgroups=True)
+
+# Function to trigger user sync from provider
+sync_users(storage_id="storage_di", action="action")
+```
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak-realm.json b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak-realm.json
new file mode 100644
index 0000000000000000000000000000000000000000..72416d4de45c06a24bbff5b0e5b29a49116c59f8
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak-realm.json
@@ -0,0 +1,1999 @@
+{
+  "id": "sunbird",
+  "realm": "sunbird",
+  "notBefore": 0,
+  "revokeRefreshToken": false,
+  "accessTokenLifespan": 21600,
+  "accessTokenLifespanForImplicitFlow": 7200,
+  "ssoSessionIdleTimeout": 1800,
+  "ssoSessionMaxLifespan": 21600,
+  "offlineSessionIdleTimeout": 43200,
+  "accessCodeLifespan": 60,
+  "accessCodeLifespanUserAction": 300,
+  "accessCodeLifespanLogin": 1800,
+  "actionTokenGeneratedByAdminLifespan": 43200,
+  "actionTokenGeneratedByUserLifespan": 300,
+  "enabled": true,
+  "sslRequired": "external",
+  "registrationAllowed": false,
+  "registrationEmailAsUsername": false,
+  "rememberMe": true,
+  "verifyEmail": false,
+  "loginWithEmailAllowed": true,
+  "duplicateEmailsAllowed": false,
+  "resetPasswordAllowed": true,
+  "editUsernameAllowed": false,
+  "bruteForceProtected": false,
+  "permanentLockout": false,
+  "maxFailureWaitSeconds": 900,
+  "minimumQuickLoginWaitSeconds": 60,
+  "waitIncrementSeconds": 60,
+  "quickLoginCheckMilliSeconds": 1000,
+  "maxDeltaTimeSeconds": 43200,
+  "failureFactor": 30,
+  "roles": {
+    "realm": [
+      {
+        "id": "7b955d7f-0a1e-4935-8391-642886d34612",
+        "name": "offline_access",
+        "description": "${role_offline-access}",
+        "scopeParamRequired": true,
+        "composite": false,
+        "clientRole": false,
+        "containerId": "sunbird"
+      },
+      {
+        "id": "96adf368-c8e2-4b39-b2a5-2559573edb63",
+        "name": "uma_authorization",
+        "description": "${role_uma_authorization}",
+        "scopeParamRequired": false,
+        "composite": false,
+        "clientRole": false,
+        "containerId": "sunbird"
+      }
+    ],
+    "client": {
+      "realm-management": [
+        {
+          "id": "3f8bf7e5-5d66-4394-8f06-1270529c605f",
+          "name": "manage-authorization",
+          "description": "${role_manage-authorization}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "601fa2c9-29d4-49c1-87ac-939a1260f6ce",
+          "name": "query-realms",
+          "description": "${role_query-realms}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "9aa1dcd9-cb93-4496-af5f-41b9ecacc1da",
+          "name": "view-authorization",
+          "description": "${role_view-authorization}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "98999987-faf5-4c4e-958a-e5463bc4edc6",
+          "name": "manage-events",
+          "description": "${role_manage-events}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "f898fca8-5361-49d5-900a-ebf5b775a939",
+          "name": "impersonation",
+          "description": "${role_impersonation}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "698dfeb0-b8d2-4240-b8a8-acd4b7a12ad3",
+          "name": "view-realm",
+          "description": "${role_view-realm}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "3ff462fc-b33c-431a-b54b-861c3298d910",
+          "name": "manage-users",
+          "description": "${role_manage-users}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "be1802b1-558c-404c-bcb9-b9bf77af9788",
+          "name": "manage-identity-providers",
+          "description": "${role_manage-identity-providers}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "387b44e4-e901-4431-b9af-6abd9377ed46",
+          "name": "query-clients",
+          "description": "${role_query-clients}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "a408b6e8-03c9-46a2-97ba-305d09db0c3c",
+          "name": "view-events",
+          "description": "${role_view-events}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "41c2f39a-3008-4f9d-9e1e-a7738c118570",
+          "name": "query-groups",
+          "description": "${role_query-groups}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "26d3289b-d2eb-4cf2-a501-f1e3fa07344c",
+          "name": "manage-clients",
+          "description": "${role_manage-clients}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "e2077ab0-6efb-450d-9cba-89cacd887b71",
+          "name": "create-client",
+          "description": "${role_create-client}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "46019462-3dc8-46a8-9786-ffcbad293f43",
+          "name": "view-users",
+          "description": "${role_view-users}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "composites": {
+            "client": {
+              "realm-management": [
+                "query-groups",
+                "query-users"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "d269f220-e93f-4b43-96a1-9f2c117a2dfb",
+          "name": "view-clients",
+          "description": "${role_view-clients}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "composites": {
+            "client": {
+              "realm-management": [
+                "query-clients"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "0c998f1b-7363-47fb-a493-4b6f4aacb0ba",
+          "name": "realm-admin",
+          "description": "${role_realm-admin}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "composites": {
+            "client": {
+              "realm-management": [
+                "manage-authorization",
+                "query-realms",
+                "view-authorization",
+                "manage-events",
+                "impersonation",
+                "view-realm",
+                "manage-users",
+                "manage-identity-providers",
+                "query-clients",
+                "view-events",
+                "query-groups",
+                "manage-clients",
+                "create-client",
+                "view-users",
+                "view-clients",
+                "manage-realm",
+                "view-identity-providers",
+                "query-users"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "d77bf5a5-5877-450b-b11e-5f874f410e10",
+          "name": "manage-realm",
+          "description": "${role_manage-realm}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "d97009ed-d0c7-4afb-b9a3-6ee03ef01a74",
+          "name": "view-identity-providers",
+          "description": "${role_view-identity-providers}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        },
+        {
+          "id": "57118202-c5e5-4c49-829b-c2ed796bfdea",
+          "name": "query-users",
+          "description": "${role_query-users}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+        }
+      ],
+      "security-admin-console": [],
+      "android": [],
+      "admin-cli": [],
+      "trampoline": [],
+      "broker": [
+        {
+          "id": "19ef58ac-2d90-40a4-a158-0e2f8893264a",
+          "name": "read-token",
+          "description": "${role_read-token}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "c3950efa-6684-44c2-b50a-c7b3d16df04b"
+        }
+      ],
+      "portal": [],
+      "account": [
+        {
+          "id": "1fef7ac5-b042-462b-8298-0446044788b3",
+          "name": "manage-account",
+          "description": "${role_manage-account}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "composites": {
+            "client": {
+              "account": [
+                "manage-account-links"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "c2d24d3f-65ca-46de-9cd8-3eeb71a7f83d"
+        },
+        {
+          "id": "f8786348-6fa4-4b13-828e-9f080c9c6824",
+          "name": "manage-account-links",
+          "description": "${role_manage-account-links}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "c2d24d3f-65ca-46de-9cd8-3eeb71a7f83d"
+        },
+        {
+          "id": "91c5c738-9c39-4c4d-bae8-75f18fd7c5e4",
+          "name": "view-profile",
+          "description": "${role_view-profile}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "c2d24d3f-65ca-46de-9cd8-3eeb71a7f83d"
+        }
+      ]
+    }
+  },
+  "groups": [],
+  "defaultRoles": [
+    "offline_access",
+    "uma_authorization"
+  ],
+  "requiredCredentials": [
+    "password"
+  ],
+  "passwordPolicy": "hashIterations(20000)",
+  "otpPolicyType": "totp",
+  "otpPolicyAlgorithm": "HmacSHA1",
+  "otpPolicyInitialCounter": 0,
+  "otpPolicyDigits": 6,
+  "otpPolicyLookAheadWindow": 1,
+  "otpPolicyPeriod": 30,
+  "clientScopeMappings": {
+    "realm-management": [
+      {
+        "client": "admin-cli",
+        "roles": [
+          "realm-admin"
+        ]
+      },
+      {
+        "client": "security-admin-console",
+        "roles": [
+          "realm-admin"
+        ]
+      }
+    ]
+  },
+  "clients": [
+    {
+      "id": "9a901d18-377b-4615-9b89-677b544be3c5",
+      "clientId": "trampoline",
+      "rootUrl": "",
+      "adminUrl": "",
+      "baseUrl": "/",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [
+      ],
+      "webOrigins": [
+      ],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": false,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": true,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "saml.assertion.signature": "false",
+        "saml.force.post.binding": "false",
+        "saml.multivalued.roles": "false",
+        "saml.encrypt": "false",
+        "saml_force_name_id_format": "false",
+        "saml.client.signature": "false",
+        "saml.authnstatement": "false",
+        "saml.server.signature": "false",
+        "saml.server.signature.keyinfo.ext": "false",
+        "saml.onetimeuse.condition": "false"
+      },
+      "fullScopeAllowed": true,
+      "nodeReRegistrationTimeout": -1,
+      "protocolMappers": [
+        {
+          "id": "12134027-94cc-401c-bbf6-be565078ddfb",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "6a956bf1-6c40-4549-b335-9fe8c788b18f",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "d32ba1d4-3fef-42ff-aa2b-98cb4bfef6f9",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "9e899fc7-1ddd-447d-810c-d91333d6621c",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "74e4d13f-bd02-4f17-bbbc-d4b79bab1971",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "48fe23c2-a6fb-4c5e-8930-28ad1913829a",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "da893beb-6ac7-420d-b51b-f05dadf56bbc",
+      "clientId": "android",
+      "rootUrl": "",
+      "baseUrl": "/",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [
+      ],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": true,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "saml.assertion.signature": "false",
+        "saml.force.post.binding": "false",
+        "saml.multivalued.roles": "false",
+        "saml.encrypt": "false",
+        "saml_force_name_id_format": "false",
+        "saml.client.signature": "false",
+        "saml.authnstatement": "false",
+        "saml.server.signature": "false",
+        "saml.server.signature.keyinfo.ext": "false",
+        "saml.onetimeuse.condition": "false"
+      },
+      "fullScopeAllowed": true,
+      "nodeReRegistrationTimeout": -1,
+      "protocolMappers": [
+        {
+          "id": "ff7dac46-16b4-4ab6-a054-dd03d5411fa9",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "32fad9c0-0dfe-45b2-94a1-3e2f74d756ec",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "4fb4d644-c609-4a27-a407-d451bcd83e16",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "84e7c6e5-1afb-44d8-b507-1ed31fa0f351",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "e7ca189f-94de-4996-a192-e93ba960bbba",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "16bedb3b-7571-4106-9a47-66151915ac31",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "8891d8e9-35e6-4a1c-b32b-027be03b0f24",
+      "clientId": "admin-cli",
+      "name": "${client_admin-cli}",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": false,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": true,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "32d6a3a4-8635-4a36-bd14-8ac5b73a49cc",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "900fa741-d1b2-467e-88a6-b454a9519568",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "8ea14714-d160-49b8-b612-59102d50ef53",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "bd167b99-5d23-49c1-90c7-85c2b088fed7",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "c4fe56a1-8d15-455a-b87b-cf051454b57c",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "26e3bf4c-8f9a-4548-b0db-5bbb7c398991",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "c3950efa-6684-44c2-b50a-c7b3d16df04b",
+      "clientId": "broker",
+      "name": "${client_broker}",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "54c3bbc3-850b-4636-82d1-ed4f3a46a00a",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "0f0d9b74-c476-4981-a783-dd4bdbe041ec",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "d6f625cc-eac1-49d0-bea5-17e6f9d3860c",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "bbf35056-9bbe-49a0-aefc-2bde2379ccdc",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "38b04951-1043-4dc6-9504-7b0f31ed71a4",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "88bb836b-7feb-45eb-b004-fb3be8436908",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "b2f45201-1362-4b10-83c3-207d470f44bf",
+      "clientId": "realm-management",
+      "name": "${client_realm-management}",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": true,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "71605238-bf41-400e-8c03-a5d78f54b00b",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "a0cb6f3a-30ef-4475-b73f-ca6c2f1f3675",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "3a7708b1-63b9-4116-af7f-969fc1bf61a4",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "c393d7b7-fa22-4e90-9ad7-07d520632c20",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "2d8cbac4-e4dd-4fa6-bf71-98adf826b9dd",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "e77aae69-8ea4-4ee4-bcd6-ba7ef3958c02",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "8c12290d-d62f-48ce-913b-c93bf995ca59",
+      "clientId": "portal",
+      "rootUrl": "",
+      "adminUrl": "/callback",
+      "baseUrl": "/",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [
+      ],
+      "webOrigins": [
+        ""
+      ],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "saml.assertion.signature": "false",
+        "saml.force.post.binding": "false",
+        "saml.multivalued.roles": "false",
+        "saml.encrypt": "false",
+        "saml_force_name_id_format": "false",
+        "saml.client.signature": "false",
+        "saml.authnstatement": "false",
+        "saml.server.signature": "false",
+        "saml.server.signature.keyinfo.ext": "false",
+        "saml.onetimeuse.condition": "false"
+      },
+      "fullScopeAllowed": true,
+      "nodeReRegistrationTimeout": -1,
+      "protocolMappers": [
+        {
+          "id": "63071ff2-a5e5-4d38-b534-a9f25a075403",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "9bf9cad5-dbce-41e9-aa36-d84cc5a768a2",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "238e55b7-6545-467e-856b-f95477afe1ff",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "edb1ff4e-b452-46bc-8c3b-d6075f6ee579",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "7a0118e2-57ff-4d23-bf74-cbfe1f545d1d",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "b59a913e-118a-4dc4-a8d7-66c44ced5345",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "79c518d7-b41a-4e6f-be42-4ef365824100",
+      "clientId": "security-admin-console",
+      "name": "${client_security-admin-console}",
+      "baseUrl": "/auth/admin/sunbird/console/index.html",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "redirectUris": [
+        "/auth/admin/sunbird/console/*"
+      ],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "c989a8c8-cb8b-40ff-b4b9-86122bad7aa9",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "b180fb8c-997c-4f6a-b774-af677f903139",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "c373dc9a-49d7-4d28-9b94-06cf20fb1955",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "24c7b1c4-62c2-4d92-ab19-49bfaedcc3d4",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "883a39a7-37b4-46ef-a761-3e51b95ccc35",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "95ed8e44-38cc-4f09-8adc-19c12d5eada0",
+          "name": "locale",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "consentText": "${locale}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "locale",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "locale",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "c66c6a41-eb22-443f-8a77-e68d404ad26f",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    },
+    {
+      "id": "c2d24d3f-65ca-46de-9cd8-3eeb71a7f83d",
+      "clientId": "account",
+      "name": "${client_account}",
+      "baseUrl": "/auth/realms/sunbird/account",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "",
+      "defaultRoles": [
+        "manage-account",
+        "view-profile"
+      ],
+      "redirectUris": [
+        "/auth/realms/sunbird/account/*"
+      ],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "a64118ab-33c8-4060-9f3e-3ed817ba8e0d",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        },
+        {
+          "id": "1f4a0c5e-7c8a-4693-8be5-14681b243868",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${username}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "8d88a133-a399-4e75-b051-5b0d4ae850ab",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": true,
+          "consentText": "${fullName}",
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "45593258-916c-4158-8577-d9806c16415a",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${email}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "027be48e-b7dc-4c3a-a648-414a466b67dd",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${familyName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "c93937f9-0446-4be9-8b47-3c6de857497e",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": true,
+          "consentText": "${givenName}",
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "useTemplateConfig": false,
+      "useTemplateScope": false,
+      "useTemplateMappers": false
+    }
+  ],
+  "clientTemplates": [],
+  "browserSecurityHeaders": {
+    "xContentTypeOptions": "nosniff",
+    "xRobotsTag": "none",
+    "xFrameOptions": "SAMEORIGIN",
+    "xXSSProtection": "1; mode=block",
+    "contentSecurityPolicy": "frame-src 'self'"
+  },
+  "smtpServer": {
+    "password": "",
+    "starttls": "",
+    "auth": "true",
+    "port": "587",
+    "host": "",
+    "from": "",
+    "ssl": "",
+    "user": ""
+  },
+  "loginTheme": "sunrise",
+  "eventsEnabled": false,
+  "eventsListeners": [
+    "jboss-logging"
+  ],
+  "enabledEventTypes": [],
+  "adminEventsEnabled": false,
+  "adminEventsDetailsEnabled": false,
+  "components": {
+    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
+      {
+        "id": "84078bbb-e005-44c8-9c7d-a1b4821558da",
+        "name": "Max Clients Limit",
+        "providerId": "max-clients",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "max-clients": [
+            "200"
+          ]
+        }
+      },
+      {
+        "id": "346d857e-4385-4f8f-a2fc-072fd11a10ec",
+        "name": "Allowed Protocol Mapper Types",
+        "providerId": "allowed-protocol-mappers",
+        "subType": "authenticated",
+        "subComponents": {},
+        "config": {
+          "allowed-protocol-mapper-types": [
+            "saml-user-attribute-mapper",
+            "oidc-usermodel-attribute-mapper",
+            "oidc-usermodel-property-mapper",
+            "saml-role-list-mapper",
+            "saml-user-property-mapper",
+            "oidc-full-name-mapper",
+            "oidc-address-mapper",
+            "oidc-sha256-pairwise-sub-mapper"
+          ],
+          "consent-required-for-all-mappers": [
+            "true"
+          ]
+        }
+      },
+      {
+        "id": "eed64f9f-4b66-45ad-bdb4-4070e3802366",
+        "name": "Allowed Client Templates",
+        "providerId": "allowed-client-templates",
+        "subType": "authenticated",
+        "subComponents": {},
+        "config": {}
+      },
+      {
+        "id": "17ac4eaa-9139-4b3a-b1db-c82d44c1531d",
+        "name": "Allowed Client Templates",
+        "providerId": "allowed-client-templates",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {}
+      },
+      {
+        "id": "38532936-be91-40e4-b65d-c0abfaf9547c",
+        "name": "Full Scope Disabled",
+        "providerId": "scope",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {}
+      },
+      {
+        "id": "8c1690a2-6eea-4d61-ab66-7a015e3bea3c",
+        "name": "Allowed Protocol Mapper Types",
+        "providerId": "allowed-protocol-mappers",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "allowed-protocol-mapper-types": [
+            "oidc-usermodel-property-mapper",
+            "saml-user-property-mapper",
+            "oidc-full-name-mapper",
+            "oidc-sha256-pairwise-sub-mapper",
+            "oidc-address-mapper",
+            "oidc-usermodel-attribute-mapper",
+            "saml-role-list-mapper",
+            "saml-user-attribute-mapper"
+          ],
+          "consent-required-for-all-mappers": [
+            "true"
+          ]
+        }
+      },
+      {
+        "id": "3dcc314c-07f8-484d-9535-29424dbaddfc",
+        "name": "Trusted Hosts",
+        "providerId": "trusted-hosts",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "host-sending-registration-request-must-match": [
+            "true"
+          ],
+          "client-uris-must-match": [
+            "true"
+          ]
+        }
+      },
+      {
+        "id": "ab52b781-64b9-42a0-99f5-cbeba6710763",
+        "name": "Consent Required",
+        "providerId": "consent-required",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {}
+      }
+    ],
+    "org.keycloak.keys.KeyProvider": [
+      {
+        "id": "bd30c46f-9ee3-443d-9faa-6ed8075aac87",
+        "name": "rsa-generated",
+        "providerId": "rsa-generated",
+        "subComponents": {},
+        "config": {
+          "priority": [
+            "100"
+          ]
+        }
+      },
+      {
+        "id": "a93cc73f-b070-48cd-bf08-9b290707c2f5",
+        "name": "hmac-generated",
+        "providerId": "hmac-generated",
+        "subComponents": {},
+        "config": {
+          "priority": [
+            "100"
+          ]
+        }
+      }
+    ]
+  },
+  "internationalizationEnabled": true,
+  "supportedLocales": [
+    "de",
+    "no",
+    "ru",
+    "sv",
+    "pt-BR",
+    "ja",
+    "lt",
+    "en",
+    "it",
+    "fr",
+    "es",
+    "ca"
+  ],
+  "defaultLocale": "en",
+  "authenticationFlows": [
+    {
+      "id": "6c9d3423-9956-4d08-a124-41cd17aceb5a",
+      "alias": "Direct Grant 2",
+      "description": "OpenID Connect Resource Owner Grant",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": false,
+      "authenticationExecutions": [
+        {
+          "authenticator": "direct-grant-validate-username",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "direct-grant-validate-password",
+          "requirement": "DISABLED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "direct-grant-validate-otp",
+          "requirement": "OPTIONAL",
+          "priority": 30,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "a7a49eb1-4386-499a-8a8f-13454b428f98",
+      "alias": "Direct Grant w/o Password",
+      "description": "Grant user access using only the username and no password.",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": false,
+      "authenticationExecutions": []
+    },
+    {
+      "id": "c7b2f9c2-525b-486a-b2a8-148606caac0e",
+      "alias": "Handle Existing Account",
+      "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "idp-confirm-link",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "idp-email-verification",
+          "requirement": "ALTERNATIVE",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "ALTERNATIVE",
+          "priority": 30,
+          "flowAlias": "Verify Existing Account by Re-authentication",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "c4674fef-8631-43c5-8f44-deb8867fa866",
+      "alias": "Verify Existing Account by Re-authentication",
+      "description": "Reauthentication of existing account",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "idp-username-password-form",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-otp-form",
+          "requirement": "OPTIONAL",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "35016b3a-a041-47fd-8a85-a131c6f7b745",
+      "alias": "browser",
+      "description": "browser based authentication",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "auth-cookie",
+          "requirement": "ALTERNATIVE",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-spnego",
+          "requirement": "DISABLED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "identity-provider-redirector",
+          "requirement": "ALTERNATIVE",
+          "priority": 25,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "ALTERNATIVE",
+          "priority": 30,
+          "flowAlias": "forms",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "8e85927e-349d-4a0a-a7da-efb352ba78ce",
+      "alias": "clients",
+      "description": "Base authentication for clients",
+      "providerId": "client-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "client-secret",
+          "requirement": "ALTERNATIVE",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "client-jwt",
+          "requirement": "ALTERNATIVE",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "b62ac783-8af6-429e-a8ff-7c8073195675",
+      "alias": "direct grant",
+      "description": "OpenID Connect Resource Owner Grant",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "direct-grant-validate-username",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "direct-grant-validate-password",
+          "requirement": "DISABLED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "direct-grant-validate-otp",
+          "requirement": "OPTIONAL",
+          "priority": 30,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "e16e69c8-a3e8-480c-8201-8474d614e172",
+      "alias": "docker auth",
+      "description": "Used by Docker clients to authenticate against the IDP",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "docker-http-basic-authenticator",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "487ab3f9-33bf-49e2-8b03-5c45c85ea8b5",
+      "alias": "first broker login",
+      "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticatorConfig": "review profile config",
+          "authenticator": "idp-review-profile",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticatorConfig": "create unique user config",
+          "authenticator": "idp-create-user-if-unique",
+          "requirement": "ALTERNATIVE",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "ALTERNATIVE",
+          "priority": 30,
+          "flowAlias": "Handle Existing Account",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "a6d19ee2-387a-4db8-9ecb-2e9f806a88a1",
+      "alias": "forms",
+      "description": "Username, password, otp and other auth forms.",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "auth-username-password-form",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-otp-form",
+          "requirement": "OPTIONAL",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "43fc7877-ad15-4c93-b327-15d4ca83f3e1",
+      "alias": "registration",
+      "description": "registration flow",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "registration-page-form",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "flowAlias": "registration form",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "8a77377f-60eb-4a23-8bfe-b7c360d7b48f",
+      "alias": "registration form",
+      "description": "registration form",
+      "providerId": "form-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "registration-user-creation",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "registration-profile-action",
+          "requirement": "REQUIRED",
+          "priority": 40,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "registration-password-action",
+          "requirement": "REQUIRED",
+          "priority": 50,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "registration-recaptcha-action",
+          "requirement": "DISABLED",
+          "priority": 60,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "30bd3dd1-f2f1-4708-a07d-08cf759c7b28",
+      "alias": "reset credentials",
+      "description": "Reset credentials for a user if they forgot their password or something",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "reset-credentials-choose-user",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "reset-credential-email",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "reset-password",
+          "requirement": "REQUIRED",
+          "priority": 30,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "reset-otp",
+          "requirement": "OPTIONAL",
+          "priority": 40,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "226a50b1-059a-44ef-8cfe-082dee5d60b9",
+      "alias": "saml ecp",
+      "description": "SAML ECP Profile Authentication Flow",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "http-basic-authenticator",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    }
+  ],
+  "authenticatorConfig": [
+    {
+      "id": "aec72381-3c1d-4a96-b436-ddb72b3737b9",
+      "alias": "create unique user config",
+      "config": {
+        "require.password.update.after.registration": "false"
+      }
+    },
+    {
+      "id": "51f3fa48-bf74-4df9-9724-c0a9d6fe7c80",
+      "alias": "review profile config",
+      "config": {
+        "update.profile.on.first.login": "missing"
+      }
+    }
+  ],
+  "requiredActions": [
+    {
+      "alias": "CONFIGURE_TOTP",
+      "name": "Configure OTP",
+      "providerId": "CONFIGURE_TOTP",
+      "enabled": true,
+      "defaultAction": false,
+      "config": {}
+    },
+    {
+      "alias": "UPDATE_PASSWORD",
+      "name": "Update Password",
+      "providerId": "UPDATE_PASSWORD",
+      "enabled": true,
+      "defaultAction": false,
+      "config": {}
+    },
+    {
+      "alias": "UPDATE_PROFILE",
+      "name": "Update Profile",
+      "providerId": "UPDATE_PROFILE",
+      "enabled": true,
+      "defaultAction": false,
+      "config": {}
+    },
+    {
+      "alias": "VERIFY_EMAIL",
+      "name": "Verify Email",
+      "providerId": "VERIFY_EMAIL",
+      "enabled": true,
+      "defaultAction": false,
+      "config": {}
+    },
+    {
+      "alias": "terms_and_conditions",
+      "name": "Terms and Conditions",
+      "providerId": "terms_and_conditions",
+      "enabled": true,
+      "defaultAction": false,
+      "config": {}
+    }
+  ],
+  "browserFlow": "browser",
+  "registrationFlow": "registration",
+  "directGrantFlow": "Direct Grant 2",
+  "resetCredentialsFlow": "reset credentials",
+  "clientAuthenticationFlow": "clients",
+  "dockerAuthenticationFlow": "docker auth",
+  "attributes": {
+    "_browser_header.xXSSProtection": "1; mode=block",
+    "_browser_header.xFrameOptions": "SAMEORIGIN",
+    "permanentLockout": "false",
+    "quickLoginCheckMilliSeconds": "1000",
+    "_browser_header.xRobotsTag": "none",
+    "maxFailureWaitSeconds": "900",
+    "minimumQuickLoginWaitSeconds": "60",
+    "failureFactor": "30",
+    "actionTokenGeneratedByUserLifespan": "300",
+    "maxDeltaTimeSeconds": "43200",
+    "_browser_header.xContentTypeOptions": "nosniff",
+    "actionTokenGeneratedByAdminLifespan": "43200",
+    "bruteForceProtected": "false",
+    "_browser_header.contentSecurityPolicy": "frame-src 'self'",
+    "waitIncrementSeconds": "60"
+  },
+  "keycloakVersion": "3.2.0.Final"
+}
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/__init__.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6da124c13c4840a8a1cf814f4266847e6cf54605
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/__init__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from .keycloak_openid import *
+from .keycloak_admin import *
+from .keycloak_adminchild import *
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/__init__.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a1d86dbeba8b6911332d783e5aa62d11795ee7f
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/__init__.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import ast
+import json
+
+from .permission import Permission
+from .policy import Policy
+from .role import Role
+
+
+class Authorization:
+    """
+    Keycloak Authorization (policies, roles, scopes and resources).
+
+    https://keycloak.gitbooks.io/documentation/authorization_services/index.html
+
+    """
+
+    def __init__(self):
+        self._policies = {}
+
+    @property
+    def policies(self):
+        return self._policies
+
+    @policies.setter
+    def policies(self, value):
+        self._policies = value
+
+    def load_config(self, data):
+        """
+        Load policies, roles and permissions (scope/resources).
+
+        :param data: keycloak authorization data (dict)
+        :return:
+        """
+        for pol in data['policies']:
+            if pol['type'] == 'role':
+                policy = Policy(name=pol['name'],
+                                type=pol['type'],
+                                logic=pol['logic'],
+                                decision_strategy=pol['decisionStrategy'])
+
+                config_roles = json.loads(pol['config']['roles'])
+                for role in config_roles:
+                    policy.add_role(Role(name=role['id'],
+                                         required=role['required']))
+
+                self.policies[policy.name] = policy
+
+            if pol['type'] == 'scope':
+                permission = Permission(name=pol['name'],
+                                        type=pol['type'],
+                                        logic=pol['logic'],
+                                        decision_strategy=pol['decisionStrategy'])
+
+                permission.scopes = ast.literal_eval(pol['config']['scopes'])
+
+                for policy_name in ast.literal_eval(pol['config']['applyPolicies']):
+                    self.policies[policy_name].add_permission(permission)
+
+            if pol['type'] == 'resource':
+                permission = Permission(name=pol['name'],
+                                        type=pol['type'],
+                                        logic=pol['logic'],
+                                        decision_strategy=pol['decisionStrategy'])
+
+                permission.resources = ast.literal_eval(pol['config']['resources'])
+
+                for policy_name in ast.literal_eval(pol['config']['applyPolicies']):
+                    self.policies[policy_name].add_permission(permission)
+
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/permission.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/permission.py
new file mode 100644
index 0000000000000000000000000000000000000000..94eca779542b9af1639490af19c564db62c07ffd
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/permission.py
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+class Permission:
+    """
+    Consider this simple and very common permission:
+
+    A permission associates the object being protected with the policies that must be evaluated to determine whether access is granted.
+
+    X CAN DO Y ON RESOURCE Z
+
+    where …
+        X represents one or more users, roles, or groups, or a combination of them. You can
+        also use claims and context here.
+        Y represents an action to be performed, for example, write, view, and so on.
+        Z represents a protected resource, for example, "/accounts".
+
+    https://keycloak.gitbooks.io/documentation/authorization_services/topics/permission/overview.html
+
+    """
+
+    def __init__(self, name, type, logic, decision_strategy):
+        self._name = name
+        self._type = type
+        self._logic = logic
+        self._decision_strategy = decision_strategy
+        self._resources = []
+        self._scopes = []
+
+    def __repr__(self):
+        return "<Permission: %s (%s)>" % (self.name, self.type)
+
+    def __str__(self):
+        return "Permission: %s (%s)" % (self.name, self.type)
+
+    @property
+    def name(self):
+        return self._name
+
+    @name.setter
+    def name(self, value):
+        self._name = value
+
+    @property
+    def type(self):
+        return self._type
+
+    @type.setter
+    def type(self, value):
+        self._type = value
+
+    @property
+    def logic(self):
+        return self._logic
+
+    @logic.setter
+    def logic(self, value):
+        self._logic = value
+
+    @property
+    def decision_strategy(self):
+        return self._decision_strategy
+
+    @decision_strategy.setter
+    def decision_strategy(self, value):
+        self._decision_strategy = value
+
+    @property
+    def resources(self):
+        return self._resources
+
+    @resources.setter
+    def resources(self, value):
+        self._resources = value
+
+    @property
+    def scopes(self):
+        return self._scopes
+
+    @scopes.setter
+    def scopes(self, value):
+        self._scopes = value
+
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/policy.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/policy.py
new file mode 100644
index 0000000000000000000000000000000000000000..66512bac3a5a0a7efe77f7118f09910535992335
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/policy.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from ..exceptions import KeycloakAuthorizationConfigError
+
+
+class Policy:
+    """
+    A policy defines the conditions that must be satisfied to grant access to an object.
+    Unlike permissions, you do not specify the object being protected but rather the conditions
+    that must be satisfied for access to a given object (for example, resource, scope, or both).
+    Policies are strongly related to the different access control mechanisms (ACMs) that you can use to
+    protect your resources. With policies, you can implement strategies for attribute-based access control
+    (ABAC), role-based access control (RBAC), context-based access control, or any combination of these.
+
+    https://keycloak.gitbooks.io/documentation/authorization_services/topics/policy/overview.html
+
+    """
+
+    def __init__(self, name, type, logic, decision_strategy):
+        self._name = name
+        self._type = type
+        self._logic = logic
+        self._decision_strategy = decision_strategy
+        self._roles = []
+        self._permissions = []
+
+    def __repr__(self):
+        return "<Policy: %s (%s)>" % (self.name, self.type)
+
+    def __str__(self):
+        return "Policy: %s (%s)" % (self.name, self.type)
+
+    @property
+    def name(self):
+        return self._name
+
+    @name.setter
+    def name(self, value):
+        self._name = value
+
+    @property
+    def type(self):
+        return self._type
+
+    @type.setter
+    def type(self, value):
+        self._type = value
+
+    @property
+    def logic(self):
+        return self._logic
+
+    @logic.setter
+    def logic(self, value):
+        self._logic = value
+
+    @property
+    def decision_strategy(self):
+        return self._decision_strategy
+
+    @decision_strategy.setter
+    def decision_strategy(self, value):
+        self._decision_strategy = value
+
+    @property
+    def roles(self):
+        return self._roles
+
+    @property
+    def permissions(self):
+        return self._permissions
+
+    def add_role(self, role):
+        """
+        Add keycloak role in policy.
+
+        :param role: keycloak role.
+        :return:
+        """
+        if self.type != 'role':
+            raise KeycloakAuthorizationConfigError(
+                "Can't add role. Policy type is different of role")
+        self._roles.append(role)
+
+    def add_permission(self, permission):
+        """
+        Add keycloak permission in policy.
+
+        :param permission: keycloak permission.
+        :return:
+        """
+        self._permissions.append(permission)
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/role.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/role.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d398b09ee0565f2b89e2e899a02c9ec01609cf7
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/authorization/role.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+class Role:
+    """
+    Roles identify a type or category of user. Admin, user,
+    manager, and employee are all typical roles that may exist in an organization.
+
+    https://keycloak.gitbooks.io/documentation/server_admin/topics/roles.html
+
+    """
+
+    def __init__(self, name, required=False):
+        self.name = name
+        self.required = required
+
+    @property
+    def get_name(self):
+        return self.name
+
+    def __eq__(self, other):
+        if isinstance(other, str):
+            return self.name == other
+        return NotImplemented
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/connection.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..503b688a7f11435ece97aee23b0769c651602584
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/connection.py
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+try:
+    from urllib.parse import urljoin
+except ImportError:
+    from urlparse import urljoin
+
+from .exceptions import *
+import requests
+
+
+class ConnectionManager(object):
+    """ Represents a simple server connection.
+    Args:
+        base_url (str): The server URL.
+        headers (dict): The header parameters of the requests to the server.
+        timeout (int): Timeout to use for requests to the server.
+        verify (bool): Verify server SSL.
+    """
+
+    def __init__(self, base_url, headers={}, timeout=60, verify=True):
+        self._base_url = base_url
+        self._headers = headers
+        self._timeout = timeout
+        self._verify = verify
+
+    @property
+    def base_url(self):
+        """ Return base url in use for requests to the server. """
+        return self._base_url
+
+    @base_url.setter
+    def base_url(self, value):
+        """ """
+        self._base_url = value
+
+    @property
+    def timeout(self):
+        """ Return timeout in use for request to the server. """
+        return self._timeout
+
+    @timeout.setter
+    def timeout(self, value):
+        """ """
+        self._timeout = value
+
+    @property
+    def verify(self):
+        """ Return verify in use for request to the server. """
+        return self._verify
+
+    @verify.setter
+    def verify(self, value):
+        """ """
+        self._verify = value
+
+    @property
+    def headers(self):
+        """ Return header request to the server. """
+        return self._headers
+
+    @headers.setter
+    def headers(self, value):
+        """ """
+        self._headers = value
+
+    def param_headers(self, key):
+        """ Return a specific header parameter.
+        :arg
+            key (str): Header parameters key.
+        :return:
+            If the header parameters exist, return its value.
+        """
+        return self.headers.get(key)
+
+    def clean_headers(self):
+        """ Clear header parameters. """
+        self.headers = {}
+
+    def exist_param_headers(self, key):
+        """ Check if the parameter exists in the header.
+        :arg
+            key (str): Header parameters key.
+        :return:
+            If the header parameters exist, return True.
+        """
+        return self.param_headers(key) is not None
+
+    def add_param_headers(self, key, value):
+        """ Add a single parameter inside the header.
+        :arg
+            key (str): Header parameters key.
+            value (str): Value to be added.
+        """
+        self.headers[key] = value
+
+    def del_param_headers(self, key):
+        """ Remove a specific parameter.
+        :arg
+            key (str): Key of the header parameters.
+        """
+        self.headers.pop(key, None)
+
+    def raw_get(self, path, **kwargs):
+        """ Submit get request to the path.
+        :arg
+            path (str): Path for request.
+        :return
+            Response the request.
+        :exception
+            HttpError: Can't connect to server.
+        """
+
+        try:
+            return requests.get(urljoin(self.base_url, path),
+                                params=kwargs,
+                                headers=self.headers,
+                                timeout=self.timeout,
+                                verify=self.verify)
+        except Exception as e:
+            raise KeycloakConnectionError(
+                "Can't connect to server (%s)" % e)
+
+    def raw_post(self, path, data, **kwargs):
+        """ Submit post request to the path.
+        :arg
+            path (str): Path for request.
+            data (dict): Payload for request.
+        :return
+            Response the request.
+        :exception
+            HttpError: Can't connect to server.
+        """
+        try:
+            return requests.post(urljoin(self.base_url, path),
+                                 params=kwargs,
+                                 data=data,
+                                 headers=self.headers,
+                                 timeout=self.timeout,
+                                 verify=self.verify)
+        except Exception as e:
+            raise KeycloakConnectionError(
+                "Can't connect to server (%s)" % e)
+
+    def raw_put(self, path, data, **kwargs):
+        """ Submit put request to the path.
+        :arg
+            path (str): Path for request.
+            data (dict): Payload for request.
+        :return
+            Response the request.
+        :exception
+            HttpError: Can't connect to server.
+        """
+        try:
+            return requests.put(urljoin(self.base_url, path),
+                                params=kwargs,
+                                data=data,
+                                headers=self.headers,
+                                timeout=self.timeout,
+                                verify=self.verify)
+        except Exception as e:
+            raise KeycloakConnectionError(
+                "Can't connect to server (%s)" % e)
+
+    def raw_delete(self, path, **kwargs):
+        """ Submit delete request to the path.
+
+        :arg
+            path (str): Path for request.
+        :return
+            Response the request.
+        :exception
+            HttpError: Can't connect to server.
+        """
+        try:
+            return requests.delete(urljoin(self.base_url, path),
+                                   params=kwargs,
+                                   headers=self.headers,
+                                   timeout=self.timeout,
+                                   verify=self.verify)
+        except Exception as e:
+            raise KeycloakConnectionError(
+                "Can't connect to server (%s)" % e)
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/exceptions.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..27d8b14c156086b3de650a4248c4bf09c5cc27c3
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/exceptions.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import requests
+
+
+class KeycloakError(Exception):
+    def __init__(self, error_message="", response_code=None,
+                 response_body=None):
+
+        Exception.__init__(self, error_message)
+
+        self.response_code = response_code
+        self.response_body = response_body
+        self.error_message = error_message
+
+    def __str__(self):
+        if self.response_code is not None:
+            return "{0}: {1}".format(self.response_code, self.error_message)
+        else:
+            return "{0}".format(self.error_message)
+
+
+class KeycloakAuthenticationError(KeycloakError):
+    pass
+
+
+class KeycloakConnectionError(KeycloakError):
+    pass
+
+
+class KeycloakOperationError(KeycloakError):
+    pass
+
+
+class KeycloakGetError(KeycloakOperationError):
+    pass
+
+
+class KeycloakSecretNotFound(KeycloakOperationError):
+    pass
+
+
+class KeycloakRPTNotFound(KeycloakOperationError):
+    pass
+
+
+class KeycloakAuthorizationConfigError(KeycloakOperationError):
+    pass
+
+
+class KeycloakInvalidTokenError(KeycloakOperationError):
+    pass
+
+
+def raise_error_from_response(response, error, expected_code=200):
+
+    if expected_code == response.status_code:
+        if expected_code == requests.codes.no_content:
+            return {}
+        try:
+            return response.json()
+        except ValueError:
+            return response.content
+
+    try:
+        message = response.json()['message']
+    except (KeyError, ValueError):
+        message = response.content
+
+    if isinstance(error, dict):
+        error = error.get(response.status_code, KeycloakOperationError)
+    else:
+        if response.status_code == 401:
+            error = KeycloakAuthenticationError
+
+    raise error(error_message=message,
+                response_code=response.status_code,
+                response_body=response.content)
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_admin.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..79f5c2c6d319fb9cfbe40f8e53ab25a01128e2b6
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_admin.py
@@ -0,0 +1,670 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Unless otherwise stated in the comments, "id", in e.g. user_id, refers to the
+# internal Keycloak server ID, usually a uuid string
+from keycloak.urls_patterns import URL_ADMIN_CLIENT_ROLE
+from .urls_patterns import \
+    URL_ADMIN_USERS_COUNT, URL_ADMIN_USER, URL_ADMIN_USER_CONSENTS, \
+    URL_ADMIN_SEND_UPDATE_ACCOUNT, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_VERIFY_EMAIL, URL_ADMIN_GET_SESSIONS, \
+    URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENTS, URL_ADMIN_CLIENT, URL_ADMIN_CLIENT_ROLES, URL_ADMIN_REALM_ROLES, \
+    URL_ADMIN_GROUP, URL_ADMIN_GROUPS, URL_ADMIN_GROUP_CHILD, URL_ADMIN_USER_GROUP,\
+    URL_ADMIN_GROUP_PERMISSIONS, URL_ADMIN_USER_CLIENT_ROLES, URL_ADMIN_USER_STORAGE, URL_ADMIN_REALM
+
+from .keycloak_openid import KeycloakOpenID
+
+from .exceptions import raise_error_from_response, KeycloakGetError
+
+from .urls_patterns import (
+    URL_ADMIN_USERS,
+)
+
+from .connection import ConnectionManager
+import json
+
+
+class KeycloakAdmin:
+
+    def __init__(self, server_url, username, password, realm_name='master', client_id='admin-cli', verify=True):
+        """
+
+        :param server_url: Keycloak server url
+        :param username: admin username
+        :param password: admin password
+        :param realm_name: realm name
+        :param client_id: client id
+        :param verify: True if want check connection SSL
+        """
+        self._username = username
+        self._password = password
+        self._client_id = client_id
+        self._realm_name = realm_name
+
+        # Get token Admin
+        keycloak_openid = KeycloakOpenID(server_url=server_url, client_id=client_id, realm_name=realm_name,
+                                         verify=verify)
+        self._token = keycloak_openid.token(username, password)
+
+        self._connection = ConnectionManager(base_url=server_url,
+                                             headers={'Authorization': 'Bearer ' + self.token.get('access_token'),
+                                                      'Content-Type': 'application/json'},
+                                             timeout=60,
+                                             verify=verify)
+
+    @property
+    def realm_name(self):
+        return self._realm_name
+
+    @realm_name.setter
+    def realm_name(self, value):
+        self._realm_name = value
+
+    @property
+    def connection(self):
+        return self._connection
+
+    @connection.setter
+    def connection(self, value):
+        self._connection = value
+
+    @property
+    def client_id(self):
+        return self._client_id
+
+    @client_id.setter
+    def client_id(self, value):
+        self._client_id = value
+
+    @property
+    def username(self):
+        return self._username
+
+    @username.setter
+    def username(self, value):
+        self._username = value
+
+    @property
+    def password(self):
+        return self._password
+
+    @password.setter
+    def password(self, value):
+        self._password = value
+
+    @property
+    def token(self):
+        return self._token
+
+    @token.setter
+    def token(self, value):
+        self._token = value
+
+    def get_users(self, query=None):
+        """
+        Get users Returns a list of users, filtered according to query parameters
+
+        :return: users list
+        """
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_ADMIN_USERS.format(**params_path), **query)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def create_user(self, payload):
+        """
+        Create a new user Username must be unique
+
+        UserRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_userrepresentation
+
+        :param payload: UserRepresentation
+
+        :return: UserRepresentation
+        """
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_post(URL_ADMIN_USERS.format(**params_path),
+                                            data=json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201)
+
+    def users_count(self):
+        """
+        User counter
+
+        :return: counter
+        """
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_ADMIN_USERS_COUNT.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_user_id(self, username):
+        """
+        Get internal keycloak user id from username
+        This is required for further actions against this user.
+
+        UserRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_userrepresentation
+
+        :param username: id in UserRepresentation
+
+        :return: user_id
+        """
+        params_path = {"realm-name": self.realm_name, "username": username}
+        data_raw = self.connection.raw_get(URL_ADMIN_USERS.format(**params_path))
+        data_content = raise_error_from_response(data_raw, KeycloakGetError)
+
+        for user in data_content:
+            this_use_rname = json.dumps(user["username"]).strip('"')
+            if this_use_rname == username:
+                return json.dumps(user["id"]).strip('"')
+
+        return None
+
+    def get_user(self, user_id):
+        """
+        Get representation of the user
+
+        :param user_id: User id
+
+        UserRepresentation: http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_userrepresentation
+
+        :return: UserRepresentation
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        data_raw = self.connection.raw_get(URL_ADMIN_USER.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def update_user(self, user_id, payload):
+        """
+        Update the user
+
+        :param user_id: User id
+        :param payload: UserRepresentation
+
+        :return: Http response
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        data_raw = self.connection.raw_put(URL_ADMIN_USER.format(**params_path),
+                                           data=json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def delete_user(self, user_id):
+        """
+        Delete the user
+
+        :param user_id: User id
+
+        :return: Http response
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        data_raw = self.connection.raw_delete(URL_ADMIN_USER.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def set_user_password(self, user_id, password, temporary=True):
+        """
+        Set up a password for the user. If temporary is True, the user will have to reset
+        the temporary password next time they log in.
+
+        http://www.keycloak.org/docs-api/3.2/rest-api/#_users_resource
+        http://www.keycloak.org/docs-api/3.2/rest-api/#_credentialrepresentation
+
+        :param user_id: User id
+        :param password: New password
+        :param temporary: True if password is temporary
+
+        :return:
+        """
+        payload = {"type": "password", "temporary": temporary, "value": password}
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        data_raw = self.connection.raw_put(URL_ADMIN_RESET_PASSWORD.format(**params_path),
+                                           data=json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def consents_user(self, user_id):
+        """
+        Get consents granted by the user
+
+        :param user_id: User id
+
+        :return: consents
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        data_raw = self.connection.raw_get(URL_ADMIN_USER_CONSENTS.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def send_update_account(self, user_id, payload, client_id=None, lifespan=None, redirect_uri=None):
+        """
+        Send a update account email to the user An email contains a
+        link the user can click to perform a set of required actions.
+
+        :param user_id:
+        :param payload:
+        :param client_id:
+        :param lifespan:
+        :param redirect_uri:
+
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        params_query = {"client_id": client_id, "lifespan": lifespan, "redirect_uri": redirect_uri}
+        data_raw = self.connection.raw_put(URL_ADMIN_SEND_UPDATE_ACCOUNT.format(**params_path),
+                                           data=payload, **params_query)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def send_verify_email(self, user_id, client_id=None, redirect_uri=None):
+        """
+        Send a update account email to the user An email contains a
+        link the user can click to perform a set of required actions.
+
+        :param user_id: User id
+        :param client_id: Client id
+        :param redirect_uri: Redirect uri
+
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        params_query = {"client_id": client_id, "redirect_uri": redirect_uri}
+        data_raw = self.connection.raw_put(URL_ADMIN_SEND_VERIFY_EMAIL.format(**params_path),
+                                           data={}, **params_query)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_sessions(self, user_id):
+        """
+        Get sessions associated with the user
+
+        :param user_id:  id of user
+
+        UserSessionRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_usersessionrepresentation
+
+        :return: UserSessionRepresentation
+        """
+        params_path = {"realm-name": self.realm_name, "id": user_id}
+        data_raw = self.connection.raw_get(URL_ADMIN_GET_SESSIONS.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_server_info(self):
+        """
+        Get themes, social providers, auth providers, and event listeners available on this server
+
+        ServerInfoRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_serverinforepresentation
+
+        :return: ServerInfoRepresentation
+        """
+        data_raw = self.connection.raw_get(URL_ADMIN_SERVER_INFO)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_groups(self):
+        """
+        Get groups belonging to the realm. Returns a list of groups belonging to the realm
+
+        GroupRepresentation
+        http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
+
+        :return: array GroupRepresentation
+        """
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_ADMIN_GROUPS.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_group(self, group_id):
+        """
+        Get group by id. Returns full group details
+
+        GroupRepresentation
+        http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
+
+        :return: Keycloak server response (GroupRepresentation)
+        """
+        params_path = {"realm-name": self.realm_name, "id": group_id}
+        data_raw = self.connection.raw_get(URL_ADMIN_GROUP.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_group_by_name(self, name_or_path, search_in_subgroups=False):
+        """
+        Get group id based on name or path.
+        A straight name or path match with a top-level group will return first.
+        Subgroups are traversed, the first to match path (or name with path) is returned.
+
+        GroupRepresentation
+        http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
+
+        :param name: group name
+        :param path: group path
+        :param search_in_subgroups: True if want search in the subgroups
+        :return: Keycloak server response (GroupRepresentation)
+        """
+
+        groups = self.get_groups()
+
+        # TODO: Review this code is necessary
+        for group in groups:
+            if group['name'] == name_or_path or group['path'] == name_or_path:
+                return group
+            elif search_in_subgroups and group["subGroups"]:
+                for subgroup in group["subGroups"]:
+                    if subgroup['name'] == name_or_path or subgroup['path'] == name_or_path:
+                        return subgroup
+
+        return None
+
+    def create_group(self, name=None, client_roles={}, realm_roles=[], sub_groups=[], path=None, parent=None):
+        """
+        Create a group in the Realm
+
+        GroupRepresentation
+        http://www.keycloak.org/docs-api/3.2/rest-api/#_grouprepresentation
+
+        :param name: group name
+        :param client_roles: (Dict) Client roles to include in groupp # Not demonstrated to work
+        :param realm_roles: (List) Realm roles to include in group # Not demonstrated to work
+        :param sub_groups: (List) Subgroups to include in groupp # Not demonstrated to work
+        :param path: group path
+        :param parent: parent group's id. Required to create a sub-group.
+
+        :return: Keycloak server response (GroupRepresentation)
+        """
+
+        data = {"name": name or path,
+                "path": path,
+                "clientRoles": client_roles,
+                "realmRoles": realm_roles,
+                "subGroups": sub_groups}
+
+        if parent is None:
+            params_path = {"realm-name": self.realm_name}
+            data_raw = self.connection.raw_post(URL_ADMIN_GROUPS.format(**params_path),
+                                                data=json.dumps(data))
+        else:
+            params_path = {"realm-name": self.realm_name, "id": parent}
+            data_raw = self.connection.raw_post(URL_ADMIN_GROUP_CHILD.format(**params_path),
+                                                data=json.dumps(data))
+
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201)
+
+    def group_set_permissions(self, group_id, enabled=True):
+        """
+        Enable/Disable permissions for a group. Cannot delete group if disabled
+
+        :param group_id: id of group
+        :param enabled: boolean
+        :return: Keycloak server response
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": group_id}
+        data_raw = self.connection.raw_put(URL_ADMIN_GROUP_PERMISSIONS.format(**params_path),
+                                           data=json.dumps({"enabled": enabled}))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def group_user_add(self, user_id, group_id):
+        """
+        Add user to group (user_id and group_id)
+
+        :param group_id:  id of group
+        :param user_id:  id of user
+        :param group_id:  id of group to add to
+        :return: Keycloak server response
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": user_id, "group-id": group_id}
+        data_raw = self.connection.raw_put(URL_ADMIN_USER_GROUP.format(**params_path), data=None)
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def group_user_remove(self, user_id, group_id):
+        """
+        Remove user from group (user_id and group_id)
+
+        :param group_id:  id of group
+        :param user_id:  id of user
+        :param group_id:  id of group to add to
+        :return: Keycloak server response
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": user_id, "group-id": group_id}
+        data_raw = self.connection.raw_delete(URL_ADMIN_USER_GROUP.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def delete_group(self, group_id):
+        """
+        Deletes a group in the Realm
+
+        :param group_id:  id of group to delete
+        :return: Keycloak server response
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": group_id}
+        data_raw = self.connection.raw_delete(URL_ADMIN_GROUP.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def get_clients(self):
+        """
+        Get clients belonging to the realm Returns a list of clients belonging to the realm
+
+        ClientRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
+
+        :return: Keycloak server response (ClientRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_ADMIN_CLIENTS.format(**params_path))
+        
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_client(self, client_id):
+        """
+        Get representation of the client
+
+        ClientRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
+
+        :param client_id:  id of client (not client-id)
+        :return: Keycloak server response (ClientRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": client_id}
+        data_raw = self.connection.raw_get(URL_ADMIN_CLIENT.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_client_id(self, client_name):
+        """
+        Get internal keycloak client id from client-id.
+        This is required for further actions against this client.
+
+        :param client_name: name in ClientRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
+        :return: client_id (uuid as string)
+        """
+
+        clients = self.get_clients()
+
+        for client in clients:
+            if client_name == client['name']:
+                return client["id"]
+
+        return None
+
+    def create_client(self, payload):
+        """
+        Create a client
+
+        ClientRepresentation: http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
+
+        :param payload: ClientRepresentation
+        :return:  Keycloak server response (UserRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_post(URL_ADMIN_CLIENTS.format(**params_path),
+                                            data=json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201)
+
+    def delete_client(self, client_id):
+        """
+        Get representation of the client
+
+        ClientRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_clientrepresentation
+
+        :param client_id: keycloak client id (not oauth client-id)
+        :return: Keycloak server response (ClientRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": client_id}
+        data_raw = self.connection.raw_delete(URL_ADMIN_CLIENT.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def get_realm_roles(self):
+        """
+        Get all roles for the realm or client
+
+        RoleRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
+
+        :return: Keycloak server response (RoleRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_ADMIN_REALM_ROLES.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_client_roles(self, client_id):
+        """
+        Get all roles for the client
+
+        :param client_id: id of client (not client-id)
+
+        RoleRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
+
+        :return: Keycloak server response (RoleRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": client_id}
+        data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ROLES.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_client_role(self, client_id, role_name):
+        """
+        Get client role id by name
+        This is required for further actions with this role.
+
+        :param client_id: id of client (not client-id)
+        :param role_name: role’s name (not id!)
+
+        RoleRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
+
+        :return: role_id
+        """
+        params_path = {"realm-name": self.realm_name, "id": client_id, "role-name": role_name}
+        data_raw = self.connection.raw_get(URL_ADMIN_CLIENT_ROLE.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def get_client_role_id(self, client_id, role_name):
+        """
+        Warning: Deprecated
+
+        Get client role id by name
+        This is required for further actions with this role.
+
+        :param client_id: id of client (not client-id)
+        :param role_name: role’s name (not id!)
+
+        RoleRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
+
+        :return: role_id
+        """
+        role = self.get_client_role(client_id, role_name)
+        return role.get("id")
+
+    def create_client_role(self, payload):
+        """
+        Create a client role
+
+        RoleRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
+
+        :param payload: id of client (not client-id), role_name: name of role
+        :return: Keycloak server response (RoleRepresentation)
+        """
+
+        params_path = {"realm-name": self.realm_name, "id": self.client_id}
+        data_raw = self.connection.raw_post(URL_ADMIN_CLIENT_ROLES.format(**params_path),
+                                            data=json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201)
+
+    def delete_client_role(self, role_name):
+        """
+        Create a client role
+
+        RoleRepresentation
+        http://www.keycloak.org/docs-api/3.3/rest-api/index.html#_rolerepresentation
+
+        :param role_name: role’s name (not id!)
+        """
+        params_path = {"realm-name": self.realm_name, "id": self.client_id, "role-name": role_name}
+        data_raw = self.connection.raw_delete(URL_ADMIN_CLIENT_ROLE.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def assign_client_role(self, user_id, client_id, roles):
+        """
+        Assign a client role to a user
+
+        :param client_id: id of client (not client-id)
+        :param user_id: id of user
+        :param client_id: id of client containing role,
+        :param roles: roles list or role (use RoleRepresentation)
+        :return Keycloak server response
+        """
+
+        payload = roles if isinstance(roles, list) else [roles]
+        params_path = {"realm-name": self.realm_name, "id": user_id, "client-id": client_id}
+        data_raw = self.connection.raw_post(URL_ADMIN_USER_CLIENT_ROLES.format(**params_path),
+                                            data=json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def sync_users(self, storage_id, action):
+        """
+        Function to trigger user sync from provider
+
+        :param storage_id:
+        :param action:
+        :return:
+        """
+        data = {'action': action}
+        params_query = {"action": action}
+
+        params_path = {"realm-name": self.realm_name, "id": storage_id}
+        data_raw = self.connection.raw_post(URL_ADMIN_USER_STORAGE.format(**params_path),
+                                            data=json.dumps(data), **params_query)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def import_realm(self, payload):
+        """
+        Imports a realm from a full representation of that realm
+
+        Realmrepresentation
+        http://www.keycloak.org/docs-api/2.5/rest-api/index.html#_import_a_realm
+
+        :param payload: Realmrepresentation
+
+        :return: Realmrepresentation
+        """
+        data_raw = self.connection.raw_post(URL_ADMIN_REALM, 
+                                            data = json.dumps(payload))
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201)
\ No newline at end of file
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_main.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_main.py
new file mode 100644
index 0000000000000000000000000000000000000000..109852154530cabd2d661524406492004430befb
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_main.py
@@ -0,0 +1,79 @@
+import json
+
+from keycloak import KeycloakOpenID
+from keycloak import KeycloakAdmin
+import urllib2, argparse, json
+
+# Import realm
+def keycloak_import_realm(keycloak_realm_file):
+    data = json.load(open(keycloak_realm_file))
+    realm_import = keycloak_admin.import_realm(data)
+
+# Add user and set password
+def keycloak_create_user(email, username, firstName, lastName, password):
+    new_user = keycloak_admin.create_user({"email": email,
+                    "username": username,
+                    "emailVerified": True,
+                    "enabled": True,
+                    "firstName": firstName,
+                    "lastName": lastName,
+                    "credentials": [{"value": "12345","type": password}],
+                    "realmRoles": ["user_default"]})
+
+# Create the user and assign the role to access the user management API
+def update_user_roles(config):
+    realm_json = json.load(open(config['keycloak_realm_json_file_path']))
+    clientId = "realm-management"
+
+    for client in realm_json['clients']:
+        if clientId == client['clientId']:
+            client_id = client["id"]
+            break
+
+    user = keycloak_admin.get_users({"username":config['keycloak_api_management_username']})
+    user_id = user[0]['id'];
+
+    # Read the role from file
+    with open(config['keycloak_user_manager_roles_json_file_path'], 'r') as data_file:
+        json_data = data_file.read()
+
+    roles = json.loads(json_data)
+    keycloak_admin.assign_client_role(user_id, client_id, roles)
+
+
+if  __name__ == "__main__":
+    parser = argparse.ArgumentParser(description='Configure keycloak user apis')
+    parser.add_argument('keycloak_bootstrap_config', help='keycloak server url')
+    args = parser.parse_args()
+
+    with open(args.keycloak_bootstrap_config) as keycloak_bootstrap_config:
+        config = json.load(keycloak_bootstrap_config)
+
+    try:
+        # Get access token
+        keycloak_admin = KeycloakAdmin(server_url=config['keycloak_auth_server_url'],
+                            username=config['keycloak_management_user'],
+                            password=config['keycloak_management_password'],
+                            realm_name="master",
+                            client_id='admin-cli',
+                            verify=False)
+        # Import realm
+        keycloak_import_realm(config['keycloak_realm_json_file_path'])
+
+        # Set realm name to sunbird
+        keycloak_admin.realm_name = config['keycloak_realm']
+
+        # Add user for user api
+        keycloak_create_user(email=config['keycloak_api_management_user_email'],
+            username=config['keycloak_api_management_username'],
+            firstName=config['keycloak_api_management_user_first_name'],
+            lastName=config['keycloak_api_management_user_last_name'],
+            password=config['keycloak_api_management_user_password'])
+
+        # Update user roles for access user management API's
+        update_user_roles(config)
+
+    except urllib2.HTTPError as e:
+        error_message = e.read()
+        print error_message
+        raise
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_openid.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_openid.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1dcde44e32b46848ed5dcc0a1de8a4220e24854
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/keycloak_openid.py
@@ -0,0 +1,390 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from .authorization import Authorization
+from .exceptions import raise_error_from_response, KeycloakGetError, \
+    KeycloakRPTNotFound, KeycloakAuthorizationConfigError, KeycloakInvalidTokenError
+from .urls_patterns import (
+    URL_TOKEN,
+    URL_USERINFO,
+    URL_WELL_KNOWN,
+    URL_LOGOUT,
+    URL_CERTS,
+    URL_ENTITLEMENT,
+    URL_INTROSPECT
+)
+from .connection import ConnectionManager
+from jose import jwt
+import json
+
+
+class KeycloakOpenID:
+
+    def __init__(self, server_url, realm_name, client_id, client_secret_key=None, verify=True):
+        """
+
+        :param server_url: Keycloak server url
+        :param client_id: client id
+        :param realm_name: realm name
+        :param client_secret_key: client secret key
+        :param verify: True if want check connection SSL
+        """
+        self._client_id = client_id
+        self._client_secret_key = client_secret_key
+        self._realm_name = realm_name
+        self._connection = ConnectionManager(base_url=server_url,
+                                             headers={},
+                                             timeout=60,
+                                             verify=verify)
+
+        self._authorization = Authorization()
+
+    @property
+    def client_id(self):
+        return self._client_id
+
+    @client_id.setter
+    def client_id(self, value):
+        self._client_id = value
+
+    @property
+    def client_secret_key(self):
+        return self._client_secret_key
+
+    @client_secret_key.setter
+    def client_secret_key(self, value):
+        self._client_secret_key = value
+
+    @property
+    def realm_name(self):
+        return self._realm_name
+
+    @realm_name.setter
+    def realm_name(self, value):
+        self._realm_name = value
+
+    @property
+    def connection(self):
+        return self._connection
+
+    @connection.setter
+    def connection(self, value):
+        self._connection = value
+
+    @property
+    def authorization(self):
+        return self._authorization
+
+    @authorization.setter
+    def authorization(self, value):
+        self._authorization = value
+
+    def _add_secret_key(self, payload):
+        """
+        Add secret key if exist.
+
+        :param payload:
+        :return:
+        """
+        if self.client_secret_key:
+            payload.update({"client_secret": self.client_secret_key})
+
+        return payload
+
+    def _build_name_role(self, role):
+        """
+
+        :param role:
+        :return:
+        """
+        return self.client_id + "/" + role
+
+    def _token_info(self, token, method_token_info, **kwargs):
+        """
+
+        :param token:
+        :param method_token_info:
+        :param kwargs:
+        :return:
+        """
+        if method_token_info == 'introspect':
+            token_info = self.introspect(token)
+        else:
+            token_info = self.decode_token(token, **kwargs)
+
+        return token_info
+
+    def well_know(self):
+        """ The most important endpoint to understand is the well-known configuration
+            endpoint. It lists endpoints and other configuration options relevant to
+            the OpenID Connect implementation in Keycloak.
+
+            :return It lists endpoints and other configuration options relevant.
+        """
+
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_WELL_KNOWN.format(**params_path))
+
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def auth_url(self, redirect_uri):
+        """
+
+        http://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
+
+        :return:
+        """
+        return NotImplemented
+
+    def token(self, username, password, grant_type=["password"]):
+        """
+        The token endpoint is used to obtain tokens. Tokens can either be obtained by
+        exchanging an authorization code or by supplying credentials directly depending on
+        what flow is used. The token endpoint is also used to obtain new access tokens
+        when they expire.
+
+        http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
+
+        :param username:
+        :param password:
+        :param grant_type:
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name}
+        payload = {"username": username, "password": password,
+                   "client_id": self.client_id, "grant_type": grant_type}
+
+        payload = self._add_secret_key(payload)
+        data_raw = self.connection.raw_post(URL_TOKEN.format(**params_path),
+                                            data=payload)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def refresh_token(self, refresh_token, grant_type=["refresh_token"]):
+        """
+        The token endpoint is used to obtain tokens. Tokens can either be obtained by
+        exchanging an authorization code or by supplying credentials directly depending on
+        what flow is used. The token endpoint is also used to obtain new access tokens
+        when they expire.
+
+        http://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
+
+        :param refresh_token:
+        :param grant_type:
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name}
+        payload = {"client_id": self.client_id, "grant_type": grant_type, "refresh_token": refresh_token}
+        payload = self._add_secret_key(payload)
+        data_raw = self.connection.raw_post(URL_TOKEN.format(**params_path),
+                                            data=payload)
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def userinfo(self, token):
+        """
+        The userinfo endpoint returns standard claims about the authenticated user,
+        and is protected by a bearer token.
+
+        http://openid.net/specs/openid-connect-core-1_0.html#UserInfo
+
+        :param token:
+        :return:
+        """
+
+        self.connection.add_param_headers("Authorization", "Bearer " + token)
+        params_path = {"realm-name": self.realm_name}
+
+        data_raw = self.connection.raw_get(URL_USERINFO.format(**params_path))
+
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def logout(self, refresh_token):
+        """
+        The logout endpoint logs out the authenticated user.
+        :param refresh_token:
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name}
+        payload = {"client_id": self.client_id, "refresh_token": refresh_token}
+
+        payload = self._add_secret_key(payload)
+        data_raw = self.connection.raw_post(URL_LOGOUT.format(**params_path),
+                                            data=payload)
+
+        return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
+
+    def certs(self):
+        """
+        The certificate endpoint returns the public keys enabled by the realm, encoded as a
+        JSON Web Key (JWK). Depending on the realm settings there can be one or more keys enabled
+        for verifying tokens.
+
+        https://tools.ietf.org/html/rfc7517
+
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name}
+        data_raw = self.connection.raw_get(URL_CERTS.format(**params_path))
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def entitlement(self, token, resource_server_id):
+        """
+        Client applications can use a specific endpoint to obtain a special security token
+        called a requesting party token (RPT). This token consists of all the entitlements
+        (or permissions) for a user as a result of the evaluation of the permissions and authorization
+        policies associated with the resources being requested. With an RPT, client applications can
+        gain access to protected resources at the resource server.
+
+        :return:
+        """
+        self.connection.add_param_headers("Authorization", "Bearer " + token)
+        params_path = {"realm-name": self.realm_name, "resource-server-id": resource_server_id}
+        data_raw = self.connection.raw_get(URL_ENTITLEMENT.format(**params_path))
+
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def introspect(self, token, rpt=None, token_type_hint=None):
+        """
+        The introspection endpoint is used to retrieve the active state of a token. It is can only be
+        invoked by confidential clients.
+
+        https://tools.ietf.org/html/rfc7662
+
+        :param token:
+        :param rpt:
+        :param token_type_hint:
+
+        :return:
+        """
+        params_path = {"realm-name": self.realm_name}
+
+        payload = {"client_id": self.client_id, "token": token}
+
+        if token_type_hint == 'requesting_party_token':
+            if rpt:
+                payload.update({"token": rpt, "token_type_hint": token_type_hint})
+                self.connection.add_param_headers("Authorization", "Bearer " + token)
+            else:
+                raise KeycloakRPTNotFound("Can't found RPT.")
+
+        payload = self._add_secret_key(payload)
+
+        data_raw = self.connection.raw_post(URL_INTROSPECT.format(**params_path),
+                                            data=payload)
+
+        return raise_error_from_response(data_raw, KeycloakGetError)
+
+    def decode_token(self, token, key, algorithms=['RS256'], **kwargs):
+        """
+        A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data
+        structure that represents a cryptographic key.  This specification
+        also defines a JWK Set JSON data structure that represents a set of
+        JWKs.  Cryptographic algorithms and identifiers for use with this
+        specification are described in the separate JSON Web Algorithms (JWA)
+        specification and IANA registries established by that specification.
+
+        https://tools.ietf.org/html/rfc7517
+
+        :param token:
+        :param key:
+        :param algorithms:
+        :return:
+        """
+
+        return jwt.decode(token, key, algorithms=algorithms,
+                          audience=self.client_id, **kwargs)
+
+    def load_authorization_config(self, path):
+        """
+        Load Keycloak settings (authorization)
+
+        :param path: settings file (json)
+        :return:
+        """
+        authorization_file = open(path, 'r')
+        authorization_json = json.loads(authorization_file.read())
+        self.authorization.load_config(authorization_json)
+        authorization_file.close()
+
+    def get_policies(self, token, method_token_info='introspect', **kwargs):
+        """
+        Get policies by user token
+
+        :param token: user token
+        :return: policies list
+        """
+
+        if not self.authorization.policies:
+            raise KeycloakAuthorizationConfigError(
+                "Keycloak settings not found. Load Authorization Keycloak settings."
+            )
+
+        token_info = self._token_info(token, method_token_info, **kwargs)
+
+        if method_token_info == 'introspect' and not token_info['active']:
+            raise KeycloakInvalidTokenError(
+                "Token expired or invalid."
+            )
+
+        user_resources = token_info['resource_access'].get(self.client_id)
+
+        if not user_resources:
+            return None
+
+        policies = []
+
+        for policy_name, policy in self.authorization.policies.items():
+            for role in user_resources['roles']:
+                if self._build_name_role(role) in policy.roles:
+                    policies.append(policy)
+
+        return list(set(policies))
+
+    def get_permissions(self, token, method_token_info='introspect', **kwargs):
+        """
+        Get permission by user token
+
+        :param token: user token
+        :param method_token_info: Decode token method
+        :param kwargs: parameters for decode
+        :return: permissions list
+        """
+
+        if not self.authorization.policies:
+            raise KeycloakAuthorizationConfigError(
+                "Keycloak settings not found. Load Authorization Keycloak settings."
+            )
+
+        token_info = self._token_info(token, method_token_info, **kwargs)
+
+        if method_token_info == 'introspect' and not token_info['active']:
+            raise KeycloakInvalidTokenError(
+                "Token expired or invalid."
+            )
+
+        user_resources = token_info['resource_access'].get(self.client_id)
+
+        if not user_resources:
+            return None
+
+        permissions = []
+
+        for policy_name, policy in self.authorization.policies.items():
+            for role in user_resources['roles']:
+                if self._build_name_role(role) in policy.roles:
+                    permissions += policy.permissions
+
+        return list(set(permissions))
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/PKG-INFO b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..e98a1ee3c0a656997e8a87a4d92881f1c17cd0f3
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/PKG-INFO
@@ -0,0 +1,18 @@
+Metadata-Version: 1.1
+Name: python-keycloak
+Version: 0.12.0
+Summary: python-keycloak is a Python package providing access to the Keycloak API.
+Home-page: https://bitbucket.org/agriness/python-keycloak
+Author: Marcos Pereira
+Author-email: marcospereira.mpj@gmail.com
+License: GNU General Public License - V3
+Description: UNKNOWN
+Keywords: keycloak openid
+Platform: UNKNOWN
+Classifier: Programming Language :: Python :: 3
+Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
+Classifier: Development Status :: 3 - Alpha
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: Unix
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Topic :: Utilities
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/SOURCES.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/SOURCES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/dependency_links.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/dependency_links.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/requires.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/requires.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d6eafdf65702ff256e75b81a0f7fbdbcc975e899
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/requires.txt
@@ -0,0 +1,3 @@
+requests==2.18.4
+httmock==1.2.5
+python-jose==1.4.0
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/top_level.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..26c07c1da4a50b7acffbd55aa039a9d4e0d27494
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/python_keycloak.egg-info/top_level.txt
@@ -0,0 +1 @@
+keycloak
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/tests/__init__.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/tests/test_connection.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/tests/test_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..97ec1792dfa5312c4b6c5d2fa4563e7577a3037a
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/tests/test_connection.py
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from httmock import urlmatch, response, HTTMock, all_requests
+
+from ..connection import ConnectionManager
+
+
+try:
+    import unittest
+except ImportError:
+    import unittest2 as unittest
+
+    
+class TestConnection(unittest.TestCase):
+    
+    def setUp(self):
+        self._conn = ConnectionManager(
+                            base_url="http://localhost:8080/",
+                            headers={}, 
+                            timeout=60)
+
+    @all_requests
+    def response_content_success(self, url, request):
+        headers = {'content-type': 'application/json'}
+        content = b'response_ok'
+        return response(200, content, headers, None, 5, request)
+        
+    def test_raw_get(self):            
+        with HTTMock(self.response_content_success):
+            resp = self._conn.raw_get("/known_path")
+        self.assertEqual(resp.content, b'response_ok')
+        self.assertEqual(resp.status_code, 200) 
+
+    def test_raw_post(self):
+
+        @urlmatch(path="/known_path", method="post")
+        def response_post_success(url, request):
+            headers = {'content-type': 'application/json'}
+            content = 'response'.encode("utf-8")
+            return response(201, content, headers, None, 5, request)
+                 
+        with HTTMock(response_post_success):
+            resp = self._conn.raw_post("/known_path",
+                                        {'field': 'value'})
+        self.assertEqual(resp.content, b'response')
+        self.assertEqual(resp.status_code, 201)
+
+    def test_raw_put(self):
+        @urlmatch(netloc="localhost", path="/known_path", method="put")
+        def response_put_success(url, request):
+            headers = {'content-type': 'application/json'}
+            content = 'response'.encode("utf-8")
+            return response(200, content, headers, None, 5, request)
+
+        with HTTMock(response_put_success):
+            resp = self._conn.raw_put("/known_path",
+                                       {'field': 'value'})
+        self.assertEqual(resp.content, b'response')
+        self.assertEqual(resp.status_code, 200)
+
+    def test_raw_get_fail(self):
+
+        @urlmatch(netloc="localhost", path="/known_path", method="get")
+        def response_get_fail(url, request):
+            headers = {'content-type': 'application/json'}
+            content = "404 page not found".encode("utf-8")
+            return response(404, content, headers, None, 5, request)
+                 
+        with HTTMock(response_get_fail):
+            resp = self._conn.raw_get("/known_path")
+
+        self.assertEqual(resp.content, b"404 page not found")
+        self.assertEqual(resp.status_code, 404)   
+        
+    def test_raw_post_fail(self):
+
+        @urlmatch(netloc="localhost", path="/known_path", method="post")
+        def response_post_fail(url, request):
+            headers = {'content-type': 'application/json'}
+            content = str(["Start can't be blank"]).encode("utf-8")
+            return response(404, content, headers, None, 5, request)
+                 
+        with HTTMock(response_post_fail):
+            resp = self._conn.raw_post("/known_path",
+                                       {'field': 'value'})
+        self.assertEqual(resp.content, str(["Start can't be blank"]).encode("utf-8"))
+        self.assertEqual(resp.status_code, 404)
+
+    def test_raw_put_fail(self):
+
+        @urlmatch(netloc="localhost", path="/known_path", method="put")
+        def response_put_fail(url, request):
+            headers = {'content-type': 'application/json'}
+            content = str(["Start can't be blank"]).encode("utf-8")
+            return response(404, content, headers, None, 5, request)
+
+        with HTTMock(response_put_fail):
+            resp = self._conn.raw_put("/known_path",
+                                      {'field': 'value'})
+        self.assertEqual(resp.content, str(["Start can't be blank"]).encode("utf-8"))
+        self.assertEqual(resp.status_code, 404)
+
+    def test_add_param_headers(self):
+        self._conn.add_param_headers("test", "value")
+        self.assertEqual(self._conn.headers,
+                         {"test": "value"})
+
+    def test_del_param_headers(self):
+        self._conn.add_param_headers("test", "value")
+        self._conn.del_param_headers("test")
+        self.assertEqual(self._conn.headers, {})
+    
+    def test_clean_param_headers(self):
+        self._conn.add_param_headers("test", "value")
+        self.assertEqual(self._conn.headers,
+                         {"test": "value"})
+        self._conn.clean_headers()
+        self.assertEqual(self._conn.headers, {})
+
+    def test_exist_param_headers(self):
+        self._conn.add_param_headers("test", "value")
+        self.assertTrue(self._conn.exist_param_headers("test"))
+        self.assertFalse(self._conn.exist_param_headers("test_no"))
+        
+    def test_get_param_headers(self):
+        self._conn.add_param_headers("test", "value")
+        self.assertTrue(self._conn.exist_param_headers("test"))
+        self.assertFalse(self._conn.exist_param_headers("test_no"))
+        
+    def test_get_headers(self):
+        self._conn.add_param_headers("test", "value")
+        self.assertEqual(self._conn.headers,
+                         {"test": "value"})
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/urls_patterns.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/urls_patterns.py
new file mode 100644
index 0000000000000000000000000000000000000000..b57212950b4b22de76174803be0969ca78e79ba1
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/keycloak/urls_patterns.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2017 Marcos Pereira <marcospereira.mpj@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# OPENID URLS
+URL_WELL_KNOWN = "realms/{realm-name}/.well-known/openid-configuration"
+URL_TOKEN = "realms/{realm-name}/protocol/openid-connect/token"
+URL_USERINFO = "realms/{realm-name}/protocol/openid-connect/userinfo"
+URL_LOGOUT = "realms/{realm-name}/protocol/openid-connect/logout"
+URL_CERTS = "realms/{realm-name}/protocol/openid-connect/certs"
+URL_INTROSPECT = "realms/{realm-name}/protocol/openid-connect/token/introspect"
+URL_ENTITLEMENT = "realms/{realm-name}/authz/entitlement/{resource-server-id}"
+
+# ADMIN URLS
+URL_ADMIN_USERS = "admin/realms/{realm-name}/users"
+URL_ADMIN_USERS_COUNT = "admin/realms/{realm-name}/users/count"
+URL_ADMIN_USER = "admin/realms/{realm-name}/users/{id}"
+URL_ADMIN_USER_CONSENTS = "admin/realms/{realm-name}/users/{id}/consents"
+URL_ADMIN_SEND_UPDATE_ACCOUNT = "admin/realms/{realm-name}/users/{id}/execute-actions-email"
+URL_ADMIN_SEND_VERIFY_EMAIL = "admin/realms/{realm-name}/users/{id}/send-verify-email"
+URL_ADMIN_RESET_PASSWORD = "admin/realms/{realm-name}/users/{id}/reset-password"
+URL_ADMIN_GET_SESSIONS = "admin/realms/{realm-name}/users/{id}/sessions"
+URL_ADMIN_USER_CLIENT_ROLES = "admin/realms/{realm-name}/users/{id}/role-mappings/clients/{client-id}"
+URL_ADMIN_USER_GROUP = "admin/realms/{realm-name}/users/{id}/groups/{group-id}"
+
+URL_ADMIN_SERVER_INFO = "admin/serverinfo"
+
+URL_ADMIN_GROUPS = "admin/realms/{realm-name}/groups"
+URL_ADMIN_GROUP = "admin/realms/{realm-name}/groups/{id}"
+URL_ADMIN_GROUP_CHILD = "admin/realms/{realm-name}/groups/{id}/children"
+URL_ADMIN_GROUP_PERMISSIONS = "admin/realms/{realm-name}/groups/{id}/management/permissions"
+
+URL_ADMIN_CLIENTS = "admin/realms/{realm-name}/clients"
+URL_ADMIN_CLIENT = "admin/realms/{realm-name}/clients/{id}"
+URL_ADMIN_CLIENT_ROLES = "admin/realms/{realm-name}/clients/{id}/roles"
+URL_ADMIN_CLIENT_ROLE = "admin/realms/{realm-name}/clients/{id}/roles/{role-name}"
+
+URL_ADMIN_REALM_ROLES = "admin/realms/{realm-name}/roles"
+
+URL_ADMIN_USER_STORAGE = "admin/realms/{realm-name}/user-storage/{id}/sync"
+URL_ADMIN_REALM = "admin/realms"
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/PKG-INFO b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/PKG-INFO
new file mode 100644
index 0000000000000000000000000000000000000000..e98a1ee3c0a656997e8a87a4d92881f1c17cd0f3
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/PKG-INFO
@@ -0,0 +1,18 @@
+Metadata-Version: 1.1
+Name: python-keycloak
+Version: 0.12.0
+Summary: python-keycloak is a Python package providing access to the Keycloak API.
+Home-page: https://bitbucket.org/agriness/python-keycloak
+Author: Marcos Pereira
+Author-email: marcospereira.mpj@gmail.com
+License: GNU General Public License - V3
+Description: UNKNOWN
+Keywords: keycloak openid
+Platform: UNKNOWN
+Classifier: Programming Language :: Python :: 3
+Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
+Classifier: Development Status :: 3 - Alpha
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: Unix
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Topic :: Utilities
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/SOURCES.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/SOURCES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d0e7305a6e0d611c5de47f23bca28423fabd2742
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/SOURCES.txt
@@ -0,0 +1,22 @@
+README.md
+setup.cfg
+setup.py
+keycloak/__init__.py
+keycloak/connection.py
+keycloak/exceptions.py
+keycloak/keycloak_admin.py
+keycloak/keycloak_adminchild.py
+keycloak/keycloak_main.py
+keycloak/keycloak_openid.py
+keycloak/urls_patterns.py
+keycloak/authorization/__init__.py
+keycloak/authorization/permission.py
+keycloak/authorization/policy.py
+keycloak/authorization/role.py
+keycloak/tests/__init__.py
+keycloak/tests/test_connection.py
+python_keycloak.egg-info/PKG-INFO
+python_keycloak.egg-info/SOURCES.txt
+python_keycloak.egg-info/dependency_links.txt
+python_keycloak.egg-info/requires.txt
+python_keycloak.egg-info/top_level.txt
\ No newline at end of file
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/dependency_links.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/dependency_links.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/requires.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/requires.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d6eafdf65702ff256e75b81a0f7fbdbcc975e899
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/requires.txt
@@ -0,0 +1,3 @@
+requests==2.18.4
+httmock==1.2.5
+python-jose==1.4.0
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/top_level.txt b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..26c07c1da4a50b7acffbd55aa039a9d4e0d27494
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/python_keycloak.egg-info/top_level.txt
@@ -0,0 +1 @@
+keycloak
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/roles.json b/ansible/roles/keycloak/files/python-keycloak-0.12.0/roles.json
new file mode 100644
index 0000000000000000000000000000000000000000..9aba580d5292e4126a40c321b47f42e7741318d1
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/roles.json
@@ -0,0 +1,28 @@
+[
+    {
+        "id": "3ff462fc-b33c-431a-b54b-861c3298d910",
+        "name": "manage-users",
+        "description": "${role_manage-users}",
+        "scopeParamRequired": false,
+        "composite": false,"clientRole": true,
+        "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+    },
+    {
+        "id": "57118202-c5e5-4c49-829b-c2ed796bfdea",
+        "name": "query-users",
+        "description": "${role_query-users}",
+        "scopeParamRequired": false,
+        "composite": false,
+        "clientRole": true,
+        "containerId": "b2f45201-1362-4b10-83c3-207d470f44bf"
+    },
+    {
+        "id":"46019462-3dc8-46a8-9786-ffcbad293f43",
+        "name":"view-users",
+        "description":"${role_view-users}",
+        "scopeParamRequired":false,
+        "composite":true,
+        "clientRole":true,
+        "containerId":"b2f45201-1362-4b10-83c3-207d470f44bf"
+    }
+]
\ No newline at end of file
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/setup.cfg b/ansible/roles/keycloak/files/python-keycloak-0.12.0/setup.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..9f88734b50dc5105d44ecd76494e065e8437e14f
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/setup.cfg
@@ -0,0 +1,7 @@
+[metadata]
+description-file = README.md
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff --git a/ansible/roles/keycloak/files/python-keycloak-0.12.0/setup.py b/ansible/roles/keycloak/files/python-keycloak-0.12.0/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf6a505f0a0816299d694a5e6db9ecca8421b449
--- /dev/null
+++ b/ansible/roles/keycloak/files/python-keycloak-0.12.0/setup.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+
+from setuptools import setup
+
+setup(
+    name='python-keycloak',
+    version='0.12.0',
+    url='https://bitbucket.org/agriness/python-keycloak',
+    license='GNU General Public License - V3',
+    author='Marcos Pereira',
+    author_email='marcospereira.mpj@gmail.com',
+    keywords='keycloak openid',
+    description=u'python-keycloak is a Python package providing access to the Keycloak API.',
+    packages=['keycloak', 'keycloak.authorization', 'keycloak.tests'],
+    install_requires=['requests==2.18.4', 'httmock==1.2.5', 'python-jose==1.4.0'],
+    classifiers=[
+        'Programming Language :: Python :: 3',
+        'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
+        'Development Status :: 3 - Alpha',
+        'Operating System :: MacOS',
+        'Operating System :: Unix',
+        'Operating System :: Microsoft :: Windows',
+        'Topic :: Utilities'
+    ]
+)
diff --git a/ansible/roles/keycloak/tasks/keycloak_bootstrap.yml b/ansible/roles/keycloak/tasks/keycloak_bootstrap.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6b4807a15a4cc3a9d0d695a4f4d61c21700215ca
--- /dev/null
+++ b/ansible/roles/keycloak/tasks/keycloak_bootstrap.yml
@@ -0,0 +1,8 @@
+- name: initialize python library to run keycloak bootstrap script 
+  shell: python roles/keycloak/files/python-keycloak-0.12.0/keycloak/setup.py install
+
+- name: Save keycalok vars to json
+  template: src="roles/keycloak/templates/keycloak-bootstrap.conf.j2" dest="/tmp/keycloak-bootstrap.conf.json" mode="0644"
+
+- name: Run the keycloak bootstrap script
+  shell: python keycloak_main.py  /tmp/keycloak-bootstrap.conf.json
\ No newline at end of file
diff --git a/ansible/roles/keycloak/tasks/main.yml b/ansible/roles/keycloak/tasks/main.yml
index 0965ef98af028c8f08b0134ec156e14b66aac15d..23f4fa229f9b81fabec19fb1a79ad25fbabb501c 100644
--- a/ansible/roles/keycloak/tasks/main.yml
+++ b/ansible/roles/keycloak/tasks/main.yml
@@ -6,3 +6,6 @@
   tags:
     - deploy
 
+- include: keycloak_bootstrap.yml
+  tags:
+    - keycloak-bootstrap.yml
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/keycloak-bootstrap.conf.j2 b/ansible/roles/keycloak/templates/keycloak-bootstrap.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..e17a8594c16be86a8d97314f700bc4d050c3dab4
--- /dev/null
+++ b/ansible/roles/keycloak/templates/keycloak-bootstrap.conf.j2
@@ -0,0 +1,13 @@
+{
+    "keycloak_auth_server_url": "{{ keycloak_auth_server_url }}",
+    "keycloak_management_user": "{{ keycloak_management_user }}",
+    "keycloak_management_password": "{{ keycloak_management_password }}",
+    "keycloak_realm": "{{ keycloak_realm }}",
+    "keycloak_realm_json_file_path": "{{keycloak_realm_json_file_path}}",
+    "keycloak_user_manager_roles_json_file_path": "{{ keycloak_user_manager_roles_json_file_path }}",
+    "keycloak_api_management_username":  "{{ keycloak_api_management_username }}",
+    "keycloak_api_management_user_email": "{{ keycloak_api_management_user_email }}",
+    "keycloak_api_management_user_first_name": "{{ keycloak_api_management_user_first_name }}",
+    "keycloak_api_management_user_last_name": "{{ keycloak_api_management_user_last_name }}",
+    "keycloak_api_management_user_password": "{{ keycloak_api_management_user_password }}"
+}