KEYCLOAK-8297 Documentation for audience
This commit is contained in:
parent
205e8961f9
commit
c56a6a2cdb
16 changed files with 148 additions and 3 deletions
|
@ -18,3 +18,14 @@ Since these are symmetric signatures only Keycloak is able to verify the signatu
|
|||
application to use the token introspection endpoint to verify tokens.
|
||||
|
||||
Thanks to https://github.com/tnorimat[tnorimat] for contributing a signficant part of this work.
|
||||
|
||||
= Better Audience Support for OpenID Connect clients
|
||||
|
||||
It is now possible to specify the audiences in the tokens issued for OpenID Connect clients. There is also support for verification
|
||||
of audience on the adapter side.
|
||||
|
||||
= Minor improvements
|
||||
|
||||
* Added LocaleSelector SPI, which allows to change the way how the locale will be resolved for a particular request. Thanks to https://github.com/knutz3n[knutz3n]
|
||||
* Added an authenticator to automatically link Identity Provider identity to an existing account after first Idp authentication. Thanks to https://github.com/slominskir[slominskir]
|
||||
|
||||
|
|
|
@ -29,3 +29,7 @@ keycloak-config-file::
|
|||
Configure alternative class for Role principals attached to JAAS Subject.
|
||||
Default value is `org.keycloak.adapters.jaas.RolePrincipal`. Note: The class is required to have a constructor with a single `String` argument.
|
||||
|
||||
`scope`::
|
||||
This option is only applicable to the `DirectAccessGrantsLoginModule`. The specified value will be used as the OAuth2 `scope`
|
||||
parameter in the Resource Owner Password Credentials Grant request.
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ This is what one might look like:
|
|||
"bearer-only" : false,
|
||||
"enable-basic-auth" : false,
|
||||
"expose-token" : true,
|
||||
"verify-token-audience" : true,
|
||||
"credentials" : {
|
||||
"secret" : "234234-234234-234234"
|
||||
},
|
||||
|
@ -249,3 +250,9 @@ ignore-oauth-query-parameter::
|
|||
redirect-rewrite-rules::
|
||||
If needed, specify the Redirect URI rewrite rule. This is an object notation where the key is the regular expression to which the Redirect URI is to be matched and the value is the replacement String.
|
||||
`$` character can be used for backreferences in the replacement String.
|
||||
|
||||
verify-token-audience::
|
||||
If set to `true`, then during authentication with the bearer token, the adapter will verify whether the token contains this
|
||||
client name (resource) as an audience. The option is especially useful for services, which primarily serve requests authenticated
|
||||
by the bearer token. This is set to `false` by default, however for improved security, it is recommended to enable this.
|
||||
See link:{adminguide_link}#_audience[Audience Support] for more details about audience support.
|
||||
|
|
|
@ -17,7 +17,7 @@ to impersonate a user. Here's a short summary of the current capabilities of {p
|
|||
* A client can exchange an external token for a {project_name} token.
|
||||
* A client can impersonate a user
|
||||
|
||||
Token exchange in {project_name} is a very loose implementation of the link:https://www.ietf.org/id/draft-ietf-oauth-token-exchange-14.txt[OAuth Token Exchange] specification at the IETF.
|
||||
Token exchange in {project_name} is a very loose implementation of the link:https://www.ietf.org/id/draft-ietf-oauth-token-exchange-15.txt[OAuth Token Exchange] specification at the IETF.
|
||||
We have extended it a little, ignored some of it, and loosely interpreted other parts of the specification. It is
|
||||
a simple grant type invocation on a realm's OpenID Connect token endpoint.
|
||||
|
||||
|
@ -72,7 +72,7 @@ NOTE: We currently only support OpenID Connect and OAuth exchanges. Support f
|
|||
|
||||
A successful response from an exchange invocation will return the HTTP 200 response code with a content type that
|
||||
depends on the `requested-token-type` and `requested_issuer` the client asks for. OAuth requested token types will return
|
||||
a JSON document as described in the link:https://www.ietf.org/id/draft-ietf-oauth-token-exchange-14.txt[OAuth Token Exchange] specification.
|
||||
a JSON document as described in the link:https://www.ietf.org/id/draft-ietf-oauth-token-exchange-15.txt[OAuth Token Exchange] specification.
|
||||
|
||||
[source,json]
|
||||
----
|
||||
|
|
BIN
server_admin/keycloak-images/audience_client-scope-creating.png
Normal file
BIN
server_admin/keycloak-images/audience_client-scope-creating.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
server_admin/keycloak-images/audience_mapper.png
Normal file
BIN
server_admin/keycloak-images/audience_mapper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
BIN
server_admin/rhsso-images/audience_client-scope-creating.png
Normal file
BIN
server_admin/rhsso-images/audience_client-scope-creating.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
server_admin/rhsso-images/audience_mapper.png
Normal file
BIN
server_admin/rhsso-images/audience_mapper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
|
@ -38,6 +38,7 @@ include::topics/clients.adoc[]
|
|||
include::topics/clients/client-oidc.adoc[]
|
||||
include::topics/clients/oidc/confidential.adoc[]
|
||||
include::topics/clients/oidc/service-accounts.adoc[]
|
||||
include::topics/clients/oidc/audience.adoc[]
|
||||
include::topics/clients/client-saml.adoc[]
|
||||
include::topics/clients/saml/idp-initiated-login.adoc[]
|
||||
include::topics/clients/saml/entity-descriptors.adoc[]
|
||||
|
@ -110,6 +111,7 @@ include::topics/threat/compromised-codes.adoc[]
|
|||
include::topics/threat/open-redirect.adoc[]
|
||||
include::topics/threat/password-db-compromised.adoc[]
|
||||
include::topics/threat/scope.adoc[]
|
||||
include::topics/threat/audience-limit.adoc[]
|
||||
include::topics/threat/sql.adoc[]
|
||||
include::topics/admin-cli.adoc[]
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ cannot contain a space character in it). The value `openid` is the meta-value us
|
|||
it for this example. The token will contain mappers and role scope mappings from the client scopes `profile`, `email` (which are
|
||||
default scopes) and `phone` (an optional client scope requested by the scope parameter).
|
||||
|
||||
[[_client_scopes_evaluate]]
|
||||
==== Evaluating Client Scopes
|
||||
|
||||
The tabs `Mappers` and `Scope` of the client contain the protocol mappers and role scope mappings declared solely for this client.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
[[_client_installation]]
|
||||
|
||||
=== Generating Client Adapter Config
|
||||
|
||||
|
|
111
server_admin/topics/clients/oidc/audience.adoc
Normal file
111
server_admin/topics/clients/oidc/audience.adoc
Normal file
|
@ -0,0 +1,111 @@
|
|||
[[_audience]]
|
||||
|
||||
==== Audience Support
|
||||
|
||||
The typical environment where the {project_name} is deployed generally consists of a set of _confidential_ or _public_ client
|
||||
applications (frontend client applications) which use {project_name} for authentication.
|
||||
|
||||
There are also _services_ (called _Resource Servers_ in the OAuth 2 specification), which serve requests from frontend client
|
||||
applications and provide resources. These services typically require an _Access token_ (Bearer token) to be sent to them to
|
||||
authenticate for a particular request. This token was previously obtained by the frontend application when it tries to log in
|
||||
against {project_name}.
|
||||
|
||||
In the environment where the trust among services is low, you may encounter this scenario:
|
||||
|
||||
. A frontend client called `my-app` is required to be authenticated against {project_name}.
|
||||
|
||||
. A user is authenticated in {project_name}. {project_name} then issued tokens to the `my-app` application.
|
||||
|
||||
. The application `my-app` used the token to invoke the service `evil-service`. The application needs to invoke `evil-service` as
|
||||
the service is able to serve some very useful data.
|
||||
|
||||
. The `evil-service` application returned the response to `my-app`. However, at the same time, it kept the token previously sent to it.
|
||||
|
||||
. The `evil-service` application then invoked another service called `good-service` with the previously kept token. The invocation
|
||||
was successful and `good-service` returned the data. This results in broken security as the `evil-service` misused the token to
|
||||
access other services on behalf of the client `my-app`.
|
||||
|
||||
This flow may not be an issue in many environments with the high level of trust among services. However in other environments, where
|
||||
the trust among services is lower, this can be problematic.
|
||||
|
||||
NOTE: In some environments, this example work flow may be even requested behavior as the `evil-service` may need to retrieve
|
||||
additional data from `good-service` to be able to properly return the requested data to the original caller (my-app client).
|
||||
You may notice similarities with the Kerberos Credential Delegation. As with the Kerberos Credential Delegation, an unlimited
|
||||
audience is a mixed blessing as it is only useful when a high level of trust exists among services. Otherwise, it is
|
||||
recommended to limit audience as described next. You can limit audience and at the same time allow the `evil-service` to
|
||||
retrieve required data from the `good-service`. In this case, you need to ensure that both the `evil-service` and `good-service`
|
||||
are added as audiences to the token.
|
||||
|
||||
To prevent any misuse of the access token as in the example above, it is recommended to limit _Audience_ on the token and configure
|
||||
your services to verify the audience on the token. If this is done, the flow above will change, like this:
|
||||
|
||||
. A frontend client called `my-app` is required to be authenticated against {project_name}.
|
||||
|
||||
. A user is authenticated in {project_name}. {project_name} then issued tokens to the `my-app` application. The client application
|
||||
already knows that it will need to invoke service `evil-service`, so it used `scope=evil-service` in the authentication request
|
||||
sent to the {project_name} server. See <<_client_scopes, Client Scopes section>> for more details about the _scope_ parameter.
|
||||
The token issued to the `my-app` client contains the audience, as in `"audience": [ "evil-service" ]`, which declares that the
|
||||
client wants to use this access token to invoke just the service `evil-service`.
|
||||
|
||||
. The `evil-service` application served the request to the `my-app`. At the same time, it kept the token previously sent to it.
|
||||
|
||||
. The `evil-service` application then invoked the `good-service` with the previously kept token. Invocation was not successful
|
||||
because `good-service` checks the audience on the token and it sees that audience is only `evil-service`. This is expected behavior
|
||||
and security is not broken.
|
||||
|
||||
If the client wants to invoke the `good-service` later, it will need to obtain another token by issuing the SSO login with the
|
||||
`scope=good-service`. The returned token will then contain `good-service` as an audience:
|
||||
|
||||
[source,json]
|
||||
----
|
||||
"audience": [ "good-service" ]
|
||||
----
|
||||
and can be used to invoke `good-service`.
|
||||
|
||||
===== Setup
|
||||
|
||||
To properly set up audience checking:
|
||||
|
||||
* Ensure that services are configured to check audience on the access token sent to them by adding the flag _verify-token-audience_
|
||||
in the adapter configuration. See link:{adapterguide_link}#_java_adapter_config[Adapter configuration] for details.
|
||||
|
||||
* Ensure that when an access token is issued by {project_name}, it contains all requested audiences and does not contain any
|
||||
audiences that are not needed. This is described below in more details.
|
||||
|
||||
As an example, let us assume that you have a bearer-only client `good-service`. Set up {project_name} for audience support like this:
|
||||
|
||||
* Log in to the admin console. Go to the _Client Scopes_ tab on the left and click _Create_.
|
||||
|
||||
* Choose the _Audience template_.
|
||||
|
||||
* Select `good-service` as the requested audience
|
||||
|
||||
.Creating Audience Client Scope
|
||||
image:{project_images}/audience_client-scope-creating.png[]
|
||||
|
||||
* When the client scope is created, you should confirm that it contains:
|
||||
** An audience protocol mapper, which is used for adding the `good-service` as an audience to the access token. See the figure below.
|
||||
** Role scope mappings for all the client roles of `good-service` client.
|
||||
|
||||
.Audience Protocol Mapper
|
||||
image:{project_images}/audience_mapper.png[]
|
||||
|
||||
* From the <<_client_installation, Installation tab>> of the `good-service` client, you can generate the adapter
|
||||
configuration and you can confirm that _verify-token-audience_ option will be set to true. This indicates that the adapter will
|
||||
require verifying the audience if you use this generated configuration.
|
||||
|
||||
* Finally, you need to ensure that the `my-app` frontend client is able to request `good-service` as an audience in its tokens.
|
||||
On the `my-app` client, click the _Client Scopes_ tab. Then assign `good-service` as an optional (or default) client scope. See
|
||||
<<_client_scopes_linking, Client Scopes Linking section>> for more details.
|
||||
|
||||
* You can optionally <<_client_scopes_evaluate, Evaluate Client Scopes>> and generate an example access token. If you do, notice
|
||||
that `good-service` will be added to the audience of the generated access token only if `good-service` is included in the _scope_
|
||||
parameter in the case you assigned it as an optional client scope.
|
||||
|
||||
* In your `my-app` application, you must ensure that _scope_ parameter is used with the value `good-service` always included when
|
||||
you want to issue the token for accessing the `good-service`.
|
||||
See the link:{adapterguide_link}#_params_forwarding[parameters forwarding section], if your application uses the servlet
|
||||
adapter, or the link:{adapterguide_link}#_javascript_adapter[javascript adapter section], if your application uses the
|
||||
javascript adapter.
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[[_service_accounts]]
|
||||
|
||||
=== Service Accounts
|
||||
==== Service Accounts
|
||||
|
||||
Each OIDC client has a built-in _service account_ which allows it to obtain an access token.
|
||||
This is covered in the OAuth 2.0 specifiation under <<_client_credentials_grant,Client Credentials Grant>>.
|
||||
|
|
6
server_admin/topics/threat/audience-limit.adoc
Normal file
6
server_admin/topics/threat/audience-limit.adoc
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
=== Limit Token Audience
|
||||
|
||||
In environments where the level of trust among services is low, it is a good practice to limit the audiences on the token. The
|
||||
motivation behind this is described in the https://tools.ietf.org/html/rfc6819#section-5.1.5.5[OAuth2 Threat Model] document and
|
||||
more details are in the <<_audience, Audience Support section>>.
|
|
@ -5,4 +5,6 @@ By default, each new client application has an unlimited `role scope mappings`.
|
|||
for that client will contain all the permissions the user has. If the client gets compromised and the access token
|
||||
is leaked, then each system that the user has permission to access is now also compromised. It is highly suggested
|
||||
that you limit the roles an access token is assigned by using the <<_role_scope_mappings, Scope menu>> for each client.
|
||||
Or alternatively, you can set role scope mappings at the Client Scope level and assign Client Scopes to your client by using the
|
||||
<<_client_scopes_linking, Client Scope menu>>.
|
||||
|
||||
|
|
Loading…
Reference in a new issue