Repository: octo-technology/awscli-saml-sso (language: python)

Issue:
Enhance developper local experience with docker-compose stack
**Is your feature request related to a problem? Please describe.**
Currently it is not so easy for a new developper to join the project as it required a properly setup SAML SSO authentication plugged in AWS account.
Also we often need multiple accounts to cover different cases (multi-role account, single role or no role associated at all for instance).

**Describe the solution you'd like**
This aims to provide a local environment based on docker-compose with a SAML SSO identity provider ([keycloak](https://github.com/keycloak/keycloak)) and an AWS mock ([localstack](https://github.com/localstack/localstack)).



Discussion / hints:

Fix patch:
diff --git a/.env b/.env
new file mode 100644
index 0000000..4f2500d
--- /dev/null
+++ b/.env
@@ -0,0 +1,10 @@
+LOCALSTACK_EXPOSED_PORT=4566
+LOCALSTACK_S3_BUCKET_NAME=example-bucket
+LOCALSTACK_SAML_PROVIDER_NAME=SamlExampleProvider
+
+KEYCLOAK_EXPOSED_PORT=8080
+KEYCLOAK_DATABASE_DB=keycloak
+KEYCLOAK_DATABASE_USER=keycloak
+KEYCLOAK_DATABASE_PASSWORD=password
+KEYCLOAK_ADMIN_USER=admin
+KEYCLOAK_ADMIN_PASSWORD=password
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index d4320da..9fae19d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,12 +109,8 @@ celerybeat.pid
 *.sage.py
 
 # Environments
-.env
 .venv
-env/
 venv/
-ENV/
-env.bak/
 venv.bak/
 pythonenv*
 
diff --git a/README.rst b/README.rst
index 075e768..71938ed 100644
--- a/README.rst
+++ b/README.rst
@@ -13,6 +13,14 @@ AWSCLI SAML SSO
 
 awscli_saml_sso is a command line tool that aims to get temporary credentials from SAML identity provider in order to authenticate to awscli.
 
+.. _requirements:
+Requirements
+------------
+
+* Python 3.5+
+* Google Chrome, Chromium or Firefox web browser installed on operating system
+
+.. _installation:
 Installation
 ------------
 
@@ -22,6 +30,7 @@ You need a fully functional python 3 environment, then you can install tool from
 
     pip install awscli-saml-sso
 
+.. _usage:
 Usage
 -----
 
@@ -69,7 +78,7 @@ OR
 
     AWS_PROFILE=saml aws ec2 describe-instances
 
-
+.. _features:
 Features
 --------
 
@@ -77,18 +86,291 @@ Features
 * Select among retrieved AWS roles you are allowed to assume
 * Store temporary credentials in aws configuration files
 
+.. _how-it-works:
+How it works
+------------
+
+This section aims to explain how awscli-saml-sso works internally. When you authenticate through awscli-saml-sso, you will follow this workflow:
+
+* First a web browser is opened at the given identity provider start url
+* You will authenticate with your credentials (and MFA if required)
+* If authentication succeed, you will be redirected to `AWS SAML REDIRECT URL <https://signin.aws.amazon.com/saml>`_ which leads to several cases:
+  * If you belong to multiple roles, a web page let you choose which one you would like to assume
+  * If you belong to only one role, you should be automatically redirected to AWS console authenticated through the given role
+  * If you do not belong to any role, an error page is returned to you
+* Whatever the case, your browser should close automatically and awscli-saml-sso will report the SAML authentication result to you.
+  * Given the case, you should need to choose a role to assume
+  * or the authenticate workflow stop here if you do not belong to any role
+* Finally awscli-saml-sso has automatically provided a ``saml`` profile in `your aws credentials file <~/.aws/credentials>`_ which is authenticated through AWS STS temporary credentials which should by default expire in one hour.
+
+
+What is the awscli-saml-sso secret sauce to make the work transparently for you?
+
+At first, we choose to not make any assumption on the way your identity provider let you authenticate (how is named username/password fields, would you need to answer a challenge, required MFA step, ...).
+Instead we choose to open a web browser which will let you follow your regular SSO authentication workflow.
+This web browser is driven by selenium, awscli-saml-sso will try to detect which browser is installed on your system and required web driver is automatically downloaded for you.
+
+When authentication workflow ended, you will be redirected to `AWS SAML REDIRECT URL <https://signin.aws.amazon.com/saml>`_.
+Here, thanks to a proxy configured in the previously opened web browser, we are able to detect that you reach redirect url, thus we can close web browser from now on.
+
+In the redirect HTTP request, we find a ``SAMLResponse`` attribute in body that is base64 encoded, which correspond to SAML response in XML format.
+You can find an example `here <docs/examples/keycloak_saml_response.xml>`_.
+
+The most interesting part for us is the ``saml:AttributeStatement`` block enclosed here, which should contains those attributes:
+
+* RoleSessionName: should correspond to your authenticated username
+* Role: list of AWS roles you belong to that you are authorized to assume
+* SessionDuration: optional attribute that can override default one hour session duration from identity provider side
+
+.. code-block:: xml
+
+    <saml:AttributeStatement>
+        <saml:Attribute FriendlyName="Session Duration"
+                        Name="https://aws.amazon.com/SAML/Attributes/SessionDuration"
+                        NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">28800
+            </saml:AttributeValue>
+        </saml:Attribute>
+        <saml:Attribute FriendlyName="Session Name" Name="https://aws.amazon.com/SAML/Attributes/RoleSessionName"
+                        NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">admin
+            </saml:AttributeValue>
+        </saml:Attribute>
+        <saml:Attribute FriendlyName="Session Role" Name="https://aws.amazon.com/SAML/Attributes/Role"
+                        NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+                arn:aws:iam::000000000000:role/Role.User,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider
+            </saml:AttributeValue>
+            <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+                arn:aws:iam::000000000000:role/Role.Admin,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider
+            </saml:AttributeValue>
+        </saml:Attribute>
+    </saml:AttributeStatement>
+
+
+In our case, we will parse `SAML Role Attribute <https://aws.amazon.com/SAML/Attributes/Role>`_ to print to user the list of AWS roles it is allowed to assume.
+Each role is in the form of ``<aws_role_arn>,<aws_identity_provider_arn>``, for instance: ``arn:aws:iam::000000000000:role/Role.User,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider``.
+
+Finally we call `aws assume_role_with_saml <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts.html#STS.Client.assume_role_with_saml>`_ through boto3 python sdk which expect the following arguments:
+
+* role_arn: the ``aws_role_arn`` retrieved previously
+* principal_arn: the ``aws_identity_provider_arn`` retrieved previously
+* saml_assertion: the base64 encoded saml response retrieved previously
+
+AWS STS response will be retrieved and stored in a ``saml`` profile configured this way:
+
+.. code-block:: python
+
+    config.set("saml", "aws_access_key_id", sts_response["Credentials"]["AccessKeyId"])
+    config.set("saml", "aws_secret_access_key", sts_response["Credentials"]["SecretAccessKey"])
+    config.set("saml", "aws_session_token", sts_response["Credentials"]["SessionToken"])
+    config.set("saml", "aws_security_token", sts_response["Credentials"]["SessionToken"])
+
+
+Note that you can call `assume-role-with-saml <https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-saml.html> directly from ``awscli`` this way:
+
+.. code-block:: shell
+
+    awslocal sts assume-role-with-saml \
+        --role-arn arn:aws:iam::000000000000:role/Role.Admin \
+        --principal-arn arn:aws:iam::000000000000:saml-provider/SamlExampleProvider \
+        --saml-assertion $(cat docs/examples/keycloak_saml_response.xml | base64)
+
+... which should give you response like:
+
+.. code-block:: json
+
+    {
+        "Credentials": {
+            "AccessKeyId": "ASIA...",
+            "SecretAccessKey": "...",
+            "SessionToken": "FQoGZXIvYXdzEBYaDwL8pPz/cNvhUKkibZTashetWcPahlTMbaBUvDwXxjiehDkRQGYYUQrTrMdv7+6SinGiDNBiB7ZKEoyfDja6vhHwnBP2UcY/XozN+MFFPGEMhHcsUqPApwOErN37uHAM5kIOukhGlNmIPvPVWZtDoWryAuygKbqZTWwKecCwtURG2I0KF8MpS+s6SaG6EOUl5OJf/mJJQvH725q2VOWUk7HBezFCIXO+t3L8SzMygdt2FNzwUenhazYvDs2ngSlsbFbAaeeMHikZrWgTs6GkUv1uyAknpTRnInmwBDHb7SZAqpDmc7Q9+b+NXTcO1qzx/eMarHHlFQyeEEI3BEc=",
+            "Expiration": "2020-12-06T18:54:38.114Z"
+        },
+        "AssumedRoleUser": {
+            "AssumedRoleId": "AROA3X42LBCD9KGW7O43L:benjamin.brabant",
+            "Arn": "arn:aws:sts::123456789012:assumed-role/Role.Admin/benjamin.brabant"
+        },
+        "Subject": "AROA3X42LBCD9KGW7O43L:benjamin.brabant",
+        "SubjectType": "persistent",
+        "Issuer": "http://localhost:3000/",
+        "Audience": "https://signin.aws.amazon.com/saml",
+        "NameQualifier": "B64EncodedStringOfHashOfIssuerAccountIdAndUserId="
+    }
+
+.. _contributing:
 Contributing
 ------------
 
 Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
-
 Please make sure to update tests as appropriate.
+For further information, please read `CONTRIBUTING <CONTRIBUTING.rst>`_ document.
+
+.. _development:
+Development
+-----------
+
+If you would like to setup awscli-saml-sso for local development, please read the following section.
+Before beginning, ensure to comply with requirements defined in :ref:`requirements` section.
+
+You should create a python virtual environment:
+
+.. code-block:: shell
+
+    virtualenv -p python3 .venv
+    # OR
+    python3 -m venv .venv
+
+    # THEN
+    source .venv/bin/activate
+
+You can figure out useful development requirements in `requirements_dev.txt <requirements_dev.txt>`_ and install them:
+
+.. code-block:: shell
+
+    pip install -r requirements_dev.txt
+
+
+Then install a local editable version of awscli-saml-sso project with pip.
+Under the hood, the following command will create an `awscli-saml-sso.egg-link <.venv/lib/python3.8/site-packages/awscli-saml-sso.egg-link>`_ file in ``.venv/lib/python3.8/site-packages/`` directory which contains a path pointing to your current awscli-saml-sso project directory.
+
+.. code-block:: shell
+
+    # from awscli-saml-sso project root
+    pip install -e .
+
+Thus you will be able to use development version of `awscli_saml_sso` cli.
+Please check that this command correctly link to your local virtual environment:
+
+.. code-block:: shell
+
+    which awscli_saml_sso
+    > /path/to/your/project/directory/.venv/bin/awscli_saml_sso
+
+To ensure that `awscli_saml_sso` work properly, you will need:
+
+* A configured SAML identity provider
+* An access to AWS account
+
+To prevent having to manually setup these requirements, you will find a ready to use local setup configured through `docker-compose.yml <docker-compose.yml>`_.
+This configuration will setup the following environment:
+
+* An instance of `localstack <https://github.com/localstack/localstack>`_ which aims to replicate AWS services locally
+* A configured `keycloak <https://github.com/keycloak/keycloak>`_ server
+* A postgresql instance as a database backend required for keycloak server
+
+To setup this environment, just execute the following command:
+
+.. code-block:: shell
+
+    docker-compose up -d
+
+After waiting few minutes, complete environment should be up and running.
+You can run awscli-saml-sso this way to target localstack services endpoint instead of AWS default ones:
+
+.. code-block:: shell
+
+    awscli_saml_sso --endpoint-url=http://localhost:4566
+    # OR
+    ASS_ENDPOINT_URL=http://localhost:4566 awscli_saml_sso
+
+You can now use the following url as your identity provider url when asked by awscli-saml-sso: http://localhost:8080/auth/realms/master/protocol/saml/clients/amazon-aws
+If needed, you will find more details about the local environment setup in the following sections.
+
+Localstack
+^^^^^^^^^^
+
+The provided `localstack <https://github.com/localstack/localstack>`_ instance setup a local server on port ``4566`` that can be used as an AWS backend for required services.
+You can override the local exposed port by defining ``LOCALSTACK_EXPOSED_PORT`` environment variable.
+
+You can interact with localstack this way, for instance to list existing buckets:
+
+.. code-block:: shell
+
+    AWS_ACCESS_KEY_ID='_not_needed_locally_' AWS_SECRET_ACCESS_KEY='_not_needed_locally_' aws --endpoint-url=http://localhost:4566 s3 ls
+
+To ease local usage, you can leverage ``awslocal`` cli which is configured properly to rely on localstack backend:
+
+.. code-block:: shell
+
+    awslocal s3 ls
+
+.. warning:: note the ``awslocal`` command will only target default ``4566`` port, please stick to first method if overriding exposed port
+
+
+On container startup, localstack will automatically execute `localstack-setup.sh <./docker/localstack/localstack-setup.sh>`_ script which will provision default resources:
+
+* An AWS S3 bucket named `example-bucket`
+* An AWS SAML provider named `SamlExampleProvider`
+* AWS roles named `Role.User` and `Role.Admin` which would be assumed by SSO users after authentication
+
+
+Keycloak
+^^^^^^^^
+
+The provided `keycloak <https://github.com/keycloak/keycloak>`_ instance setup a local server on port ``8080`` that can be used as an identity provider backend.
+You can override the local exposed port by defining ``KEYCLOAK_EXPOSED_PORT`` environment variable.
+
+Keycloak expose a web interface that can be accessed at `http://localhost:8080 <http://localhost:8080>`_.
+
+.. image:: ./docs/images/keycloak-welcome-page.png
+  :alt: Keycloak Welcome Page
+
+You can authenticate to `keycloak administration console <http://localhost:8080/auth/admin/>`_ with following credentials:
+
+* username: admin
+* password: admin
+
+On container startup, keycloak will automatically import `master-realm-with-users.json <./docker/keycloak/master-realm-with-users.json>`_ configuration which will provision default resources:
+
+* An ``urn:amazon:webservices`` `client <http://localhost:8080/auth/admin/master/console/#/realms/master/clients>`_ aims to register AWS as a SAML service provider
+* Role mapping has been properly defined with default provided `users <http://localhost:8080/auth/admin/master/console/#/realms/master/users>`_ and `groups <http://localhost:8080/auth/admin/master/console/#/realms/master/groups>`_.
+
+Following users has been defined:
+
+* AWS ADMIN
+  * username: aws_admin
+  * password: aws_admin
+  * groups: AWS_ADMINS, AWS_USERS
+* AWS USER
+  * username: aws_user
+  * password: aws_user
+  * groups: AWS_USERS
+* AWS VOID
+  * username: aws_void
+  * password: aws_void
+  * groups: N/A (not attached to any group)
+
+Thus you can now use the following url as your identity provider url when asked by awscli-saml-sso: http://localhost:8080/auth/realms/master/protocol/saml/clients/amazon-aws
+
+Please feel free to update keycloak configuration from administration console to fulfil your needs.
+If you think that your configuration should be setup by default, you can export it this way, replace `master-realm-with-users.json <./docker/keycloak/master-realm-with-users.json>`_ content then submit your pull request :)
+
+.. code-block:: shell
+
+    docker-compose run --rm -v $(pwd)/export:/tmp/export keycloak -Djboss.socket.binding.port-offset=100 -Dkeycloak.migration.action=export -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=/tmp/export/master-realm-with-users.json
+
+    > [...]
+    > 13:21:15,119 INFO  [org.keycloak.services] (ServerService Thread Pool -- 67) KC-SERVICES0033: Full model export requested
+    > 13:21:15,925 INFO  [org.keycloak.services] (ServerService Thread Pool -- 67) KC-SERVICES0035: Export finished successfully
+    > 13:21:15,119 INFO  [org.keycloak.exportimport.singlefile.SingleFileExportProvider] (ServerService Thread Pool -- 67) Exporting model into file /tmp/export/master-realm-with-users.json
+    > [...]
+
+When you read above logs, you can hit ``CTRL+C`` to stop running instance.
+You will find a ``master-realm-with-users.json`` file in ``export`` directory created in your current path.
 
+.. _credits:
 Credits
 -------
 
 `AWS - How to Implement Federated API and CLI Access Using SAML 2.0 and AD FS <https://aws.amazon.com/blogs/security/how-to-implement-federated-api-and-cli-access-using-saml-2-0-and-ad-fs>`_
+`AWS SAML based User Federation using Keycloak <https://neuw.medium.com/aws-connect-saml-based-identity-provider-using-keycloak-9b3e6d0111e6>`_
 
+.. _license:
 License
 -------
 
diff --git a/awscli_saml_sso/__main__.py b/awscli_saml_sso/__main__.py
index 7c3302e..99d541f 100644
--- a/awscli_saml_sso/__main__.py
+++ b/awscli_saml_sso/__main__.py
@@ -43,8 +43,10 @@
               type=click.Choice(supported_log_levels, case_sensitive=False),
               default=default_log_level,
               help=f"Configure python log level to print (default: {default_log_level})")
