Merge pull request #37 from mposolda/master
KEYCLOAK-3643 Remove public-key references in keycloak.json . Add mor…
This commit is contained in:
commit
4853d4b468
11 changed files with 95 additions and 10 deletions
|
@ -31,6 +31,7 @@
|
||||||
... link:topics/oidc/java/adapter_error_handling.adoc[Error Handling]
|
... link:topics/oidc/java/adapter_error_handling.adoc[Error Handling]
|
||||||
... link:topics/oidc/java/logout.adoc[Logout]
|
... link:topics/oidc/java/logout.adoc[Logout]
|
||||||
... link:topics/oidc/java/params_forwarding.adoc[Parameters Forwarding]
|
... link:topics/oidc/java/params_forwarding.adoc[Parameters Forwarding]
|
||||||
|
... link:topics/oidc/java/client-authentication.adoc[Client Authentication]
|
||||||
... link:topics/oidc/java/multi-tenancy.adoc[Multi Tenancy]
|
... link:topics/oidc/java/multi-tenancy.adoc[Multi Tenancy]
|
||||||
... link:topics/oidc/java/application-clustering.adoc[Application Clustering]
|
... link:topics/oidc/java/application-clustering.adoc[Application Clustering]
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,17 @@
|
||||||
"community": true,
|
"community": true,
|
||||||
"product": false,
|
"product": false,
|
||||||
"images": "keycloak-images",
|
"images": "keycloak-images",
|
||||||
|
"developerguide": {
|
||||||
|
"name": "Server Developer Guide",
|
||||||
|
"link": "https://keycloak.gitbooks.io/server-developer-guide/content/"
|
||||||
|
},
|
||||||
"adminguide": {
|
"adminguide": {
|
||||||
"name": "Server Administration Guide",
|
"name": "Server Administration Guide",
|
||||||
"link": "https://keycloak.gitbooks.io/server-adminstration-guide/content/"
|
"link": "https://keycloak.gitbooks.io/server-adminstration-guide/content/"
|
||||||
|
},
|
||||||
|
"installguide": {
|
||||||
|
"name": "Server Installation and Configuration Guide",
|
||||||
|
"link": "https://keycloak.gitbooks.io/server-installation-and-configuration/content/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
74
topics/oidc/java/client-authentication.adoc
Normal file
74
topics/oidc/java/client-authentication.adoc
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
[[_client_authentication_adapter]]
|
||||||
|
==== Client Authentication
|
||||||
|
|
||||||
|
When confidential OIDC client needs to send backchannel request (eg. exchange code for the token, or refresh token) it needs to authenticate
|
||||||
|
against {{book.project.name}} server. By default, there are 2 possibilities how to authenticate client:
|
||||||
|
|
||||||
|
===== Client ID and Client Secret
|
||||||
|
|
||||||
|
This is traditional method described in OAuth2 specification. Client has a secret, which needs to be known to both adapter (application) and {{book.project.name}} server.
|
||||||
|
You can simply generate the secret for particular client in {{book.project.name}} admin console and then paste this secret in the `keycloak.json` file on the application's side:
|
||||||
|
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
"credentials": {
|
||||||
|
"secret": "19666a4f-32dd-4049-b082-684c74115f28"
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
===== Client authentication with signed JWT
|
||||||
|
|
||||||
|
This is based on the https://tools.ietf.org/html/rfc7523[RFC7523] specification. It works this way:
|
||||||
|
|
||||||
|
* Client must have the private key and certificate. In case of {{book.project.name}} this is available through the traditional `keystore` file, which is either available
|
||||||
|
on client application's classpath or somewhere on the filesystem.
|
||||||
|
|
||||||
|
* Once the client application is started, it allows to download it's public key in https://self-issued.info/docs/draft-ietf-jose-json-web-key.html[JWKS] format on URL
|
||||||
|
like http://myhost.com/myapp/k_jwks assuming that http://myhost.com/myapp is the base URL of your client application. This URL can be used by the {{book.project.name}} (see below).
|
||||||
|
|
||||||
|
* During authentication, client generates JWT token and signs it with his private key and sends it to the {{book.project.name}} in
|
||||||
|
the particular backchannel request (eg. code-to-token request) in the `client_assertion` parameter.
|
||||||
|
|
||||||
|
* {{book.project.name}} must have public key or certificate of the client, so that it can verify the signature on JWT. In {{book.project.name}} you either
|
||||||
|
need to configure client credentials for your client. First you need to choose `Signed JWT` as the method of authenticating your client in the tab `Credentials` in admin console.
|
||||||
|
Then you can choose either to:
|
||||||
|
** Configure the JWKS URL where {{book.project.name}} can download the client's public keys. This can be URL like http://myhost.com/myapp/k_jwks (see details above). This is flexible as
|
||||||
|
client can rotate it's keys anytime and {{book.project.name}} will then always download new keys when needed without need to change something in it's configuration. More acurately, {{book.project.name}}
|
||||||
|
will download new keys when it sees the token signed by unknown `kid` (Key ID).
|
||||||
|
** Upload the client's public key or certificate - either in PEM format, in JWK format or from keystore. With this option, public key is hardcoded and
|
||||||
|
needs to be changed anytime when client generates new keypair.
|
||||||
|
You can even generate your own keystore from {{book.project.name}} admin console if you don't have your own ready.
|
||||||
|
See {{book.adminguide.link}}[{{book.adminguide.name}}] for more details of setup in {{book.project.name}} admin console.
|
||||||
|
|
||||||
|
For setup on adapter's side you need to have something like this in your `keycloak.json` file:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
"credentials": {
|
||||||
|
"jwt": {
|
||||||
|
"client-keystore-file": "classpath:keystore-client.jks",
|
||||||
|
"client-keystore-type": "JKS",
|
||||||
|
"client-keystore-password": "storepass",
|
||||||
|
"client-key-password": "keypass",
|
||||||
|
"client-key-alias": "clientkey",
|
||||||
|
"token-expiration": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
With this configuration, the keystore file `keystore-client.jks` must be available on classpath in your WAR. If you don't use prefix `classpath:`
|
||||||
|
you can point to any file on the filesystem where client application is running.
|
||||||
|
|
||||||
|
{% if book.community %}
|
||||||
|
For inspiration, you can take a look at the examples distribution into the main demo example into the `product-portal` application.
|
||||||
|
|
||||||
|
|
||||||
|
===== Add your own client authentication method
|
||||||
|
|
||||||
|
This is possible. You will need to implement both client's side and server's side providers. See `Authentication SPI` section
|
||||||
|
in {{book.developerguide.link}}[{{book.developerguide.name}}] for more details.
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ The roles, security constraint mappings and {{book.project.name}} adapter config
|
||||||
<bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
|
<bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
|
||||||
<property name="realm" value="demo"/>
|
<property name="realm" value="demo"/>
|
||||||
<property name="resource" value="admin-camel-endpoint"/>
|
<property name="resource" value="admin-camel-endpoint"/>
|
||||||
<property name="realmKey" value="MIGfMA0G..."/>
|
|
||||||
<property name="bearerOnly" value="true"/>
|
<property name="bearerOnly" value="true"/>
|
||||||
<property name="authServerUrl" value="http://localhost:8080/auth" />
|
<property name="authServerUrl" value="http://localhost:8080/auth" />
|
||||||
<property name="sslRequired" value="EXTERNAL"/>
|
<property name="sslRequired" value="EXTERNAL"/>
|
||||||
|
|
|
@ -26,7 +26,6 @@ injected `KeycloakJettyAuthenticator` inside. The configuration may look like th
|
||||||
<bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
|
<bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
|
||||||
<property name="realm" value="demo"/>
|
<property name="realm" value="demo"/>
|
||||||
<property name="resource" value="custom-cxf-endpoint"/>
|
<property name="resource" value="custom-cxf-endpoint"/>
|
||||||
<property name="realmKey" value="MIGfMA0..."/>
|
|
||||||
<property name="bearerOnly" value="true"/>
|
<property name="bearerOnly" value="true"/>
|
||||||
<property name="authServerUrl" value="http://localhost:8080/auth" />
|
<property name="authServerUrl" value="http://localhost:8080/auth" />
|
||||||
<property name="sslRequired" value="EXTERNAL"/>
|
<property name="sslRequired" value="EXTERNAL"/>
|
||||||
|
|
|
@ -27,7 +27,6 @@ sshRealm=keycloak
|
||||||
{
|
{
|
||||||
"realm": "demo",
|
"realm": "demo",
|
||||||
"resource": "ssh-jmx-admin-client",
|
"resource": "ssh-jmx-admin-client",
|
||||||
"realm-public-key": "MIGfMA...",
|
|
||||||
"ssl-required" : "external",
|
"ssl-required" : "external",
|
||||||
"auth-server-url" : "http://localhost:8080/auth",
|
"auth-server-url" : "http://localhost:8080/auth",
|
||||||
"credentials": {
|
"credentials": {
|
||||||
|
|
|
@ -32,7 +32,8 @@ This is what one might look like:
|
||||||
"client-keystore" : "path/to/client-keystore.jks",
|
"client-keystore" : "path/to/client-keystore.jks",
|
||||||
"client-keystore-password" : "geheim",
|
"client-keystore-password" : "geheim",
|
||||||
"client-key-password" : "geheim",
|
"client-key-password" : "geheim",
|
||||||
"token-minimum-time-to-live" : 10
|
"token-minimum-time-to-live" : 10,
|
||||||
|
"min-time-between-jwks-requests" : 10
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -54,7 +55,9 @@ resource::
|
||||||
|
|
||||||
realm-public-key::
|
realm-public-key::
|
||||||
PEM format of the realm public key. You can obtain this from the administration console.
|
PEM format of the realm public key. You can obtain this from the administration console.
|
||||||
This is _OPTIONAL_. If not set the adapter will download this from {{book.project.name}}.
|
This is _OPTIONAL_ and it's not recommended to set it. If not set, the adapter will download this from {{book.project.name}} and
|
||||||
|
it will always re-download it when needed (eg. {{book.project.name}} rotate it's keys). However if realm-public-key is set, then adapter
|
||||||
|
will never download new keys from {{book.project.name}}, so when {{book.project.name}} rotate it's keys, adapter will break.
|
||||||
|
|
||||||
auth-server-url::
|
auth-server-url::
|
||||||
The base URL of the {{book.project.name}} server. All other {{book.project.name}} pages and REST service endpoints are derived from this. It is usually of the form `$$https://host:port/auth$$`.
|
The base URL of the {{book.project.name}} server. All other {{book.project.name}} pages and REST service endpoints are derived from this. It is usually of the form `$$https://host:port/auth$$`.
|
||||||
|
@ -198,3 +201,10 @@ token-minimum-time-to-live::
|
||||||
This is especially useful when the access token is sent to another REST client where it could expire before being evaluated.
|
This is especially useful when the access token is sent to another REST client where it could expire before being evaluated.
|
||||||
This value should never exceed the realm's access token lifespan.
|
This value should never exceed the realm's access token lifespan.
|
||||||
This is _OPTIONAL_. The default value is `0` seconds, so adapter will refresh access token just if it's expired.
|
This is _OPTIONAL_. The default value is `0` seconds, so adapter will refresh access token just if it's expired.
|
||||||
|
|
||||||
|
min-time-between-jwks-requests::
|
||||||
|
Amount of time, in seconds, specifying minimum interval between two requests to {{book.project.name}} to retrieve new public keys.
|
||||||
|
It is 10 seconds by default.
|
||||||
|
Adapter will always try to download new public key when it recognize token with unknown `kid` . However it won't try it more
|
||||||
|
than once per 10 seconds (by default). This is to avoid DoS when attacker sends lots of tokens with bad `kid` forcing adapter
|
||||||
|
to send lots of requests to {{book.project.name}}.
|
||||||
|
|
|
@ -260,7 +260,6 @@ This metadata is instead defined within server configuration (i.e. `standalone.x
|
||||||
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
|
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
|
||||||
<secure-deployment name="WAR MODULE NAME.war">
|
<secure-deployment name="WAR MODULE NAME.war">
|
||||||
<realm>demo</realm>
|
<realm>demo</realm>
|
||||||
<realm-public-key>MIGfMA0GCSqGSIb3DQEBAQUAA</realm-public-key>
|
|
||||||
<auth-server-url>http://localhost:8081/auth</auth-server-url>
|
<auth-server-url>http://localhost:8081/auth</auth-server-url>
|
||||||
<ssl-required>external</ssl-required>
|
<ssl-required>external</ssl-required>
|
||||||
<resource>customer-portal</resource>
|
<resource>customer-portal</resource>
|
||||||
|
@ -284,7 +283,6 @@ If you have multiple deployments secured by the same realm you can share the rea
|
||||||
----
|
----
|
||||||
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
|
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
|
||||||
<realm name="demo">
|
<realm name="demo">
|
||||||
<realm-public-key>MIGfMA0GCSqGSIb3DQEBA...</realm-public-key>
|
|
||||||
<auth-server-url>http://localhost:8080/auth</auth-server-url>
|
<auth-server-url>http://localhost:8080/auth</auth-server-url>
|
||||||
<ssl-required>external</ssl-required>
|
<ssl-required>external</ssl-required>
|
||||||
</realm>
|
</realm>
|
||||||
|
|
|
@ -92,7 +92,6 @@ You'll just have to figure out how the json settings match to the `org.keycloak.
|
||||||
</Entry>
|
</Entry>
|
||||||
</Map>
|
</Map>
|
||||||
</Set>
|
</Set>
|
||||||
<Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4</Set>
|
|
||||||
</New>
|
</New>
|
||||||
</Set>
|
</Set>
|
||||||
</New>
|
</New>
|
||||||
|
|
|
@ -41,7 +41,6 @@ For example:
|
||||||
|
|
||||||
|
|
||||||
keycloak.realm = demorealm
|
keycloak.realm = demorealm
|
||||||
keycloak.realmKey = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCWYuxXmsmfV+Xc9Ik8QET8lD4wuHrJAXbbutS2O/eMjQQLNK7QDX/k/XhOkhxP0YBEypqeXeGaeQJjCxDhFjJXQuewUEMlmSja3IpoJ9/hFn4Cns4m7NGO+rtvnfnwgVfsEOS5EmZhRddp+40KBPPJfTH6Vgu6KjQwuFPj6DTwIDAQAB
|
|
||||||
keycloak.auth-server-url = http://127.0.0.1:8080/auth
|
keycloak.auth-server-url = http://127.0.0.1:8080/auth
|
||||||
keycloak.ssl-required = external
|
keycloak.ssl-required = external
|
||||||
keycloak.resource = demoapp
|
keycloak.resource = demoapp
|
||||||
|
|
|
@ -18,7 +18,6 @@ admin console when we provisioned this app.
|
||||||
|
|
||||||
{
|
{
|
||||||
"realm": "example-realm",
|
"realm": "example-realm",
|
||||||
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
|
||||||
"auth-server-url": "http://localhost:8080/auth",
|
"auth-server-url": "http://localhost:8080/auth",
|
||||||
"ssl-required": "external",
|
"ssl-required": "external",
|
||||||
"resource": "example-app",
|
"resource": "example-app",
|
||||||
|
|
Loading…
Reference in a new issue