Merge pull request #363 from pedroigor/KEYCLOAK-4903

[KEYCLOAK-4903] - Pushed Claims and improvements to PEP
This commit is contained in:
Matthew Helmke 2018-04-30 10:34:02 -05:00 committed by GitHub
commit cd944ade4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 193 additions and 54 deletions

View file

@ -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]

View file

@ -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;
}
}
```

View file

@ -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.

View file

@ -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

View file

@ -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.