+@click.option("--endpoint-url", envvar="ASS_ENDPOINT_URL",
+              help="Override AWS API endpoint url (mainly for testing purpose)")
 @click.version_option()
-def main(log_level):
+def main(log_level, endpoint_url):
     os.environ["WDM_LOG_LEVEL"] = str(logging.getLevelName(log_level))
     fileConfig(resource_filename("awscli_saml_sso", "logger.cfg"), disable_existing_loggers=False, defaults={
         "log_level": log_level,
@@ -112,7 +114,7 @@ def main(log_level):
         principal_arn = awsroles[int(selectedroleindex)].split(",")[1]
 
     # Use the assertion to get an AWS STS token using Assume Role with SAML
-    client = boto3.client("sts")
+    client = boto3.client("sts", endpoint_url=endpoint_url)
     sts_response = client.assume_role_with_saml(RoleArn=role_arn, PrincipalArn=principal_arn, SAMLAssertion=assertion)
 
     # Write the AWS STS token into the AWS credential file
@@ -150,7 +152,8 @@ def main(log_level):
     s3 = boto3.client("s3",
                       aws_access_key_id=sts_response["Credentials"]["AccessKeyId"],
                       aws_secret_access_key=sts_response["Credentials"]["SecretAccessKey"],
-                      aws_session_token=sts_response["Credentials"]["SessionToken"])
+                      aws_session_token=sts_response["Credentials"]["SessionToken"],
+                      endpoint_url=endpoint_url)
     response = s3.list_buckets()
     buckets = [bucket["Name"] for bucket in response["Buckets"]]
 
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..4f59e9b
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,73 @@
+version: '3.7'
+
+services:
+  keycloak:
+    container_name: ass-keycloak
+    image: jboss/keycloak:11.0.3
+    command: >
+      -Dkeycloak.migration.action=import
+      -Dkeycloak.migration.provider=singleFile
+      -Dkeycloak.migration.file=/docker-entrypoint-initkeycloak.d/master-realm-with-users.json
+      -Dkeycloak.migration.strategy=OVERWRITE_EXISTING
+    environment:
+      DB_VENDOR: POSTGRES
+      DB_ADDR: postgres
+      DB_SCHEMA: public
+      DB_DATABASE: ${KEYCLOAK_DATABASE_DB}
+      DB_USER: ${KEYCLOAK_DATABASE_USER}
+      DB_PASSWORD: ${KEYCLOAK_DATABASE_PASSWORD}
+      KEYCLOAK_USER: ${KEYCLOAK_ADMIN_USER}
+      KEYCLOAK_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
+    ports:
+      - ${KEYCLOAK_EXPOSED_PORT}:8080
+    depends_on:
+      - postgres
+    volumes:
+      - ./docker/keycloak:/docker-entrypoint-initkeycloak.d
+    networks:
+      - ass-network
+
+  localstack:
+    container_name: ass-localstack
+    image: localstack/localstack:0.12.3
+    restart: always
+    ports:
+      - "${LOCALSTACK_EXPOSED_PORT}:4566"
+    environment:
+      LOCALSTACK_DEBUG: 1
+      LOCALSTACK_SERVICES: iam, sts, s3
+      LOCALSTACK_START_WEB: 0
+      LOCALSTACK_DATA_DIR: /tmp/localstack/data
+      LOCALSTACK_DOCKER_HOST: unix:///var/run/docker.sock
+      LOCALSTACK_S3_BUCKET_NAME: ${LOCALSTACK_S3_BUCKET_NAME}
+      LOCALSTACK_SAML_PROVIDER_NAME: ${LOCALSTACK_SAML_PROVIDER_NAME}
+    volumes:
+      - localstack-s3-data:/tmp/localstack
+      - ./docker/localstack:/docker-entrypoint-initaws.d
+    networks:
+      - ass-network
+
+  postgres:
+    container_name: ass-postgres
+    image: library/postgres:13.1
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+    environment:
+      POSTGRES_DB: ${KEYCLOAK_DATABASE_DB}
+      POSTGRES_USER: ${KEYCLOAK_DATABASE_USER}
+      POSTGRES_PASSWORD: ${KEYCLOAK_DATABASE_PASSWORD}
+    networks:
+      - ass-network
+
+volumes:
+  localstack-s3-data:
+      name: ass-localstack-s3-data
+      driver: local
+  postgres_data:
+      name: ass-postgres-data
+      driver: local
+
+networks:
+  ass-network:
+    name: ass-network
+    driver: bridge
diff --git a/docker/keycloak/master-realm-with-users.json b/docker/keycloak/master-realm-with-users.json
new file mode 100644
index 0000000..cae6cc3
--- /dev/null
+++ b/docker/keycloak/master-realm-with-users.json
@@ -0,0 +1,1837 @@
+[ {
+  "id" : "master",
+  "realm" : "master",
+  "displayName" : "Keycloak",
+  "displayNameHtml" : "<div class=\"kc-logo-text\"><span>Keycloak</span></div>",
+  "notBefore" : 0,
+  "revokeRefreshToken" : false,
+  "refreshTokenMaxReuse" : 0,
+  "accessTokenLifespan" : 60,
+  "accessTokenLifespanForImplicitFlow" : 900,
+  "ssoSessionIdleTimeout" : 1800,
+  "ssoSessionMaxLifespan" : 36000,
+  "ssoSessionIdleTimeoutRememberMe" : 0,
+  "ssoSessionMaxLifespanRememberMe" : 0,
+  "offlineSessionIdleTimeout" : 2592000,
+  "offlineSessionMaxLifespanEnabled" : false,
+  "offlineSessionMaxLifespan" : 5184000,
+  "clientSessionIdleTimeout" : 0,
+  "clientSessionMaxLifespan" : 0,
+  "clientOfflineSessionIdleTimeout" : 0,
+  "clientOfflineSessionMaxLifespan" : 0,
+  "accessCodeLifespan" : 60,
+  "accessCodeLifespanUserAction" : 300,
+  "accessCodeLifespanLogin" : 1800,
+  "actionTokenGeneratedByAdminLifespan" : 43200,
+  "actionTokenGeneratedByUserLifespan" : 300,
+  "enabled" : true,
+  "sslRequired" : "external",
+  "registrationAllowed" : false,
+  "registrationEmailAsUsername" : false,
+  "rememberMe" : false,
+  "verifyEmail" : false,
+  "loginWithEmailAllowed" : true,
+  "duplicateEmailsAllowed" : false,
+  "resetPasswordAllowed" : false,
+  "editUsernameAllowed" : false,
+  "bruteForceProtected" : false,
+  "permanentLockout" : false,
+  "maxFailureWaitSeconds" : 900,
+  "minimumQuickLoginWaitSeconds" : 60,
+  "waitIncrementSeconds" : 60,
+  "quickLoginCheckMilliSeconds" : 1000,
+  "maxDeltaTimeSeconds" : 43200,
+  "failureFactor" : 30,
+  "roles" : {
+    "realm" : [ {
+      "id" : "394b75ba-eab3-4712-b30b-d2fc57a07ec7",
+      "name" : "uma_authorization",
+      "description" : "${role_uma_authorization}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "master",
+      "attributes" : { }
+    }, {
+      "id" : "19b7a359-2ec0-401a-9397-49cfab21b4ab",
+      "name" : "offline_access",
+      "description" : "${role_offline-access}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "master",
+      "attributes" : { }
+    }, {
+      "id" : "8a274d60-62a5-4883-9747-e3daa9c51dd7",
+      "name" : "admin",
+      "description" : "${role_admin}",
+      "composite" : true,
+      "composites" : {
+        "realm" : [ "create-realm" ],
+        "client" : {
+          "master-realm" : [ "impersonation", "view-users", "query-groups", "view-authorization", "manage-authorization", "create-client", "manage-users", "manage-clients", "query-users", "view-realm", "view-identity-providers", "manage-events", "query-realms", "view-clients", "manage-realm", "manage-identity-providers", "query-clients", "view-events" ]
+        }
+      },
+      "clientRole" : false,
+      "containerId" : "master",
+      "attributes" : { }
+    }, {
+      "id" : "79e54482-1784-48f7-ae98-b6e98a147c96",
+      "name" : "create-realm",
+      "description" : "${role_create-realm}",
+      "composite" : false,
+      "clientRole" : false,
+      "containerId" : "master",
+      "attributes" : { }
+    } ],
+    "client" : {
+      "urn:amazon:webservices" : [ {
+        "id" : "2e7065f3-de3d-4ffd-a0d5-959cae8c452f",
+        "name" : "arn:aws:iam::000000000000:role/Role.Admin,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "2e592dad-b2fc-4a5f-9c76-40a1cf860e29",
+        "attributes" : { }
+      }, {
+        "id" : "45dfd229-5295-4e32-a327-40522e7a583a",
+        "name" : "arn:aws:iam::000000000000:role/Role.User,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "2e592dad-b2fc-4a5f-9c76-40a1cf860e29",
+        "attributes" : { }
+      } ],
+      "security-admin-console" : [ ],
+      "admin-cli" : [ ],
+      "account-console" : [ ],
+      "broker" : [ {
+        "id" : "9a498f5a-cf6a-40b4-bc57-71abf1514518",
+        "name" : "read-token",
+        "description" : "${role_read-token}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "dd5a3ecc-c2fa-49ff-9438-110edc4e6372",
+        "attributes" : { }
+      } ],
+      "master-realm" : [ {
+        "id" : "a8e8793e-f63d-4927-8945-3209c6fffff6",
+        "name" : "impersonation",
+        "description" : "${role_impersonation}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "de786f50-42c9-4784-9e53-3d6f1f5975f0",
+        "name" : "view-users",
+        "description" : "${role_view-users}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "master-realm" : [ "query-users", "query-groups" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "a7e6f1a4-c118-4c6f-8880-8d0f623f36b5",
+        "name" : "query-groups",
+        "description" : "${role_query-groups}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "8df4793a-2d3f-475f-b9c4-bea0a0854328",
+        "name" : "view-authorization",
+        "description" : "${role_view-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "c0607064-dbc6-45c4-a0b2-dda4bcced1cd",
+        "name" : "manage-authorization",
+        "description" : "${role_manage-authorization}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "add55a46-926a-44ac-9742-f968b59f12f2",
+        "name" : "create-client",
+        "description" : "${role_create-client}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "36a5ba4c-f1d7-42f0-8760-91044c54b690",
+        "name" : "manage-users",
+        "description" : "${role_manage-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "ebf9f110-9cb7-479c-9d80-1fcec48e73ca",
+        "name" : "manage-clients",
+        "description" : "${role_manage-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "f9139caf-d602-48d6-b0f7-6902ef130573",
+        "name" : "query-users",
+        "description" : "${role_query-users}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "43aa1281-799f-445b-8617-b17d1f6133e2",
+        "name" : "view-realm",
+        "description" : "${role_view-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "5dfff67c-a251-4a42-934e-f553be7574b3",
+        "name" : "view-identity-providers",
+        "description" : "${role_view-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "4fa0290c-05b2-4c10-9ac3-adf7b00aa1ae",
+        "name" : "manage-events",
+        "description" : "${role_manage-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "ac8beed7-662a-4848-b01a-1362e4622076",
+        "name" : "query-realms",
+        "description" : "${role_query-realms}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "00319836-01a0-4be8-8954-68ee3f031809",
+        "name" : "view-clients",
+        "description" : "${role_view-clients}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "master-realm" : [ "query-clients" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "cea2655b-ccb6-47ae-ab4a-695ca628fda4",
+        "name" : "manage-realm",
+        "description" : "${role_manage-realm}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "f168cb6a-ecaa-4bbc-9a20-7063863845ee",
+        "name" : "manage-identity-providers",
+        "description" : "${role_manage-identity-providers}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "69d1b03b-2c05-42e8-8e57-07a1d1d951b3",
+        "name" : "query-clients",
+        "description" : "${role_query-clients}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      }, {
+        "id" : "5013f09f-35b6-4820-87cb-f3145cc5466c",
+        "name" : "view-events",
+        "description" : "${role_view-events}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+        "attributes" : { }
+      } ],
+      "account" : [ {
+        "id" : "3b31e7ef-b1a7-4f77-b573-5708dd454659",
+        "name" : "view-applications",
+        "description" : "${role_view-applications}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+        "attributes" : { }
+      }, {
+        "id" : "3ff1f103-c80f-464b-8595-a26f1d5282d4",
+        "name" : "manage-account",
+        "description" : "${role_manage-account}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "manage-account-links" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+        "attributes" : { }
+      }, {
+        "id" : "f1d87927-b0bb-477e-b029-16178ad7423d",
+        "name" : "manage-account-links",
+        "description" : "${role_manage-account-links}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+        "attributes" : { }
+      }, {
+        "id" : "cf711fa9-9700-489e-bfa3-21c2a0b0fca8",
+        "name" : "view-profile",
+        "description" : "${role_view-profile}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+        "attributes" : { }
+      }, {
+        "id" : "4e341dde-f0dc-49f4-b464-c433bb7703a5",
+        "name" : "manage-consent",
+        "description" : "${role_manage-consent}",
+        "composite" : true,
+        "composites" : {
+          "client" : {
+            "account" : [ "view-consent" ]
+          }
+        },
+        "clientRole" : true,
+        "containerId" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+        "attributes" : { }
+      }, {
+        "id" : "4a580f75-9dba-4ca5-9b50-393aab52059e",
+        "name" : "view-consent",
+        "description" : "${role_view-consent}",
+        "composite" : false,
+        "clientRole" : true,
+        "containerId" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+        "attributes" : { }
+      } ]
+    }
+  },
+  "groups" : [ {
+    "id" : "1294ec91-8f59-426f-ac79-76f3e642240e",
+    "name" : "AWS_ADMINS",
+    "path" : "/AWS_ADMINS",
+    "attributes" : { },
+    "realmRoles" : [ ],
+    "clientRoles" : {
+      "urn:amazon:webservices" : [ "arn:aws:iam::000000000000:role/Role.Admin,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider" ]
+    },
+    "subGroups" : [ ]
+  }, {
+    "id" : "c8ce058c-86ed-497c-8df3-c72b4fbb20aa",
+    "name" : "AWS_USERS",
+    "path" : "/AWS_USERS",
+    "attributes" : { },
+    "realmRoles" : [ ],
+    "clientRoles" : {
+      "urn:amazon:webservices" : [ "arn:aws:iam::000000000000:role/Role.User,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider" ]
+    },
+    "subGroups" : [ ]
+  } ],
+  "defaultRoles" : [ "uma_authorization", "offline_access" ],
+  "requiredCredentials" : [ "password" ],
+  "otpPolicyType" : "totp",
+  "otpPolicyAlgorithm" : "HmacSHA1",
+  "otpPolicyInitialCounter" : 0,
+  "otpPolicyDigits" : 6,
+  "otpPolicyLookAheadWindow" : 1,
+  "otpPolicyPeriod" : 30,
+  "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ],
+  "webAuthnPolicyRpEntityName" : "keycloak",
+  "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyRpId" : "",
+  "webAuthnPolicyAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyRequireResidentKey" : "not specified",
+  "webAuthnPolicyUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyCreateTimeout" : 0,
+  "webAuthnPolicyAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyAcceptableAaguids" : [ ],
+  "webAuthnPolicyPasswordlessRpEntityName" : "keycloak",
+  "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ],
+  "webAuthnPolicyPasswordlessRpId" : "",
+  "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified",
+  "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified",
+  "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified",
+  "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified",
+  "webAuthnPolicyPasswordlessCreateTimeout" : 0,
+  "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false,
+  "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ],
+  "users" : [ {
+    "id" : "c620de7b-e1b1-4a13-a1f8-d0c7031bfeff",
+    "createdTimestamp" : 1606854029806,
+    "username" : "admin",
+    "enabled" : true,
+    "totp" : false,
+    "emailVerified" : false,
+    "credentials" : [ {
+      "id" : "c79c31d6-d6c1-4ebe-b0d2-166394e5fa5e",
+      "type" : "password",
+      "createdDate" : 1606854030020,
+      "secretData" : "{\"value\":\"FjETrsdmexHe+cws2fV65Rrf0TjVJ6CiYbW9TIu4mRXTqC4/VkMbr5rdW7m9FbOyYCpsie/Z6/iUN9FbQ3mF0Q==\",\"salt\":\"XGhZLlFfl/DTzSC9DBtotw==\"}",
+      "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+    } ],
+    "disableableCredentialTypes" : [ ],
+    "requiredActions" : [ ],
+    "realmRoles" : [ "uma_authorization", "offline_access", "admin" ],
+    "clientRoles" : {
+      "account" : [ "manage-account", "view-profile" ]
+    },
+    "notBefore" : 0,
+    "groups" : [ ]
+  }, {
+    "id" : "a07dce59-66dc-48df-b894-d43d13c1dc27",
+    "createdTimestamp" : 1606855217956,
+    "username" : "aws_admin",
+    "enabled" : true,
+    "totp" : false,
+    "emailVerified" : true,
+    "credentials" : [ {
+      "id" : "d3e9e73e-041d-459b-811e-377a5d24d890",
+      "type" : "password",
+      "createdDate" : 1606855254246,
+      "secretData" : "{\"value\":\"/9rKm81oPnPTEHAGvyVf7HGh96QHntRZ4H3L/TNLHAFTECzWwKxMLxBqAng6FP05m7cgn8vJUDGYOMOrv30vqg==\",\"salt\":\"MUUbeB7d5VEdouBrM73ZNg==\"}",
+      "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+    } ],
+    "disableableCredentialTypes" : [ ],
+    "requiredActions" : [ ],
+    "realmRoles" : [ "uma_authorization", "offline_access" ],
+    "clientRoles" : {
+      "account" : [ "manage-account", "view-profile" ]
+    },
+    "notBefore" : 0,
+    "groups" : [ "/AWS_ADMINS", "/AWS_USERS" ]
+  }, {
+    "id" : "432c337e-2801-49ed-a18d-723c4ce2904f",
+    "createdTimestamp" : 1606855133275,
+    "username" : "aws_user",
+    "enabled" : true,
+    "totp" : false,
+    "emailVerified" : true,
+    "credentials" : [ {
+      "id" : "c5d301c3-178a-40c4-9ebf-0ea8521ae415",
+      "type" : "password",
+      "createdDate" : 1606855275283,
+      "secretData" : "{\"value\":\"F7Fi9+OboDQVMvv+ZTOT+y72pFHEMt+M6ie+dAZ3/YtcZnZv+gdporClSlpKCG7GXUFcpOD41E81G9xXHHeXCQ==\",\"salt\":\"nTuFWBvVjzAWohseJk/VDw==\"}",
+      "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+    } ],
+    "disableableCredentialTypes" : [ ],
+    "requiredActions" : [ ],
+    "realmRoles" : [ "uma_authorization", "offline_access" ],
+    "clientRoles" : {
+      "account" : [ "manage-account", "view-profile" ]
+    },
+    "notBefore" : 0,
+    "groups" : [ "/AWS_USERS" ]
+  }, {
+    "id" : "fb0d2ca7-b6e8-4037-976b-d83ea54ce867",
+    "createdTimestamp" : 1607483977823,
+    "username" : "aws_void",
+    "enabled" : true,
+    "totp" : false,
+    "emailVerified" : true,
+    "credentials" : [ {
+      "id" : "e13c62aa-6bc2-4bd7-8d54-ce6d17c43f25",
+      "type" : "password",
+      "createdDate" : 1607484011084,
+      "secretData" : "{\"value\":\"HirlOxXncWp1kxr8tXNr4IWEJPAt8jdCEVBhsG0+MceZKQlvEHju11BCu/BGHxpoNnkcze/TpTrGZTxpFDixPA==\",\"salt\":\"7v+GgE251EEyfErWl1BUOw==\"}",
+      "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+    } ],
+    "disableableCredentialTypes" : [ ],
+    "requiredActions" : [ ],
+    "realmRoles" : [ "uma_authorization", "offline_access" ],
+    "clientRoles" : {
+      "account" : [ "manage-account", "view-profile" ]
+    },
+    "notBefore" : 0,
+    "groups" : [ ]
+  } ],
+  "scopeMappings" : [ {
+    "clientScope" : "offline_access",
+    "roles" : [ "offline_access" ]
+  } ],
+  "clientScopeMappings" : {
+    "account" : [ {
+      "client" : "account-console",
+      "roles" : [ "manage-account" ]
+    } ]
+  },
+  "clients" : [ {
+    "id" : "ce456cc8-c862-4b5d-a1fa-a79457d03782",
+    "clientId" : "account",
+    "name" : "${client_account}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/master/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "537cc476-85d1-4934-b02e-bb9b8a939126",
+    "defaultRoles" : [ "manage-account", "view-profile" ],
+    "redirectUris" : [ "/realms/master/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : { },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "9d367f39-39f0-49e3-a311-8d112469ebff",
+    "clientId" : "account-console",
+    "name" : "${client_account-console}",
+    "rootUrl" : "${authBaseUrl}",
+    "baseUrl" : "/realms/master/account/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "6dc14e90-d730-4e2e-b50a-ecf8f49ecb78",
+    "redirectUris" : [ "/realms/master/account/*" ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "b69b008b-d213-4f8f-a925-46a6cd4d5ea6",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "c82e5f06-612d-4910-ae3f-1f44b2e5744a",
+    "clientId" : "admin-cli",
+    "name" : "${client_admin-cli}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "1ce4ee37-82c8-443d-a4dc-da3ab8a27b45",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : false,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : true,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : { },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "dd5a3ecc-c2fa-49ff-9438-110edc4e6372",
+    "clientId" : "broker",
+    "name" : "${client_broker}",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "b25077ad-d07b-415e-b73e-bfc6e630a70e",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : { },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "98d1a022-e53f-4baf-9dba-dc9da221e4e3",
+    "clientId" : "master-realm",
+    "name" : "master Realm",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "2115bdf8-0a49-49e5-9cc4-0afdb7200199",
+    "redirectUris" : [ ],
+    "webOrigins" : [ ],
+    "notBefore" : 0,
+    "bearerOnly" : true,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : { },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : true,
+    "nodeReRegistrationTimeout" : 0,
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "7e2fcbc6-426d-4f65-b28e-0450afdd1f5f",
+    "clientId" : "security-admin-console",
+    "name" : "${client_security-admin-console}",
+    "rootUrl" : "${authAdminUrl}",
+    "baseUrl" : "/admin/master/console/",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "d25064f7-61ea-490b-83cb-c951328c50ff",
+    "redirectUris" : [ "/admin/master/console/*" ],
+    "webOrigins" : [ "+" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : true,
+    "frontchannelLogout" : false,
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "pkce.code.challenge.method" : "S256"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : 0,
+    "protocolMappers" : [ {
+      "id" : "277e36f5-69b9-42bb-9626-722eced61d42",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  }, {
+    "id" : "2e592dad-b2fc-4a5f-9c76-40a1cf860e29",
+    "clientId" : "urn:amazon:webservices",
+    "baseUrl" : "/auth/realms/master/protocol/saml/clients/amazon-aws",
+    "surrogateAuthRequired" : false,
+    "enabled" : true,
+    "alwaysDisplayInConsole" : false,
+    "clientAuthenticatorType" : "client-secret",
+    "secret" : "909383f5-00f8-4d4a-bce4-5e3d98f2d34d",
+    "redirectUris" : [ "https://signin.aws.amazon.com/saml" ],
+    "webOrigins" : [ "https://signin.aws.amazon.com" ],
+    "notBefore" : 0,
+    "bearerOnly" : false,
+    "consentRequired" : false,
+    "standardFlowEnabled" : true,
+    "implicitFlowEnabled" : false,
+    "directAccessGrantsEnabled" : false,
+    "serviceAccountsEnabled" : false,
+    "publicClient" : false,
+    "frontchannelLogout" : true,
+    "protocol" : "saml",
+    "attributes" : {
+      "saml.assertion.signature" : "true",
+      "saml.force.post.binding" : "true",
+      "saml.multivalued.roles" : "false",
+      "saml.encrypt" : "false",
+      "saml_assertion_consumer_url_post" : "https://signin.aws.amazon.com/saml",
+      "saml_idp_initiated_sso_url_name" : "amazon-aws",
+      "saml.server.signature" : "true",
+      "saml.server.signature.keyinfo.ext" : "false",
+      "exclude.session.state.from.auth.response" : "false",
+      "saml.signing.certificate" : "MIIDbTCCAlWgAwIBAgIEJ+jd7DANBgkqhkiG9w0BAQsFADBnMR8wHQYDVQQDExZ1cm46YW1hem9uOndlYnNlcnZpY2VzMSIwIAYDVQQKExlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQIEwpXYXNoaW5ndG9uMQswCQYDVQQGEwJVUzAeFw0yMDExMTgwMDAwMDBaFw0yMTExMTgwMDAwMDBaMGcxHzAdBgNVBAMTFnVybjphbWF6b246d2Vic2VydmljZXMxIjAgBgNVBAoTGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAgTCldhc2hpbmd0b24xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9mndRmWlzUX29ZalO3xrcg9SNqxao3PucELQCO3NYW+Y5PKu+CwicfLdC6K/u6uWZfb0zRTCtmgShAIvV8ydBx0YTyh6A2UIIL9iyYTTRUAeTXHS0jqK7kPBdBF77+SOGkyvBwcc/emTeCWhJZd8YNwfoXM/ZQXEb7UROHF1tWuttYLS7uvJabfWuZQVibtynfONOP1T4h2CadZXpCEwrlr6Bt/Yl662eElHIR1B0biroWM2iSVCglOqaj/TeetioYeEP82oOzMLreefNNRYsfnAstT3qL5NagTe6sXyRmMIfCc2TVXU6fyya0utqNHEEOv9Ju8tLIpgrGXNINijwIDAQABoyEwHzAdBgNVHQ4EFgQUdTEzFXgjKLs+jHDJgcRF4Y+BMTMwDQYJKoZIhvcNAQELBQADggEBAMBlWzQ1IPrxq00PpHDiCZpmJGmKTpS/xXZdF9TcOurRk01j1oX63OeNi+gJNqO4rehODJDHNthNr2MpemxDpyV9DVQY4GoNYJhvPMqNMldrS+DGXCSi0U9Wt+TGo7R7fuuY4eisBvowSZrkloF0CbWld5U6ZjBIm29EXsv6au70ceYcshM7HbV68+z68YvIPBrxg622kVzvG6UTvvbwJH4GXR6yjsrepKCDbyb4iGwKLxWGESdhA+1S9JzPNMKH09fZTcgOIdoiGlRT54rVkvJgljO2bSaOKnzszb4zDXGTWyFQS92XbNDCu011b/jSLyQPsGWZM/LQ5POuz7lN3QM=",
+      "saml.signature.algorithm" : "RSA_SHA256",
+      "saml_force_name_id_format" : "false",
+      "saml.client.signature" : "true",
+      "tls.client.certificate.bound.access.tokens" : "false",
+      "saml.authnstatement" : "true",
+      "display.on.consent.screen" : "false",
+      "saml_name_id_format" : "transient",
+      "saml.onetimeuse.condition" : "false",
+      "saml_signature_canonicalization_method" : "http://www.w3.org/2001/10/xml-exc-c14n#"
+    },
+    "authenticationFlowBindingOverrides" : { },
+    "fullScopeAllowed" : false,
+    "nodeReRegistrationTimeout" : -1,
+    "protocolMappers" : [ {
+      "id" : "f7ed2051-afcb-4e2a-8cf0-0c353decd046",
+      "name" : "Session Duration",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-hardcode-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "attribute.value" : "28800",
+        "attribute.nameformat" : "Basic",
+        "friendly.name" : "Session Duration",
+        "attribute.name" : "https://aws.amazon.com/SAML/Attributes/SessionDuration"
+      }
+    }, {
+      "id" : "b556ec72-0bb1-4d3d-b387-bd1619ea4f0e",
+      "name" : "Session Role",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-role-list-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "single" : "true",
+        "attribute.nameformat" : "Basic",
+        "friendly.name" : "Session Role",
+        "attribute.name" : "https://aws.amazon.com/SAML/Attributes/Role"
+      }
+    }, {
+      "id" : "4cde093c-9d06-4ba1-83b2-bd475bb23403",
+      "name" : "Session Name",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-user-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "attribute.nameformat" : "Basic",
+        "user.attribute" : "username",
+        "friendly.name" : "Session Name",
+        "attribute.name" : "https://aws.amazon.com/SAML/Attributes/RoleSessionName"
+      }
+    } ],
+    "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
+    "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+  } ],
+  "clientScopes" : [ {
+    "id" : "dcf1d680-2723-44cd-a2c5-e20c2d07749b",
+    "name" : "address",
+    "description" : "OpenID Connect built-in scope: address",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${addressScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "609da488-7c5c-497f-a414-a7d107285d07",
+      "name" : "address",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-address-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute.formatted" : "formatted",
+        "user.attribute.country" : "country",
+        "user.attribute.postal_code" : "postal_code",
+        "userinfo.token.claim" : "true",
+        "user.attribute.street" : "street",
+        "id.token.claim" : "true",
+        "user.attribute.region" : "region",
+        "access.token.claim" : "true",
+        "user.attribute.locality" : "locality"
+      }
+    } ]
+  }, {
+    "id" : "47f865d6-0679-4ced-a4fd-458b4cc5a10d",
+    "name" : "email",
+    "description" : "OpenID Connect built-in scope: email",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${emailScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "15a48251-9701-4c3c-8521-4bb610ae9f49",
+      "name" : "email verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "emailVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email_verified",
+        "jsonType.label" : "boolean"
+      }
+    }, {
+      "id" : "f12f9f6c-4d0f-4976-9045-15810f590e0e",
+      "name" : "email",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "email",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "email",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "b05449c0-838d-4367-b025-b966c832f258",
+    "name" : "microprofile-jwt",
+    "description" : "Microprofile - JWT built-in scope",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "false"
+    },
+    "protocolMappers" : [ {
+      "id" : "af3fa28e-c97f-4665-9216-eb03cb9add12",
+      "name" : "upn",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "upn",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "a73f3bc5-2906-4f76-bc30-22c9d9e5b544",
+      "name" : "groups",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "multivalued" : "true",
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "foo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "groups",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "44d5e8e5-1b4c-4543-b26d-99e92d7e6bf9",
+    "name" : "offline_access",
+    "description" : "OpenID Connect built-in scope: offline_access",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "consent.screen.text" : "${offlineAccessScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    }
+  }, {
+    "id" : "7a65cce0-c626-4790-b991-614c605360b3",
+    "name" : "phone",
+    "description" : "OpenID Connect built-in scope: phone",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${phoneScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "95d11cf7-7164-479f-a01e-ffe14987b1a6",
+      "name" : "phone number",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumber",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "186bc4e0-2562-494e-aed8-dc2cb0c293b4",
+      "name" : "phone number verified",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "phoneNumberVerified",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "phone_number_verified",
+        "jsonType.label" : "boolean"
+      }
+    } ]
+  }, {
+    "id" : "9f292dad-63cb-4088-9fb6-8ea96ee60757",
+    "name" : "profile",
+    "description" : "OpenID Connect built-in scope: profile",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "true",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${profileScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "97fb740d-8f1d-4fce-b96a-2b699ff67e7c",
+      "name" : "full name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-full-name-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "userinfo.token.claim" : "true"
+      }
+    }, {
+      "id" : "463ef118-fbb2-401a-a301-ca3f0ad80e3a",
+      "name" : "gender",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "gender",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "gender",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "6eb7788f-079e-4742-92bf-92a405334acb",
+      "name" : "profile",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "profile",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "profile",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "2450762b-aeee-4188-a79e-2381e4977a80",
+      "name" : "picture",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "picture",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "picture",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b6317a52-42ad-49a5-a51d-60510b891767",
+      "name" : "updated at",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "updatedAt",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "updated_at",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "2c46bbf7-9306-4c78-82ea-1b37301f6236",
+      "name" : "birthdate",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "birthdate",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "birthdate",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "cb00bdf2-886e-4ed9-9908-7efde2f63891",
+      "name" : "username",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "username",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "preferred_username",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "5ca15004-267f-4d2b-97a2-ad70e70cb616",
+      "name" : "given name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "firstName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "given_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "cef403bd-a234-44da-9dd9-4fafd0ce3a28",
+      "name" : "locale",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "locale",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "locale",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "1f8ded8b-ed7e-46cd-9b09-50ae9010fc5f",
+      "name" : "family name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-property-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "lastName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "family_name",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "3e7b9360-fb90-4c43-a75c-c10952e44413",
+      "name" : "website",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "website",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "website",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "b79b6c5c-b23c-4234-b37e-65e6ae06d70c",
+      "name" : "zoneinfo",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "zoneinfo",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "zoneinfo",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "f2d30d7c-dad0-482c-917f-6ad6ae34269b",
+      "name" : "nickname",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "nickname",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "nickname",
+        "jsonType.label" : "String"
+      }
+    }, {
+      "id" : "53f288ae-b3d2-4e69-92fc-8cfcd9cd06e6",
+      "name" : "middle name",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-attribute-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "userinfo.token.claim" : "true",
+        "user.attribute" : "middleName",
+        "id.token.claim" : "true",
+        "access.token.claim" : "true",
+        "claim.name" : "middle_name",
+        "jsonType.label" : "String"
+      }
+    } ]
+  }, {
+    "id" : "93e5c892-9543-4188-8d26-8907f2b58359",
+    "name" : "role_list",
+    "description" : "SAML role list",
+    "protocol" : "saml",
+    "attributes" : {
+      "consent.screen.text" : "${samlRoleListScopeConsentText}",
+      "display.on.consent.screen" : "true"
+    },
+    "protocolMappers" : [ {
+      "id" : "b9639268-8539-4f07-a222-5416cd2ef535",
+      "name" : "role list",
+      "protocol" : "saml",
+      "protocolMapper" : "saml-role-list-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "single" : "false",
+        "attribute.nameformat" : "Basic",
+        "attribute.name" : "Role"
+      }
+    } ]
+  }, {
+    "id" : "c615ae0c-4352-47db-b995-97fb69a02038",
+    "name" : "roles",
+    "description" : "OpenID Connect scope for add user roles to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "true",
+      "consent.screen.text" : "${rolesScopeConsentText}"
+    },
+    "protocolMappers" : [ {
+      "id" : "d801d652-8ab6-4571-a6c2-3ff84d3d77fe",
+      "name" : "client roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-client-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "resource_access.${client_id}.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    }, {
+      "id" : "525351f9-45d0-46ca-b663-243bab8c767f",
+      "name" : "realm roles",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+      "consentRequired" : false,
+      "config" : {
+        "user.attribute" : "foo",
+        "access.token.claim" : "true",
+        "claim.name" : "realm_access.roles",
+        "jsonType.label" : "String",
+        "multivalued" : "true"
+      }
+    }, {
+      "id" : "c66af09c-1271-45a0-a47d-bec23a0be363",
+      "name" : "audience resolve",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-audience-resolve-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ]
+  }, {
+    "id" : "164275d0-e532-4a8e-a2cc-a2444dd0c0d9",
+    "name" : "web-origins",
+    "description" : "OpenID Connect scope for add allowed web origins to the access token",
+    "protocol" : "openid-connect",
+    "attributes" : {
+      "include.in.token.scope" : "false",
+      "display.on.consent.screen" : "false",
+      "consent.screen.text" : ""
+    },
+    "protocolMappers" : [ {
+      "id" : "d4df64af-43df-4f9a-8cb0-014ec984f4e5",
+      "name" : "allowed web origins",
+      "protocol" : "openid-connect",
+      "protocolMapper" : "oidc-allowed-origins-mapper",
+      "consentRequired" : false,
+      "config" : { }
+    } ]
+  } ],
+  "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins" ],
+  "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ],
+  "browserSecurityHeaders" : {
+    "contentSecurityPolicyReportOnly" : "",
+    "xContentTypeOptions" : "nosniff",
+    "xRobotsTag" : "none",
+    "xFrameOptions" : "SAMEORIGIN",
+    "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+    "xXSSProtection" : "1; mode=block",
+    "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
+  },
+  "smtpServer" : { },
+  "eventsEnabled" : false,
+  "eventsListeners" : [ "jboss-logging" ],
+  "enabledEventTypes" : [ ],
+  "adminEventsEnabled" : false,
+  "adminEventsDetailsEnabled" : false,
+  "components" : {
+    "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ {
+      "id" : "abae568d-7edc-4a5d-994a-58b85a11cce8",
+      "name" : "Full Scope Disabled",
+      "providerId" : "scope",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "5e31ae85-6bf4-49a1-9c64-4ab7c07f0f68",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "08b28efd-6878-4501-9bcc-45e375f15149",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "authenticated",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper" ]
+      }
+    }, {
+      "id" : "682b1c00-5890-468f-9375-5e55fbc2b5d3",
+      "name" : "Trusted Hosts",
+      "providerId" : "trusted-hosts",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "host-sending-registration-request-must-match" : [ "true" ],
+        "client-uris-must-match" : [ "true" ]
+      }
+    }, {
+      "id" : "f0b317d6-3f8d-4abf-9036-826eced2b651",
+      "name" : "Consent Required",
+      "providerId" : "consent-required",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : { }
+    }, {
+      "id" : "3088cdf2-bd49-4385-baa7-e849056153da",
+      "name" : "Allowed Client Scopes",
+      "providerId" : "allowed-client-templates",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allow-default-scopes" : [ "true" ]
+      }
+    }, {
+      "id" : "d992c0f8-43fb-435a-8be0-ecd11cca3f64",
+      "name" : "Max Clients Limit",
+      "providerId" : "max-clients",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "max-clients" : [ "200" ]
+      }
+    }, {
+      "id" : "2d30f0b3-0999-4524-8e85-44e6cc275147",
+      "name" : "Allowed Protocol Mapper Types",
+      "providerId" : "allowed-protocol-mappers",
+      "subType" : "anonymous",
+      "subComponents" : { },
+      "config" : {
+        "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper" ]
+      }
+    } ],
+    "org.keycloak.keys.KeyProvider" : [ {
+      "id" : "a556ee11-70fb-41c4-b3db-424d6bb7b07c",
+      "name" : "fallback-RS256",
+      "providerId" : "rsa-generated",
+      "subComponents" : { },
+      "config" : {
+        "privateKey" : [ "MIIEpAIBAAKCAQEAtwEPRYFEVSB/rxQHv5O5WTEeBrHOon30XmoRZPR/BtcckXdLbBDeZ9TFsSx3Wn7xpBI2c+i74kzGMnV/VB3cec9jFJeqBUQ9V/ahDIam+Z/51MDQFiHG6H+eKnngjsEDfWnXQ+HUG/XJEFyQvpkBkzDx1wvTmYnjxG0vBnUl3PG00hTfpdHCU1EXJ1DexqSW/oJXtK0W6/fVn6skry6Kq8NhGFQHoDX0C9nL+aJyGf7atKuaZPXYchJDnkvqpPcovU/TNiqB6vg+kqILLzWmCw/RhFbDecIos+Ly2kM0MBNPvcR9kU/ZBUgir7EanxZe0GOtO5ME3HyUSJcP8MOGGQIDAQABAoIBAHURVHeeDdx3Abc6FQrUsUkBRrf5nroL4PtU1vPCBFCX40qbCcCDugKp9h002NUnR+UxUWwsgaRugIte5qkkwRmbNULDEpxz3toah0PAD6i4UdVr0rGVweyRVtjNRn2Ls3PS9UYTfOC2Bn1U+bMzpfJG6S4r/pzFvNK3FdIHtsTzNO1ZpRknRp7peB8pzlFEUt8oPD0iRB1AEn6yJ5hYGhN5H7aVhhYmk9tbFSdxonnmL4jMkHzX5Z6PJG/GOhw6jCNT77xHJNVtnYsuIzCztnkw2voitYTlVhYHSbKvF1k6egZf/3EZRK/FTjOAJuxSlXuub3Geq/MyzShHIsepkdECgYEA5Cv1TtHUaL/81knJqVZyCWqVDHBwcEYggYYSkXFOBNS63KNZSL+vkuL214BvKh+oyjCqJJGbt7itR7CkTUto0ZTH4MyBJG8I2C43mT052oIVDqgpdjJfgwL3/fHEmUpExqPkIWiFXgePbm6sjZTVHhYLN3+uvJ7D9/JIaRCpdO8CgYEAzVLd3x43JCTziSKwO+RlbgYSND/sPFo+gHzt2pKDFPMUBtDVvMdKKMZQKB4BE2S0JDVhazdrZ+JTjPiz/JfJi3ct+GuGVS0TaK7wWo2UF0Wee1+yM4NCJMEtMwiiG1j8EY8nVBFjJrGNPV8xYXZy+K8vCkmRsPC3XOLfR2eihXcCgYEAzvDrcIwweLy/pN6Rbur/THkFK54C7GE99BtUVeMMnqcNvzTLsoZfx/nfZL6QlATYwmB2v+nr8ConxqB3s77UF1k4GzN/YTrvK5pnRK1Z/ksCrCNqT1AKfjlAEGqpI1pPnFVif8ZbR1fWB5OLHnHBBKN7kt9T7LCWDhgJAnlhJ7MCgYBudhh7gsvznBWRP6JEdnnDGW0Nwx4a0goyIgPsxUnUKXoquItkxmq1SQuyqYG2p0Tq/fTtM6GLAA4nF13tlNOPPozyyxY4GMoKVaNldCmp44CBq1g5snIRSARDIm/j+pmR8MwdxETtejQcQmxUnN75v3W1OSMyaC6dwEiTJ8QdvQKBgQCLEJu51Ga0BFI8OpzK9UbCcewKZMm1rhU95zHMLjXBpngo6ptzwIt/rPkhODGLawFvGwLE7kjdLNa2f3h+6okc3PktzAIU4vYVyxgnQcQbBfWKw5HhoE4s//e52xf6idPxQpZE4kew380a1iRLiIAhuU6LNAGfCZuQOEx3Ga4I5Q==" ],
+        "certificate" : [ "MIICmzCCAYMCBgF2H/bTZjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjAxMjAxMjAxODU4WhcNMzAxMjAxMjAyMDM4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3AQ9FgURVIH+vFAe/k7lZMR4Gsc6iffReahFk9H8G1xyRd0tsEN5n1MWxLHdafvGkEjZz6LviTMYydX9UHdx5z2MUl6oFRD1X9qEMhqb5n/nUwNAWIcbof54qeeCOwQN9addD4dQb9ckQXJC+mQGTMPHXC9OZiePEbS8GdSXc8bTSFN+l0cJTURcnUN7GpJb+gle0rRbr99WfqySvLoqrw2EYVAegNfQL2cv5onIZ/tq0q5pk9dhyEkOeS+qk9yi9T9M2KoHq+D6SogsvNaYLD9GEVsN5wiiz4vLaQzQwE0+9xH2RT9kFSCKvsRqfFl7QY607kwTcfJRIlw/ww4YZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJgZ70TD5EkfJHxHRtoNeCl0ILYTQOR/pEAIlUSi5Hia/1QQY/w7vhyyFOXcxSPr3TI+cnxzKA8HY693QfH/2+3vTTljlmI2rVuulpQ4JV7cUtqWgqzP989okArXKr/j+rbQHYcHxC6jl1QWXVa0wCqWNpQeGluyyTS/n0UrkX6WRTAHDl29Z4zP7vVSp95uOxotsN3T9XbdozGDs4jDIzjzvcFSgyEthlE3Mhe1sl66whMmLYrishIGS165STpyWmppEdXZLQR9gdXvpd8dZu20Z0mgRMVlTwWWHqNj8kQ4TRGCpoZIMMUKvUHAsUgjDbjWc8KM5Okb5DmjzNeqMAg=" ],
+        "priority" : [ "-100" ],
+        "algorithm" : [ "RS256" ]
+      }
+    }, {
+      "id" : "d353a80f-09e4-4add-b247-2bbb54e308ea",
+      "name" : "fallback-HS256",
+      "providerId" : "hmac-generated",
+      "subComponents" : { },
+      "config" : {
+        "kid" : [ "7dafab66-71cc-4e8e-8040-5f679a5ee3d9" ],
+        "secret" : [ "qpsp6U2ArEp8akX6EcXfC97zcUTETE0u1S23BDlwHoS22TWmy_u_xCK2I67q13FGLTZi-fjA1Du4BghznxTxtw" ],
+        "priority" : [ "-100" ],
+        "algorithm" : [ "HS256" ]
+      }
+    } ]
+  },
+  "internationalizationEnabled" : false,
+  "supportedLocales" : [ ],
+  "authenticationFlows" : [ {
+    "id" : "33178e21-6815-4cfe-90d1-cab9997100e1",
+    "alias" : "Account verification options",
+    "description" : "Method with which to verity the existing account",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "idp-email-verification",
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "flowAlias" : "Verify Existing Account by Re-authentication",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "ff0d9476-ea11-4274-bb48-82ade2779400",
+    "alias" : "Authentication Options",
+    "description" : "Authentication options.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "basic-auth",
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "basic-auth-otp",
+      "requirement" : "DISABLED",
+      "priority" : 20,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "auth-spnego",
+      "requirement" : "DISABLED",
+      "priority" : 30,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    } ]
+  }, {
+    "id" : "bfbbc2d5-cae2-45ca-bff8-c5f3c9e5d7de",
+    "alias" : "Browser - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    } ]
+  }, {
+    "id" : "03093ffd-0716-441e-8ab5-989cc9b518db",
+    "alias" : "Direct Grant - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "direct-grant-validate-otp",
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    } ]
+  }, {
+    "id" : "ce79ff5e-f404-4b28-aadc-7b836cf0ff2a",
+    "alias" : "First broker login - Conditional OTP",
+    "description" : "Flow to determine if the OTP is required for the authentication",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "auth-otp-form",
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    } ]
+  }, {
+    "id" : "368356f6-b02e-48e3-9864-2065f60df1e0",
+    "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
+    }, {
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "flowAlias" : "Account verification options",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "f8f04def-57da-458b-9a0f-ff8f24f7fcf7",
+    "alias" : "Reset - Conditional OTP",
+    "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "conditional-user-configured",
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "reset-otp",
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    } ]
+  }, {
+    "id" : "f4633c14-16f9-4556-9d01-aa33148aeb58",
+    "alias" : "User creation or linking",
+    "description" : "Flow for the existing/non-existing user alternatives",
+    "providerId" : "basic-flow",
+    "topLevel" : false,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticatorConfig" : "create unique user config",
+      "authenticator" : "idp-create-user-if-unique",
+      "requirement" : "ALTERNATIVE",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "requirement" : "ALTERNATIVE",
+      "priority" : 20,
+      "flowAlias" : "Handle Existing Account",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "32e6a824-f60b-4203-a2c7-851d15d27c24",
+    "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
+    }, {
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "flowAlias" : "First broker login - Conditional OTP",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "53a25f1d-5a02-43b8-9001-12193f106768",
+    "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" : "0ebfac9b-087e-47d2-8a18-d6c93ad82da1",
+    "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
+    }, {
+      "authenticator" : "client-secret-jwt",
+      "requirement" : "ALTERNATIVE",
+      "priority" : 30,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "authenticator" : "client-x509",
+      "requirement" : "ALTERNATIVE",
+      "priority" : 40,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    } ]
+  }, {
+    "id" : "c15e3e85-620f-4786-a4f0-f3600037a9a7",
+    "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" : "REQUIRED",
+      "priority" : 20,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "requirement" : "CONDITIONAL",
+      "priority" : 30,
+      "flowAlias" : "Direct Grant - Conditional OTP",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "5300e33a-1a6a-4966-a3b6-6b10d8c2fe6f",
+    "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" : "beb20adc-57e4-458b-b9ec-570f9c6b04c9",
+    "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
+    }, {
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "flowAlias" : "User creation or linking",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "e4b593f3-87a9-45b0-894e-49ddf2f94b56",
+    "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
+    }, {
+      "requirement" : "CONDITIONAL",
+      "priority" : 20,
+      "flowAlias" : "Browser - Conditional OTP",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "609c52bb-11e4-4c11-aaef-956104778231",
+    "alias" : "http challenge",
+    "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
+    "providerId" : "basic-flow",
+    "topLevel" : true,
+    "builtIn" : true,
+    "authenticationExecutions" : [ {
+      "authenticator" : "no-cookie-redirect",
+      "requirement" : "REQUIRED",
+      "priority" : 10,
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : false
+    }, {
+      "requirement" : "REQUIRED",
+      "priority" : 20,
+      "flowAlias" : "Authentication Options",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "c818e5d7-e848-4c02-ba62-0cbda7fb5b03",
+    "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" : "d28e35a6-a498-4426-aa68-5b79efcee7fc",
+    "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" : "fd2b230e-a2ea-4c0b-8b43-2662997b61e0",
+    "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
+    }, {
+      "requirement" : "CONDITIONAL",
+      "priority" : 40,
+      "flowAlias" : "Reset - Conditional OTP",
+      "userSetupAllowed" : false,
+      "autheticatorFlow" : true
+    } ]
+  }, {
+    "id" : "104e2bb6-e12a-4c8a-96a0-d30b75177ee0",
+    "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" : "298b2e0b-ef4d-40d6-94f0-d74b8eaf0cf3",
+    "alias" : "create unique user config",
+    "config" : {
+      "require.password.update.after.registration" : "false"
+    }
+  }, {
+    "id" : "abd8ab33-adcd-4c79-abf8-be2333a79255",
+    "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,
+    "priority" : 10,
+    "config" : { }
+  }, {
+    "alias" : "terms_and_conditions",
+    "name" : "Terms and Conditions",
+    "providerId" : "terms_and_conditions",
+    "enabled" : false,
+    "defaultAction" : false,
+    "priority" : 20,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PASSWORD",
+    "name" : "Update Password",
+    "providerId" : "UPDATE_PASSWORD",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 30,
+    "config" : { }
+  }, {
+    "alias" : "UPDATE_PROFILE",
+    "name" : "Update Profile",
+    "providerId" : "UPDATE_PROFILE",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 40,
+    "config" : { }
+  }, {
+    "alias" : "VERIFY_EMAIL",
+    "name" : "Verify Email",
+    "providerId" : "VERIFY_EMAIL",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 50,
+    "config" : { }
+  }, {
+    "alias" : "update_user_locale",
+    "name" : "Update User Locale",
+    "providerId" : "update_user_locale",
+    "enabled" : true,
+    "defaultAction" : false,
+    "priority" : 1000,
+    "config" : { }
+  } ],
+  "browserFlow" : "browser",
+  "registrationFlow" : "registration",
+  "directGrantFlow" : "direct grant",
+  "resetCredentialsFlow" : "reset credentials",
+  "clientAuthenticationFlow" : "clients",
+  "dockerAuthenticationFlow" : "docker auth",
+  "attributes" : {
+    "clientOfflineSessionMaxLifespan" : "0",
+    "clientSessionIdleTimeout" : "0",
+    "clientSessionMaxLifespan" : "0",
+    "clientOfflineSessionIdleTimeout" : "0"
+  },
+  "keycloakVersion" : "11.0.3",
+  "userManagedAccessAllowed" : false
+} ]
\ No newline at end of file
diff --git a/docker/localstack/SAML-Metadata-IDPSSODescriptor.xml b/docker/localstack/SAML-Metadata-IDPSSODescriptor.xml
new file mode 100644
index 0000000..9699b99
--- /dev/null
+++ b/docker/localstack/SAML-Metadata-IDPSSODescriptor.xml
@@ -0,0 +1,36 @@
+<md:EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+                       xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+                       Name="urn:keycloak">
+    <md:EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
+                         xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+                         xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+                         entityID="http://localhost:8080/auth/realms/master">
+        <md:IDPSSODescriptor WantAuthnRequestsSigned="true"
+                             protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+            <md:KeyDescriptor use="signing">
+                <ds:KeyInfo>
+                    <ds:KeyName>x3XW_ih67i2tvaa_4U4HxS7NXwT68I7zuYyyfTOuMJE</ds:KeyName>
+                    <ds:X509Data>
+                        <ds:X509Certificate>
+                            MIICmzCCAYMCBgF2H/bTZjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjAxMjAxMjAxODU4WhcNMzAxMjAxMjAyMDM4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3AQ9FgURVIH+vFAe/k7lZMR4Gsc6iffReahFk9H8G1xyRd0tsEN5n1MWxLHdafvGkEjZz6LviTMYydX9UHdx5z2MUl6oFRD1X9qEMhqb5n/nUwNAWIcbof54qeeCOwQN9addD4dQb9ckQXJC+mQGTMPHXC9OZiePEbS8GdSXc8bTSFN+l0cJTURcnUN7GpJb+gle0rRbr99WfqySvLoqrw2EYVAegNfQL2cv5onIZ/tq0q5pk9dhyEkOeS+qk9yi9T9M2KoHq+D6SogsvNaYLD9GEVsN5wiiz4vLaQzQwE0+9xH2RT9kFSCKvsRqfFl7QY607kwTcfJRIlw/ww4YZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJgZ70TD5EkfJHxHRtoNeCl0ILYTQOR/pEAIlUSi5Hia/1QQY/w7vhyyFOXcxSPr3TI+cnxzKA8HY693QfH/2+3vTTljlmI2rVuulpQ4JV7cUtqWgqzP989okArXKr/j+rbQHYcHxC6jl1QWXVa0wCqWNpQeGluyyTS/n0UrkX6WRTAHDl29Z4zP7vVSp95uOxotsN3T9XbdozGDs4jDIzjzvcFSgyEthlE3Mhe1sl66whMmLYrishIGS165STpyWmppEdXZLQR9gdXvpd8dZu20Z0mgRMVlTwWWHqNj8kQ4TRGCpoZIMMUKvUHAsUgjDbjWc8KM5Okb5DmjzNeqMAg=
+                        </ds:X509Certificate>
+                    </ds:X509Data>
+                </ds:KeyInfo>
+            </md:KeyDescriptor>
+            <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+                                    Location="http://localhost:8080/auth/realms/master/protocol/saml"/>
+            <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+                                    Location="http://localhost:8080/auth/realms/master/protocol/saml"/>
+            <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
+            <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
+            <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
+            <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
+            <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+                                    Location="http://localhost:8080/auth/realms/master/protocol/saml"/>
+            <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+                                    Location="http://localhost:8080/auth/realms/master/protocol/saml"/>
+            <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+                                    Location="http://localhost:8080/auth/realms/master/protocol/saml"/>
+        </md:IDPSSODescriptor>
+    </md:EntityDescriptor>
+</md:EntitiesDescriptor>
diff --git a/docker/localstack/localstack-setup.sh b/docker/localstack/localstack-setup.sh
new file mode 100644
index 0000000..aedb374
--- /dev/null
+++ b/docker/localstack/localstack-setup.sh
@@ -0,0 +1,15 @@
+echo "Creating AWS S3 bucket $LOCALSTACK_S3_BUCKET_NAME..."
+awslocal s3api create-bucket --bucket $LOCALSTACK_S3_BUCKET_NAME
+
+echo "Creating AWS SAML Provider ${LOCALSTACK_SAML_PROVIDER_NAME}..."
+awslocal iam create-saml-provider --name ${LOCALSTACK_SAML_PROVIDER_NAME} --saml-metadata-document file:///docker-entrypoint-initaws.d/SAML-Metadata-IDPSSODescriptor.xml
+
+echo "Creating AWS Role.User..."
+awslocal iam create-role --role-name Role.User --path / --assume-role-policy-document file:///docker-entrypoint-initaws.d/test-role-trust-relationship-policy.json
+awslocal iam put-role-policy --role-name Role.User --policy-name UserPolicy --policy-document file:///docker-entrypoint-initaws.d/test-role-policy.json
+
+echo "Creating AWS Role.Admin..."
+awslocal iam create-role --role-name Role.Admin --path / --assume-role-policy-document file:///docker-entrypoint-initaws.d/test-role-trust-relationship-policy.json
+awslocal iam put-role-policy --role-name Role.Admin --policy-name AdminPolicy --policy-document file:///docker-entrypoint-initaws.d/test-role-policy.json
+
+echo "... Finished"
diff --git a/docs/examples/keycloak_saml_response.xml b/docs/examples/keycloak_saml_response.xml
new file mode 100644
index 0000000..6362fe3
--- /dev/null
+++ b/docs/examples/keycloak_saml_response.xml
@@ -0,0 +1,126 @@
+<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+                Destination="https://signin.aws.amazon.com/saml" ID="ID_ce1aec42-6d1a-4ea2-b37d-1c552d93586d"
+                IssueInstant="2020-12-06T10:43:56.880Z" Version="2.0">
+    <saml:Issuer>http://localhost:8888/auth/realms/master</saml:Issuer>
+    <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+        <dsig:SignedInfo>
+            <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+            <dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+            <dsig:Reference URI="#ID_ce1aec42-6d1a-4ea2-b37d-1c552d93586d">
+                <dsig:Transforms>
+                    <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+                    <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                </dsig:Transforms>
+                <dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+                <dsig:DigestValue>6jtiYOvN8KfbtkhydQfWwNt06S6rRtAKpHW06t98HJ4=</dsig:DigestValue>
+            </dsig:Reference>
+        </dsig:SignedInfo>
+        <dsig:SignatureValue>
+            rt4ATUsVZzyocm+1UjxTb9QfooF73e7tkGTnsEfZTLH3vqKywCkPwgGdX6M4xxHW8pNz5iBSS4gw/b2zu7+MfnP1yE19T+0uCoLQMfVEx4zroHd39ILdZYn0LhW8H/5NDOYG7Z6Mcgekl5c9Y97OkVWgKo60RsX7Prntv3NOLO4gxpd7sBj29YtCOYMwe1DgLSCdKPUiKaVhxfVDHHsV3HU97omtoG4m3YbINTuu0au+zTMOfB7r6yLREnhABhRQR5Q1HgSdG4KJXjz4N1zsuSxF1wXQf0oRz3/IyEIYMXvENfY4nkDlYmm2QNP+WtNaFH2BdvCa1xYuZMOzWZzdGQ==
+        </dsig:SignatureValue>
+        <dsig:KeyInfo>
+            <dsig:KeyName>x3XW_ih67i2tvaa_4U4HxS7NXwT68I7zuYyyfTOuMJE</dsig:KeyName>
+            <dsig:X509Data>
+                <dsig:X509Certificate>
+                    MIICmzCCAYMCBgF2H/bTZjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjAxMjAxMjAxODU4WhcNMzAxMjAxMjAyMDM4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3AQ9FgURVIH+vFAe/k7lZMR4Gsc6iffReahFk9H8G1xyRd0tsEN5n1MWxLHdafvGkEjZz6LviTMYydX9UHdx5z2MUl6oFRD1X9qEMhqb5n/nUwNAWIcbof54qeeCOwQN9addD4dQb9ckQXJC+mQGTMPHXC9OZiePEbS8GdSXc8bTSFN+l0cJTURcnUN7GpJb+gle0rRbr99WfqySvLoqrw2EYVAegNfQL2cv5onIZ/tq0q5pk9dhyEkOeS+qk9yi9T9M2KoHq+D6SogsvNaYLD9GEVsN5wiiz4vLaQzQwE0+9xH2RT9kFSCKvsRqfFl7QY607kwTcfJRIlw/ww4YZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJgZ70TD5EkfJHxHRtoNeCl0ILYTQOR/pEAIlUSi5Hia/1QQY/w7vhyyFOXcxSPr3TI+cnxzKA8HY693QfH/2+3vTTljlmI2rVuulpQ4JV7cUtqWgqzP989okArXKr/j+rbQHYcHxC6jl1QWXVa0wCqWNpQeGluyyTS/n0UrkX6WRTAHDl29Z4zP7vVSp95uOxotsN3T9XbdozGDs4jDIzjzvcFSgyEthlE3Mhe1sl66whMmLYrishIGS165STpyWmppEdXZLQR9gdXvpd8dZu20Z0mgRMVlTwWWHqNj8kQ4TRGCpoZIMMUKvUHAsUgjDbjWc8KM5Okb5DmjzNeqMAg=
+                </dsig:X509Certificate>
+            </dsig:X509Data>
+            <dsig:KeyValue>
+                <dsig:RSAKeyValue>
+                    <dsig:Modulus>
+                        twEPRYFEVSB/rxQHv5O5WTEeBrHOon30XmoRZPR/BtcckXdLbBDeZ9TFsSx3Wn7xpBI2c+i74kzGMnV/VB3cec9jFJeqBUQ9V/ahDIam+Z/51MDQFiHG6H+eKnngjsEDfWnXQ+HUG/XJEFyQvpkBkzDx1wvTmYnjxG0vBnUl3PG00hTfpdHCU1EXJ1DexqSW/oJXtK0W6/fVn6skry6Kq8NhGFQHoDX0C9nL+aJyGf7atKuaZPXYchJDnkvqpPcovU/TNiqB6vg+kqILLzWmCw/RhFbDecIos+Ly2kM0MBNPvcR9kU/ZBUgir7EanxZe0GOtO5ME3HyUSJcP8MOGGQ==
+                    </dsig:Modulus>
+                    <dsig:Exponent>AQAB</dsig:Exponent>
+                </dsig:RSAKeyValue>
+            </dsig:KeyValue>
+        </dsig:KeyInfo>
+    </dsig:Signature>
+    <samlp:Status>
+        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
+    </samlp:Status>
+    <saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_109a16c9-4928-4aee-a438-a617ebeb39fa"
+                    IssueInstant="2020-12-06T10:43:56.880Z" Version="2.0">
+        <saml:Issuer>http://localhost:8888/auth/realms/master</saml:Issuer>
+        <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+            <dsig:SignedInfo>
+                <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                <dsig:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
+                <dsig:Reference URI="#ID_109a16c9-4928-4aee-a438-a617ebeb39fa">
+                    <dsig:Transforms>
+                        <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
+                        <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+                    </dsig:Transforms>
+                    <dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
+                    <dsig:DigestValue>6cKd6YcnCIu+Okl5WpLvGV9QgsZsa+Z0eCE/xH7HrOM=</dsig:DigestValue>
+                </dsig:Reference>
+            </dsig:SignedInfo>
+            <dsig:SignatureValue>
+                gVWp6mEHwoTejn/IbGd76rasGkyIj31MTi4xQQxLglwSC2gbagVYmiGSU9LRXNxjzgK5gm3r9b88ZT1PtLunYCkmiA+RgKzOuZqWZKi2ykIGQpdJD9DkFj1bvjL5Fwucbp//+/cosdo8dJbJAybKVu5EL+IYFxC7loqJzsCgwBr7zRk5F3Dn6tbjsnsbN5+Wx1ykwC4zolp2zdot+4fH2tKaFoGT1ZFQaxw/zIaveuVgR1vy9agg4sn7PAGMHQU/B0tib2kllC2+AjJiPqwFT9y5Yp9MdDaztIcr0oVMefzCFk6I+EwcGtWh8j+bKEAjXF3QzG+RlP2DUktavkTj0w==
+            </dsig:SignatureValue>
+            <dsig:KeyInfo>
+                <dsig:KeyName>x3XW_ih67i2tvaa_4U4HxS7NXwT68I7zuYyyfTOuMJE</dsig:KeyName>
+                <dsig:X509Data>
+                    <dsig:X509Certificate>
+                        MIICmzCCAYMCBgF2H/bTZjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjAxMjAxMjAxODU4WhcNMzAxMjAxMjAyMDM4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3AQ9FgURVIH+vFAe/k7lZMR4Gsc6iffReahFk9H8G1xyRd0tsEN5n1MWxLHdafvGkEjZz6LviTMYydX9UHdx5z2MUl6oFRD1X9qEMhqb5n/nUwNAWIcbof54qeeCOwQN9addD4dQb9ckQXJC+mQGTMPHXC9OZiePEbS8GdSXc8bTSFN+l0cJTURcnUN7GpJb+gle0rRbr99WfqySvLoqrw2EYVAegNfQL2cv5onIZ/tq0q5pk9dhyEkOeS+qk9yi9T9M2KoHq+D6SogsvNaYLD9GEVsN5wiiz4vLaQzQwE0+9xH2RT9kFSCKvsRqfFl7QY607kwTcfJRIlw/ww4YZAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJgZ70TD5EkfJHxHRtoNeCl0ILYTQOR/pEAIlUSi5Hia/1QQY/w7vhyyFOXcxSPr3TI+cnxzKA8HY693QfH/2+3vTTljlmI2rVuulpQ4JV7cUtqWgqzP989okArXKr/j+rbQHYcHxC6jl1QWXVa0wCqWNpQeGluyyTS/n0UrkX6WRTAHDl29Z4zP7vVSp95uOxotsN3T9XbdozGDs4jDIzjzvcFSgyEthlE3Mhe1sl66whMmLYrishIGS165STpyWmppEdXZLQR9gdXvpd8dZu20Z0mgRMVlTwWWHqNj8kQ4TRGCpoZIMMUKvUHAsUgjDbjWc8KM5Okb5DmjzNeqMAg=
+                    </dsig:X509Certificate>
+                </dsig:X509Data>
+                <dsig:KeyValue>
+                    <dsig:RSAKeyValue>
+                        <dsig:Modulus>
+                            twEPRYFEVSB/rxQHv5O5WTEeBrHOon30XmoRZPR/BtcckXdLbBDeZ9TFsSx3Wn7xpBI2c+i74kzGMnV/VB3cec9jFJeqBUQ9V/ahDIam+Z/51MDQFiHG6H+eKnngjsEDfWnXQ+HUG/XJEFyQvpkBkzDx1wvTmYnjxG0vBnUl3PG00hTfpdHCU1EXJ1DexqSW/oJXtK0W6/fVn6skry6Kq8NhGFQHoDX0C9nL+aJyGf7atKuaZPXYchJDnkvqpPcovU/TNiqB6vg+kqILLzWmCw/RhFbDecIos+Ly2kM0MBNPvcR9kU/ZBUgir7EanxZe0GOtO5ME3HyUSJcP8MOGGQ==
+                        </dsig:Modulus>
+                        <dsig:Exponent>AQAB</dsig:Exponent>
+                    </dsig:RSAKeyValue>
+                </dsig:KeyValue>
+            </dsig:KeyInfo>
+        </dsig:Signature>
+        <saml:Subject>
+            <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
+                G-6ea85412-d427-4a07-a5dc-b7344aa763ec
+            </saml:NameID>
+            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+                <saml:SubjectConfirmationData NotOnOrAfter="2020-12-06T10:44:54.880Z"
+                                              Recipient="https://signin.aws.amazon.com/saml"/>
+            </saml:SubjectConfirmation>
+        </saml:Subject>
+        <saml:Conditions NotBefore="2020-12-06T10:43:54.880Z" NotOnOrAfter="2020-12-06T10:44:54.880Z">
+            <saml:AudienceRestriction>
+                <saml:Audience>urn:amazon:webservices</saml:Audience>
+            </saml:AudienceRestriction>
+        </saml:Conditions>
+        <saml:AuthnStatement AuthnInstant="2020-12-06T10:43:56.880Z"
+                             SessionIndex="54256235-ebfd-4884-96f8-8a069e7675df::2e592dad-b2fc-4a5f-9c76-40a1cf860e29"
+                             SessionNotOnOrAfter="2020-12-06T20:43:56.880Z">
+            <saml:AuthnContext>
+                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
+                </saml:AuthnContextClassRef>
+            </saml:AuthnContext>
+        </saml:AuthnStatement>
+        <saml:AttributeStatement>
+            <saml:Attribute FriendlyName="Session Duration"
+                            Name="https://aws.amazon.com/SAML/Attributes/SessionDuration"
+                            NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">28800
+                </saml:AttributeValue>
+            </saml:Attribute>
+            <saml:Attribute FriendlyName="Session Name" Name="https://aws.amazon.com/SAML/Attributes/RoleSessionName"
+                            NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">admin
+                </saml:AttributeValue>
+            </saml:Attribute>
+            <saml:Attribute FriendlyName="Session Role" Name="https://aws.amazon.com/SAML/Attributes/Role"
+                            NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+                    arn:aws:iam::000000000000:role/Role.User,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider
+                </saml:AttributeValue>
+                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
+                    arn:aws:iam::000000000000:role/Role.Admin,arn:aws:iam::000000000000:saml-provider/SamlExampleProvider
+                </saml:AttributeValue>
+            </saml:Attribute>
+        </saml:AttributeStatement>
+    </saml:Assertion>
+</samlp:Response>
diff --git a/docs/images/keycloak-welcome-page.png b/docs/images/keycloak-welcome-page.png
new file mode 100644
index 0000000..7034481
Binary files /dev/null and b/docs/images/keycloak-welcome-page.png differ
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 882322c..94ee18e 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -1,3 +1,5 @@
+awscli==1.18.192
+awscli-local==0.9
 bump2version==1.0.1
 twine==3.2.0
 Pygments==2.7.2


Test patch:
diff --git a/docker/localstack/test-role-policy.json b/docker/localstack/test-role-policy.json
new file mode 100644
index 0000000..9cc9d92
--- /dev/null
+++ b/docker/localstack/test-role-policy.json
@@ -0,0 +1,10 @@
+{
+    "Version": "2012-10-17",
+    "Statement": [
+        {
+            "Effect": "Allow",
+            "Action": "*",
+            "Resource": "*"
+        }
+    ]
+}
diff --git a/docker/localstack/test-role-trust-relationship-policy.json b/docker/localstack/test-role-trust-relationship-policy.json
new file mode 100644
index 0000000..18ca80f
--- /dev/null
+++ b/docker/localstack/test-role-trust-relationship-policy.json
@@ -0,0 +1,17 @@
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Principal": {
+        "Federated": "arn:aws:iam::000000000000:saml-provider/SamlExampleProvider"
+      },
+      "Action": "sts:AssumeRoleWithSAML",
+      "Condition": {
+        "StringEquals": {
+          "SAML:aud": "https://signin.aws.amazon.com/saml"
+        }
+      }
+    }
+  ]
+}