From f62fa142b456c8874a6ed3e50fe7708d17ae1967 Mon Sep 17 00:00:00 2001 From: pedroigor Date: Wed, 18 Apr 2018 17:15:29 -0300 Subject: [PATCH] [KEYCLOAK-4903] - Pushed Claims and improvements to PEP --- authorization_services/topics.adoc | 8 +- .../enforcer-claim-information-point.adoc | 165 ++++++++++++++++++ .../enforcer-keycloak-enforcement-bearer.adoc | 37 ---- .../enforcer-keycloak-enforcement-filter.adoc | 17 +- .../topics/enforcer-overview.adoc | 20 +++ 5 files changed, 193 insertions(+), 54 deletions(-) create mode 100644 authorization_services/topics/enforcer-claim-information-point.adoc delete mode 100644 authorization_services/topics/enforcer-keycloak-enforcement-bearer.adoc diff --git a/authorization_services/topics.adoc b/authorization_services/topics.adoc index 96705f7cbb..ec0e7c8f4c 100644 --- a/authorization_services/topics.adoc +++ b/authorization_services/topics.adoc @@ -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] diff --git a/authorization_services/topics/enforcer-claim-information-point.adoc b/authorization_services/topics/enforcer-claim-information-point.adoc new file mode 100644 index 0000000000..882ac0e03f --- /dev/null +++ b/authorization_services/topics/enforcer-claim-information-point.adoc @@ -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 { + + @Override + public String getName() { + return "my-claims"; + } + + @Override + public void init(PolicyEnforcer policyEnforcer) { + + } + + @Override + public MyClaimInformationPointProvider create(Map 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 config; + + public ClaimsInformationPointProvider(Map config) { + this.config = config; + } + + @Override + public Map> resolve(HttpFacade httpFacade) { + Map> claims = new HashMap<>(); + + // put whatever claim you want into the map + + return claims; + } +} +``` \ No newline at end of file diff --git a/authorization_services/topics/enforcer-keycloak-enforcement-bearer.adoc b/authorization_services/topics/enforcer-keycloak-enforcement-bearer.adoc deleted file mode 100644 index c044150128..0000000000 --- a/authorization_services/topics/enforcer-keycloak-enforcement-bearer.adoc +++ /dev/null @@ -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. diff --git a/authorization_services/topics/enforcer-keycloak-enforcement-filter.adoc b/authorization_services/topics/enforcer-keycloak-enforcement-filter.adoc index dc09ee5b51..7a843ec3f1 100644 --- a/authorization_services/topics/enforcer-keycloak-enforcement-filter.adoc +++ b/authorization_services/topics/enforcer-keycloak-enforcement-filter.adoc @@ -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 diff --git a/authorization_services/topics/enforcer-overview.adoc b/authorization_services/topics/enforcer-overview.adoc index 691b56681f..361bd9c62a 100644 --- a/authorization_services/topics/enforcer-overview.adoc +++ b/authorization_services/topics/enforcer-overview.adoc @@ -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. +