Merge pull request #363 from pedroigor/KEYCLOAK-4903
[KEYCLOAK-4903] - Pushed Claims and improvements to PEP
This commit is contained in:
commit
cd944ade4e
5 changed files with 193 additions and 54 deletions
|
@ -104,10 +104,10 @@ include::topics/enforcer-overview.adoc[leveloffset=+1]
|
|||
|
||||
include::topics/enforcer-keycloak-enforcement-filter.adoc[leveloffset=+2]
|
||||
|
||||
include::topics/enforcer-keycloak-enforcement-bearer.adoc[leveloffset=+3]
|
||||
include::topics/enforcer-claim-information-point.adoc[leveloffset=+2]
|
||||
|
||||
include::topics/enforcer-authorization-context.adoc[leveloffset=+3]
|
||||
include::topics/enforcer-authorization-context.adoc[leveloffset=+2]
|
||||
|
||||
include::topics/enforcer-js-adapter.adoc[leveloffset=+3]
|
||||
include::topics/enforcer-js-adapter.adoc[leveloffset=+2]
|
||||
|
||||
include::topics/enforcer-https.adoc[leveloffset=+3]
|
||||
include::topics/enforcer-https.adoc[leveloffset=+2]
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
[[_enforcer_claim_information_point]]
|
||||
= Claim Information Point
|
||||
|
||||
A Claim Information Point (CIP) is responsible for resolving claims and pushing these claims to the {project_name} server
|
||||
in order to provide more information about the access context to policies. They can be defined as a configuration option
|
||||
to the policy-enforcer in order to resolve claims from different sources, such as:
|
||||
|
||||
* HTTP Request (parameters, headers, body, headers, etc)
|
||||
* External HTTP Service
|
||||
* Static values defined in configuration
|
||||
* Any other source by implementing the Claim Information Provider SPI
|
||||
|
||||
When pushing claims to the {project_name} server, policies can base decisions not only on who an user is but also by taking
|
||||
context and contents into account, based on who, what, why, when, where, and which for a given transaction. It is all about
|
||||
Contextual-based Authorization and how to use runtime information in order to support fine-grained authorization decisions.
|
||||
|
||||
== Obtaining information from the HTTP Request
|
||||
|
||||
Here are several examples showing how you can extract claims from an HTTP request:
|
||||
|
||||
.keycloak.json
|
||||
```json
|
||||
"policy-enforcer": {
|
||||
"paths": [
|
||||
{
|
||||
"path": "/protected/resource",
|
||||
"claim-information-point": {
|
||||
"claims": {
|
||||
"claim-from-request-parameter": "{request.parameter['a']}",
|
||||
"claim-from-header": "{request.header['b']}",
|
||||
"claim-from-cookie": "{request.cookie['c']}",
|
||||
"claim-from-remoteAddr": "{request.remoteAddr}",
|
||||
"claim-from-method": "{request.method}",
|
||||
"claim-from-uri": "{request.uri}",
|
||||
"claim-from-relativePath": "{request.relativePath}",
|
||||
"claim-from-secure": "{request.secure}",
|
||||
"claim-from-json-body-object": "{request.body['/a/b/c']}",
|
||||
"claim-from-json-body-array": "{request.body['/d/1']}",
|
||||
"claim-from-body": "{request.body}",
|
||||
"claim-from-static-value": "static value",
|
||||
"claim-from-multiple-static-value": ["static", "value"],
|
||||
"param-replace-multiple-placeholder": "Test {keycloak.access_token['/custom_claim/0']} and {request.parameter['a']} "
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
== Obtaining information from an External HTTP Service
|
||||
|
||||
Here are several examples showing how you can extract claims from an external HTTP Service:
|
||||
|
||||
.keycloak.json
|
||||
```json
|
||||
"policy-enforcer": {
|
||||
"paths": [
|
||||
{
|
||||
"path": "/protected/resource",
|
||||
"claim-information-point": {
|
||||
"http": {
|
||||
"claims": {
|
||||
"claim-a": "/a",
|
||||
"claim-d": "/d",
|
||||
"claim-d0": "/d/0",
|
||||
"claim-d-all": ["/d/0", "/d/1"]
|
||||
},
|
||||
"url": "http://mycompany/claim-provider",
|
||||
"method": "POST",
|
||||
"headers": {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"header-b": ["header-b-value1", "header-b-value2"],
|
||||
"Authorization": "Bearer {keycloak.access_token}"
|
||||
},
|
||||
"parameters": {
|
||||
"param-a": ["param-a-value1", "param-a-value2"],
|
||||
"param-subject": "{keycloak.access_token['/sub']}",
|
||||
"param-user-name": "{keycloak.access_token['/preferred_username']}",
|
||||
"param-other-claims": "{keycloak.access_token['/custom_claim']}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
== Static Claims
|
||||
|
||||
.keycloak.json
|
||||
```json
|
||||
"policy-enforcer": {
|
||||
"paths": [
|
||||
{
|
||||
"path": "/protected/resource",
|
||||
"claim-information-point": {
|
||||
"claims": {
|
||||
"claim-from-static-value": "static value",
|
||||
"claim-from-multiple-static-value": ["static", "value"],
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
== Claim Information Provider SPI
|
||||
|
||||
The Claim Information Provider SPI can be used by developers to support different claim information points in case none of the
|
||||
built-ins providers are enough to address their requirements.
|
||||
|
||||
For example, to implement a new CIP provider you need to implement `org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory`
|
||||
and `ClaimInformationPointProvider` and also provide the file `META-INF/services/org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory`
|
||||
in your application`s classpath.
|
||||
|
||||
Example of `org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory`:
|
||||
|
||||
```java
|
||||
public class MyClaimInformationPointProviderFactory implements ClaimInformationPointProviderFactory<MyClaimInformationPointProvider> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "my-claims";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(PolicyEnforcer policyEnforcer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyClaimInformationPointProvider create(Map<String, Object> config) {
|
||||
return new MyClaimInformationPointProvider(config);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Every CIP provider must be associated with a name, as defined above in the `MyClaimInformationPointProviderFactory.getName` method. The name
|
||||
will be used to map the configuration from the `claim-information-point` section in the `policy-enforcer` configuration to the implementation.
|
||||
|
||||
When processing requests, the policy enforcer will call the MyClaimInformationPointProviderFactory.create method in order to obtain an
|
||||
instance of MyClaimInformationPointProvider. When called, any configuration defined for this particular CIP provider
|
||||
(via claim-information-point) is passed as a map.
|
||||
|
||||
Example of `ClaimInformationPointProvider`:
|
||||
|
||||
```java
|
||||
public class MyClaimInformationPointProvider implements ClaimInformationPointProvider {
|
||||
|
||||
private final Map<String, Object> config;
|
||||
|
||||
public ClaimsInformationPointProvider(Map<String, Object> config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> resolve(HttpFacade httpFacade) {
|
||||
Map<String, List<String>> claims = new HashMap<>();
|
||||
|
||||
// put whatever claim you want into the map
|
||||
|
||||
return claims;
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,37 +0,0 @@
|
|||
[[_enforcer_bearer]]
|
||||
= Protecting a Stateless Service Using a Bearer Token
|
||||
|
||||
If the adapter is configured with the `bearer-only` configuration option, the policy enforcer decides whether a request
|
||||
to access a protected resource is allowed or denied based on the permissions of the bearer token.
|
||||
|
||||
. HTTP GET example passing an RPT as a bearer token
|
||||
```bash
|
||||
GET /my-resource-server/my-protected-resource HTTP/1.1
|
||||
Host: host.com
|
||||
Authorization: Bearer ${RPT}
|
||||
...
|
||||
```
|
||||
|
||||
In this example, a *keycloak.json* file in your application is similar to the following:
|
||||
|
||||
.Example of WEB-INF/keycloak.json with the bearer-only configuration option
|
||||
```json
|
||||
...
|
||||
"bearer-only" : true,
|
||||
...
|
||||
```
|
||||
|
||||
== Authorization Response
|
||||
|
||||
When a client tries to access a resource server with a bearer token that is lacking permissions to access a protected resource, the resource server
|
||||
responds with a *401* status code and a `WWW-Authenticate` header. The value of the `WWW-Authenticate` header depends on the authorization protocol
|
||||
in use by the resource server.
|
||||
|
||||
Here is an example of a response from a resource server that is using UMA as the authorization protocol:
|
||||
|
||||
```bash
|
||||
HTTP/1.1 401 Unauthorized
|
||||
WWW-Authenticate: UMA realm="photoz-restful-api",as_uri="https://${host}:${post}/auth/realms/${realm}",ticket="${PERMISSION_TICKET}"
|
||||
```
|
||||
|
||||
Once a client receives a response from the server, it examines the status code and `WWW-Authenticate` header to obtain an RPT from the {project_name} Server.
|
|
@ -1,16 +1,5 @@
|
|||
[[_enforcer_filter]]
|
||||
= {project_name} Adapter Policy Enforcer
|
||||
|
||||
You can enforce authorization decisions for your applications if you are using {project_name} OIDC adapters.
|
||||
|
||||
When you enable policy enforcement for your {project_name} application, the corresponding adapter intercepts all requests to your application and enforces the authorization decisions obtained from the server.
|
||||
|
||||
Policy enforcement is strongly linked to your application's paths and the <<_resource_overview, resources>> you created for a resource server using the {project_name} Administration Console. By default,
|
||||
when you create a resource server, {project_name} creates a <<_resource_server_default_config, default configuration>> for your resource server so you can enable policy enforcement quickly.
|
||||
|
||||
The default configuration allows access for all resources in your application provided the authenticated user belongs to the same realm as the resource server being protected.
|
||||
|
||||
== Policy Enforcement Configuration
|
||||
= Configuration
|
||||
|
||||
To enable policy enforcement for your application, add the following property to your *keycloak.json* file:
|
||||
|
||||
|
@ -156,7 +145,9 @@ Specifies how policies are enforced.
|
|||
+
|
||||
**** *DISABLED*
|
||||
+
|
||||
Disables the evaluation of policies for a path
|
||||
*** *claim-information-point*
|
||||
+
|
||||
Defines a set of one or more claims that must be resolved and pushed to the {project_name} server in order to make these claims available to policies. See <<_enforcer_claim_information_point, Claim Information Point>> for more details.
|
||||
** *lazy-load-paths*
|
||||
+
|
||||
Specifies how the adapter should fetch the server for resources associated with paths in your application. If true, the policy
|
||||
|
|
|
@ -6,3 +6,23 @@ to implement PEPs for different platforms, environments, and programming languag
|
|||
and leverages OAuth2 authorization capabilities for fine-grained authorization using a centralized authorization server.
|
||||
|
||||
image:images/pep-pattern-diagram.png[alt="PEP Overview"]
|
||||
|
||||
A PEP is responsible for enforcing access decisions from the {project_name} server where these decisions are taken by evaluating the policies
|
||||
associated with a protected resource. It acts as a filter or interceptor in your application in order to check whether or not a particular request
|
||||
to a protected resource can be fulfilled based on the permissions granted by these decisions.
|
||||
|
||||
If you are using any of the {project_name} OIDC adapters, you can easily enable the policy enforcer by adding the following property to your *keycloak.json* file:
|
||||
|
||||
.keycloak.json
|
||||
```json
|
||||
{
|
||||
"policy-enforcer": {}
|
||||
}
|
||||
```
|
||||
|
||||
When you enable the policy enforcer all requests sent your application are intercepted and access to protected resources will be granted
|
||||
depending on the permissions granted by {project_name} to the identity making the request.
|
||||
|
||||
Policy enforcement is strongly linked to your application's paths and the <<_resource_overview, resources>> you created for a resource server using the {project_name} Administration Console. By default,
|
||||
when you create a resource server, {project_name} creates a <<_resource_server_default_config, default configuration>> for your resource server so you can enable policy enforcement quickly.
|
||||
|
||||
|
|
Loading…
Reference in a new issue