<div dir="ltr"><p dir="ltr">You can implement a dynamic keycloak config resolver that can work with realms not known in advance. <span style="font-size:12.8px">I've just been doing exactly the same thing. My requirement was to use the host name to identify a realm, so</span><span style="font-size:12.8px"> </span><a href="http://tenanta.mydomain.com/my-client" target="_blank" style="font-size:12.8px">tenanta.mydomain.com/my-client</a><span style="font-size:12.8px"> </span><span style="font-size:12.8px">would use realm "tenanta",</span><a href="http://tenantb.mydomain.com/my-client" target="_blank" style="font-size:12.8px">tenantb.mydomain.com/my-client</a><span style="font-size:12.8px"> </span><span style="font-size:12.8px">would use "tenantb" etc and realms could be created dynamically and my-client would immediately work with those new realms without requiring a reboot or re-configuration. </span><span style="font-size:12.8px">There are different KeycloakConfigResolver implementations you can use to do this, depending on your client configuration.</span></p><p dir="ltr"><span style="font-size:12.8px">If the client is configured as public (no client secret) or if the client secret for the application is the same in each realm, then you can use a keycloak template for configuration. So you could</span><span style="font-size:12.8px"> deploy a WEB-INF/keycloak-template.json file which looks something like this...</span></p><div dir="ltr" style="font-size:12.8px"><div><span style="color:rgb(51,51,51);font-family:Consolas,Menlo,"Liberation Mono",Courier,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap">{</span><br></div><div><pre style="white-space:pre-wrap;margin-top:0px;margin-bottom:0px;padding:0px;font-family:Consolas,Menlo,"Liberation Mono",Courier,monospace;font-size:12px;line-height:1.4;color:rgb(51,51,51)"><a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-2" style="color:rgb(53,114,176)"></a> <span style="color:navy">"realm"</span>: <span style="color:rgb(187,136,68)">"tenantA"</span>,
<a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-3" style="color:rgb(53,114,176)"></a> <span style="color:navy">"realm-public-<span class="">key</span>"</span>: <span style="color:rgb(187,136,68)">"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA07H+1raA8G5lU9II9GwQ1r2yXzSeBpEC6Lz822iB+oZGi36KC6caVOyi1IVIWB/ZnxxoC8AHsn4ASYJnYUMNTjRvK9nwHCP825LD3nHFBHyQ0gUHBELRi6ZvmOu3TnyiIlnR2SCxwmND5ifgtDfKwldcdCTNWqJG5MkcOimhDEiZYLOrShH5pCcEkPE5JBj0GDGYs9AcUT8/OrJEvInVAfnMMxvzZfXhJQlXnq0HbkGPNL2LMq66bmfI7OTzWKpIIoa24DOcxvu5FEqnnfhEZ+RkhfrVVe876T7Jx9f128xOTAYgi98515+xeFGei1Qer1IJCtnE5vICKKVtDdJg1wIDAQAB"</span>,
<a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-4" style="color:rgb(53,114,176)"></a> <span style="color:navy">"auth-server-url"</span>: <span style="color:rgb(187,136,68)">"<a href="https://keycloak.mydomain.com/auth" target="_blank">https://keycloak.mydomain.com/auth</a>"</span>,
<a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-5" style="color:rgb(53,114,176)"></a> <span style="color:navy">"ssl-required"</span>: <span style="color:rgb(187,136,68)">"none"</span>,
<a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-6" style="color:rgb(53,114,176)"></a> <span style="color:navy">"resource"</span>: <span style="color:rgb(187,136,68)">"my-client"</span>,
<a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-7" style="color:rgb(53,114,176)"></a> <span style="color:navy">"public-client"</span>: <span style="font-weight:700">true</span>
<a name="m_-8955023691950085650_glomex-multi-tenant-keycloak.json-8" style="color:rgb(53,114,176)"></a>}</pre><div><br><div><div>The <span class="">KeycloakConfigResolver</span> would use this template for each realm and just overwrite the "realm" and "realm-public-<span class="">key</span>" values with the real values. To get those real values, the <span class="">KeycloakConfigResolver</span> would first work out the realm name. In my case, I derive the realm name from the hostname, so <a href="http://tenanta.mydomain.com/" target="_blank">tenanta.mydomain.com</a> would indicate "tenanta" was being used. Once you have derived the realm name, then you can do a http get request to http://<keycloak_url>/auth/realms/<tenantname> (eg. <a href="https://keycloak.mydomain.com/auth/realms/tenanta" target="_blank">https://keycloak.mydomain.com/auth/realms/tenanta</a>). This endpoint isn't secured and returns something similar to the following...</div><div><br></div></div></div></div><div><span style="color:rgb(0,0,0);font-family:monospace;font-size:medium">{</span><ul style="list-style-type:none;padding:0px;margin:0px 0px 0px 2em;color:rgb(0,0,0);font-family:monospace;font-size:medium"><li style="margin-left:15px"><div style="display:inline-block;padding:1px 2px;border-radius:2px"><span style="font-weight:bold">realm</span>: <span style="color:green">"tenantA"</span>,</div></li><li style="margin-left:15px"><div style="display:inline-block;padding:1px 2px;border-radius:2px"><span style="font-weight:bold">public_key</span>:<span style="color:green">"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA07H+1raA8G5lU9II9GwQ1r2yXzSeBpEC6Lz822iB+oZGi36KC6caVOyi1IVIWB/ZnxxoC8AHsn4ASYJnYUMNTjRvK9nwHCP825LD3nHFBHyQ0gUHBELRi6ZvmOu3TnyiIlnR2SCxwmND5ifgtDfKwldcdCTNWqJG5MkcOimhDEiZYLOrShH5pCcEkPE5JBj0GDGYs9AcUT8/OrJEvInVAfnMMxvzZfXhJQlXnq0HbkGPNL2LMq66bmfI7OTzWKpIIoa24DOcxvu5FEqnnfhEZ+RkhfrVVe876T7Jx9f128xOTAYgi98515+xeFGei1Qer1IJCtnE5vICKKVtDdJg1wIDAQAB"</span>,</div></li><li style="margin-left:15px"><div style="display:inline-block;padding:1px 2px;border-radius:2px"><span style="font-weight:bold">token-service</span>: <span style="color:green">"</span><a href="https://keycloak.cyberavenue.com.au/auth/realms/tenantA/protocol/openid-connect" target="_blank">https://keycloak.mydomain.com/auth/realms/tenantA/protocol/openid-connect</a><span style="color:green">"</span>,</div></li><li style="margin-left:15px"><div style="display:inline-block;padding:1px 2px;border-radius:2px"><span style="font-weight:bold">account-service</span>: <span style="color:green">"</span><a href="https://keycloak.cyberavenue.com.au/auth/realms/tenantA/account" target="_blank">https://keycloak.mydomain.com/auth/realms/tenantA/account</a><span style="color:green">"</span>,</div></li><li style="margin-left:15px"><div style="display:inline-block;padding:1px 2px;border-radius:2px"><span style="font-weight:bold">admin-api</span>: <span style="color:green">"</span><a href="https://keycloak.cyberavenue.com.au/auth/admin" target="_blank">https://keycloak.mydomain.com/auth/admin</a><span style="color:green">"</span>,</div></li><li style="margin-left:15px"><div style="display:inline-block;padding:1px 2px;border-radius:2px"><span style="font-weight:bold">tokens-not-before</span>: <span style="color:blue">0</span></div></li></ul><span style="color:rgb(0,0,0);font-family:monospace;font-size:medium">}</span><br></div><div><span style="color:rgb(0,0,0);font-family:monospace;font-size:medium"><br></span></div><div>The <span class="">KeycloakConfigResolver</span> then uses the "realm" and "public_key" values from that response, overrides the values from the keycloak-template.json file to create the KeycloakDeployment (using KeycloakDeploymentBuilder).<br></div><div><br></div><div>If your client isn't public and the client-secret differs and isn't known in advance, then this solution wouldn't work. In that case, another solution can be used which is slightly more complicated. The idea is the <span class="">KeycloakConfigResolver</span> does the following...</div><div><br></div><div>1/ Get a token for the admin-cli client in the "master" realm. This may require configuring a username and password that can be used used to obtain this token.</div><div>2/ Use the rest api to get a list of clients in the requested realm (ie. http get to <span style="font-size:12.8px">http://<keycloak_url>/</span>auth/admin/realms/{realm}/clients using a Bearer token obtained from step 1</div><div>3/ Iterate through the list and find the Client you're interested in (ie. client.getClientId().equals("my-client") ). You need the client UID identifier from this.</div><div>4/ Use the rest api to get the keycloak deployment installation file by doing a GET to <span style="font-size:12.8px">http://<keycloak_url></span>/auth/admin/realms/{realm}/clients/{client-uid}/installation/providers/keycloak-oidc-keycloak-json, using the Bearer token from step 1 and the client UID from step 3. Then use KeycloakDeploymentBuilder on the response body returned from this service.</div><div><br></div><div><br></div><div><br></div><div>Regards,</div><div><br></div><div>Anthony</div><div><br></div></div>
<br><div class="gmail_quote"><div dir="ltr">On 04:43, Sat, 11/06/2016 Jesse Chahal <<a href="mailto:jessec@stytch.com" target="_blank">jessec@stytch.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">The keycloak config resolver works well when all realms are known in<br>
advance. I was trying to imply in my diagram that all realms are not<br>
known in advance as realms are going to be created for new customers<br>
on demand. Doing a new production deployment whenever a SaaS product<br>
has a new customer added is not a feasible solution.<br>
<br>
On Wed, Jun 8, 2016 at 7:01 PM, Anthony Fryer <<a href="mailto:anthony.fryer@gmail.com" target="_blank">anthony.fryer@gmail.com</a>> wrote:<br>
> Why do you say "very hard to get App1 to support multiple realms (no adapter<br>
> or keycloak support)"?<br>
><br>
> Keycloak does provide multi-tenancy support via the KeycloakConfigResolver.<br>
> See <a href="https://github.com/keycloak/keycloak/tree/master/examples/multi-tenant" rel="noreferrer" target="_blank">https://github.com/keycloak/keycloak/tree/master/examples/multi-tenant</a>.<br>
><br>
> The issue would be if your app can't use a keycloak adapter.<br>
><br>
> On Thu, Jun 9, 2016 at 10:05 AM, Jesse Chahal <<a href="mailto:jessec@stytch.com" target="_blank">jessec@stytch.com</a>> wrote:<br>
>><br>
>> Hi,<br>
>><br>
>> I'm back again. I'm trying to figure out how scale Identity Providers.<br>
>> We are planning on trying to integrate our App1 with salesforce. A<br>
>> user who logs into salesforce should be able to have a native feel of<br>
>> our App1 within it. Todo this we'll probably have to end up building<br>
>> salesforce native apps. For every salesforce organization/licensee we<br>
>> will have to register an Identity provider with keycloak to make sure<br>
>> they can correctly use App1. Some configuration options we came up<br>
>> with are listed below. Has anyone else solved a similar problem?<br>
>><br>
>> OPTION 1<br>
>> ########################################################<br>
>> # Keycloak<br>
>> #<br>
>> # ---> master realm<br>
>> #<br>
>> # ---> realm 1<br>
>> #<br>
>> # --- ---> app1_client (open ID)<br>
>> #<br>
>> # --- ---> salesforce_org1_saml2.0_identity_provider<br>
>> #<br>
>> # --- ---> salesforce_org2_saml2.0_identity_provider<br>
>> #<br>
>> #<br>
>> #<br>
>> # Salesforce<br>
>> #<br>
>> # ---> org1<br>
>> #<br>
>> # ---- ----> salesforce_appX (uses App1)<br>
>> #<br>
>> # ---> org 2<br>
>> #<br>
>> # ---- ----> salesforce_appX (uses App1)<br>
>> #<br>
>> # ---- ----> salesforce_appY (uses App1)<br>
>> #<br>
>> # .....<br>
>> #<br>
>> #<br>
>> #<br>
>> # App 1<br>
>> #<br>
>> # ---> OpenID to realm1 (using adapter)<br>
>> #<br>
>> ########################################################<br>
>> benefits<br>
>> - single login page<br>
>> - single realm<br>
>> cons<br>
>> - login page with infinite number of identity provider buttons present<br>
>><br>
>><br>
>> OPTION 2<br>
>> ########################################################<br>
>> # Keycloak<br>
>> #<br>
>> # ---> master realm<br>
>> #<br>
>> # ---> realm 1<br>
>> #<br>
>> # --- ---> app1_client (open ID)<br>
>> #<br>
>> # --- ---> salesforce_org1_saml2.0_identity_provider<br>
>> #<br>
>> # ---> realm 2<br>
>> #<br>
>> # --- ---> app1_client (open ID)<br>
>> #<br>
>> # --- ---> salesforce_org2_saml2.0_identity_provider<br>
>> #<br>
>> #<br>
>> #<br>
>> # Salesforce<br>
>> #<br>
>> # ---> org1<br>
>> #<br>
>> # ---- ----> salesforce_appX (uses App1)<br>
>> #<br>
>> # ---> org 2<br>
>> #<br>
>> # ---- ----> salesforce_appX (uses App1)<br>
>> #<br>
>> # ---- ----> salesforce_appY (uses App1)<br>
>> #<br>
>> # .....<br>
>> #<br>
>> #<br>
>> #<br>
>> # App 1<br>
>> #<br>
>> # ---> OpenID to realm1, realm2, realm#.... (using adapter)<br>
>> #<br>
>> ########################################################<br>
>> benefits<br>
>> - single salesforce button per login page<br>
>> - users are more isolated in single realm<br>
>> cons<br>
>> - very hard to get App1 to support multiple realms (no adapter or<br>
>> keycloak support)<br>
>> _______________________________________________<br>
>> keycloak-user mailing list<br>
>> <a href="mailto:keycloak-user@lists.jboss.org" target="_blank">keycloak-user@lists.jboss.org</a><br>
>> <a href="https://lists.jboss.org/mailman/listinfo/keycloak-user" rel="noreferrer" target="_blank">https://lists.jboss.org/mailman/listinfo/keycloak-user</a><br>
><br>
><br>
><br>
><br>
> _______________________________________________<br>
> keycloak-user mailing list<br>
> <a href="mailto:keycloak-user@lists.jboss.org" target="_blank">keycloak-user@lists.jboss.org</a><br>
> <a href="https://lists.jboss.org/mailman/listinfo/keycloak-user" rel="noreferrer" target="_blank">https://lists.jboss.org/mailman/listinfo/keycloak-user</a><br>
</blockquote></div></div>