Merge pull request #6 from pedroigor/master
Servlet security quickstart
This commit is contained in:
commit
3e5a6a9281
10 changed files with 474 additions and 207 deletions
|
@ -5,6 +5,7 @@
|
|||
.. link:topics/overview/terminology.adoc[Terminology]
|
||||
. link:topics/getting-started/getting-started.adoc[Getting Started]
|
||||
.. link:topics/getting-started/hello-world.adoc[Hello Authorization World]
|
||||
.. link:topics/getting-started/hello-world-servlet-authz.adoc[Securing a Servlet Application]
|
||||
. link:topics/resource-server/overview.adoc[Managing Resource Servers]
|
||||
.. link:topics/resource-server/view.adoc[Viewing Resource Servers]
|
||||
.. link:topics/resource-server/create.adoc[Creating Resource Servers]
|
||||
|
|
BIN
images/pep-pattern-diagram.png
Normal file
BIN
images/pep-pattern-diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
images/servlet-authz-app-structure.png
Normal file
BIN
images/servlet-authz-app-structure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -1 +0,0 @@
|
|||
== JAX-RS Policy Enforcer
|
|
@ -1 +1,7 @@
|
|||
== Policy Enforcers
|
||||
== Policy Enforcers
|
||||
|
||||
PEP is a design pattern and as such you can implement it in different ways. {{book.project.name}} provides all the necessary means
|
||||
to implement PEPs for different platforms, environments and using different programming languages. After all, {{book.project.name}} {{book.project.module}} is
|
||||
fully RESTFUL-based, leveraging OAuth2 authorization capabilities to also support fine-grained authorization using a centralized authorization server.
|
||||
|
||||
image:../../images/pep-pattern-diagram.png[alt="PEP Overview"]
|
|
@ -6,7 +6,9 @@ you to understand the basic steps to enable fine-grained authorization to an app
|
|||
[NOTE]
|
||||
This guide assume that you are able to install and boot a {{book.project.name}} Server. For more information, please follow the intrusctions https://keycloak.gitbooks.io/getting-started-tutorials/content/[here].
|
||||
|
||||
Make sure you have a {{book.project.name}} instance up and running on http://localhost:8080/auth[http://localhost:8080/auth]. If everything is OK, you would be able to login to the
|
||||
All the guides are based on the *{{book.project.name}} Demo Distribution*. Please download it before going further with any guide.
|
||||
|
||||
Make sure you have a {{book.project.name}} instance up and running on http://localhost:8080/auth[http://localhost:8080/auth]. If everything is OK, you should be able to login to the
|
||||
_Administration Console_ and get a page like that:
|
||||
|
||||
image:../../images/gs-keycloak-console-page.png[alt="Keycloak Administration Console"]
|
|
@ -1,202 +0,0 @@
|
|||
=== Creating the Hello World AuthZ Realm
|
||||
|
||||
For this guide, we are going to create a *hello-world-authz* realm. Just import the following JSON file to create the new realm:
|
||||
|
||||
```json
|
||||
{
|
||||
"realm" : "hello-world-authz",
|
||||
"enabled" : true,
|
||||
"privateKey" : "MIIEpQIBAAKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQABAoIBAAwa4wVnKBOIS6srmYPfBTDNsTBBCEjxiYEErmn7JhoWxQ1DCPUxyxU6F177/q9Idqoj1FFOCtEO9P6/9+ym470HQmEQkR2Xxd1d3HOZy9oKuCro3ZbTDkVxY0JnlyxZz4MihGFxDH2e4MArfHy0sAgYbdIU+x2pWKGWSMzDd/TMSOExhc/sIQAg6ljbPCLLXCPQFAncoHRyGPrkRZs6UTZi5SJuCglVa2/3G+0drDdPuA83/mwsZfIBqQgbGbFgtq5T5C6CKMkPOQ42Rcclm7kEr6riTkJRo23EO1iOJVpxzI0tbxZsJAsW7zeqv0wWRyUgVfQAje6OdsNexp5aCtECgYEA6nMHCQ9xXvufCyzpIbYGxdAGqH6m1AR5gXerHqRiGNx+8UUt/E9cy/HTOhmZDK/eC4BT9tImeF01l1oSU/+wGKfux0SeAQchBhhq8GD6jmrtgczKAfZHp0Zrht7o9qu9KE7ZNWRmY1foJN9yNYmzY6qqHEy+zNo9amcqT7UZKO8CgYEA35sp9fMpMqkJE+NEJ9Ph/t2081BEkC0DYIuETZRSi+Ek5AliWTyEkg+oisTbWzi6fMQHS7W+M1SQP6djksLQNPP+353DKgup5gtKS+K/y2xNd7fSsNmkjW1bdJJpID7WzwwmwdahHxpcnFFuEXi5FkG3Vqmtd3cD0TYL33JlRy0CgYEA0+a3eybsDy9Zpp4m8IM3R98nxW8DlimdMLlafs2QpGvWiHdAgwWwF90wTxkHzgG+raKFQVbb0npcj7mnSyiUnxRZqt2H+eHZpUq4jR76F3LpzCGui2tvg+8QDMy4vwqmYyIxDCL8r9mqRnl3HpChBPoh2oY7BahTTjKEeZpzbR0CgYEAoNnVjX+mGzNNvGi4Fo5s/BIwoPcU20IGM+Uo/0W7O7Rx/Thi7x6BnzB0ZZ7GzRA51paNSQEsGXCzc5bOIjzR2cXLisDKK+zIAxwMDhrHLWZzM7OgdGeb38DTEUBhLzkE/VwYZUgoD1+/TxOkwhy9yCzt3gGhL1cF//GJCOwZvuECgYEAgsO4rdYScgCpsyePnHsFk+YtqtdORnmttF3JFcL3w2QneXuRwg2uW2Kfz8CVphrR9eOU0tiw38w6QTHIVeyRY8qqlHtiXj6dEYz7frh/k4hI29HwFx43rRpnAnN8kBEJYBYdbjaQ35Wsqkfu1tvHJ+6fxSwvQu/TVdGp0OfilAY=",
|
||||
"publicKey" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQAB",
|
||||
"certificate" : "MIICsTCCAZkCBgFVETX4AzANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFIZWxsbyBXb3JsZCBBdXRoWjAeFw0xNjA2MDIxMzAxMzdaFw0yNjA2MDIxMzAzMTdaMBwxGjAYBgNVBAMMEUhlbGxvIFdvcmxkIEF1dGhaMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQANm5gIT/c50lwjawM686gNXpppLA928WsCOn9NIIWjSKekP8Bf9S73kf7vWcsEppm5B8rRyRxolXmzwghv74L7uVDg8Injjgj+XbPVQP+cJqWpSaMZHF7UfWe0/4M945Xcbmsl5q+m9PmrPG0AaaZhqXHcp4ehB1H+awyRqiERpJUuwZNycw2+2kjDADpsFf8hZVUd1F6ReYyOkqUyUjbL+jYTC7ZBNa7Ok+w6HCXWgkgVATAgQXJRM3w14IOc5MH/vfMCrCl/eNQLbjGl9y7u8PKwh3MXHDO2OLqtg6hOTSrOGUPJZGmGtUAl+2/R7FzoWkML/BNe2hjsL6UJwg91",
|
||||
"requiredCredentials" : [ "password" ],
|
||||
"roles" : {
|
||||
"realm" : [
|
||||
{
|
||||
"name" : "uma_protection"
|
||||
}
|
||||
]
|
||||
},
|
||||
"users" :
|
||||
[
|
||||
{
|
||||
"username" : "alice",
|
||||
"enabled" : true,
|
||||
"credentials" : [ {
|
||||
"type" : "password",
|
||||
"value" : "password"
|
||||
} ],
|
||||
"clientRoles" : {
|
||||
"hello-world-authz-service" : [ "uma_authorization" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username" : "jdoe",
|
||||
"enabled" : true,
|
||||
"credentials" : [ {
|
||||
"type" : "password",
|
||||
"value" : "password"
|
||||
} ],
|
||||
"clientRoles" : {
|
||||
"hello-world-authz-service" : [ "uma_authorization" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username" : "service-account-hello-world-authz-service",
|
||||
"enabled" : true,
|
||||
"serviceAccountClientId" : "hello-world-authz-service",
|
||||
"realmRoles" : [ "uma_protection"]
|
||||
}
|
||||
],
|
||||
"clients" : [
|
||||
{
|
||||
"clientId" : "hello-world-authz-service",
|
||||
"secret" : "password",
|
||||
"serviceAccountsEnabled" : true,
|
||||
"enabled" : true,
|
||||
"redirectUris" : [ "http://localhost:8080/hello-world-authz-service" ],
|
||||
"directAccessGrantsEnabled" : true,
|
||||
"publicClient" : false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
The realm *hello-world-authz* consists of:
|
||||
|
||||
** Two users: _alice_ and _jdoe_
|
||||
** One client application: _hello-world-authz-service_
|
||||
** One global role: _uma_protection_
|
||||
** One client role: _uma_authorization_
|
||||
|
||||
The _hello-world-authz-service_ is the application with the resources we want to protect. In other words, it will act as a link:../overview/terminology.html[Resource Server].
|
||||
|
||||
In {{book.project.name}} a resource server is just a regular client application with some specific characteristics. It _must_ be a *confidential* client application as defined by:
|
||||
|
||||
```json
|
||||
"publicClient" : false
|
||||
```
|
||||
|
||||
It must have a *client_id*, *client_secret* and *Service Account* enabled:
|
||||
|
||||
```json
|
||||
"clients" : [
|
||||
{
|
||||
"clientId" : "hello-world-authz-service",
|
||||
"secret" : "7801be7c-437a-44ae-be34-67da32f024eb",
|
||||
"serviceAccountsEnabled" : true,
|
||||
...
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
And finally, an user mapping to the client's service account:
|
||||
|
||||
```json
|
||||
{
|
||||
"username" : "service-account-my-resource-server",
|
||||
"enabled" : true,
|
||||
"serviceAccountClientId" : "hello-world-authz-service",
|
||||
"realmRoles" : [ "uma_protection"]
|
||||
}
|
||||
```
|
||||
|
||||
In the latter case, we are also granting the *uma_protection* role to the client's service account. As you'll see, that will be necessary in order to get access to the link:../service/protection-api.html[Protection API].
|
||||
|
||||
=== Creating a Resource Server and Protecting Resources
|
||||
|
||||
Now that we have the *hello-world-authz* realm properly configured, we need to enable the *hello-world-authz-service* as a resource server. For that, click on the *Authorization* in the left menu bar.
|
||||
|
||||
image:../../images/gs-keycloak-authz-page.png[alt="Keycloak Authorization Page"]
|
||||
|
||||
To create a resource server you can click on the *Create* button.
|
||||
|
||||
image:../../images/gs-keycloak-authz-create-rs-page.png[alt="Create Resource Server"]
|
||||
|
||||
From that page you can create a resource server by manually filling that form or you can just import a JSON file with the configuration you want. For this guide, we'll just import a JSON file as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"clientId": "hello-world-authz-service",
|
||||
"resources": [
|
||||
{
|
||||
"name": "Hello World Resource"
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"name": "Only Special Users Policy",
|
||||
"type": "user",
|
||||
"logic": "POSITIVE",
|
||||
"config": {
|
||||
"users": "[\"alice\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Hello World Resource Permission",
|
||||
"type": "resource",
|
||||
"config": {
|
||||
"resources": "[\"Hello World Resource\"]",
|
||||
"applyPolicies": "[\"Only Special Users Policy\"]"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
After importing the JSON file above, you would see a page like that:
|
||||
|
||||
image:../../images/gs-authz-hello-rs-created-page.png[alt="Resource Server Successfully Created"]
|
||||
|
||||
You may take some time now exploring the resource server we just created. But first, let's understand what we just created.
|
||||
|
||||
The resource server was created based on the *hello-world-authz-service* client application, as you can see from the following configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"clientId": "hello-world-authz-service",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
What we did was basically tell {{book.project.name}} that we want that client application acting as a resource server, so we can start creating the resources we want to protect as well the permissions
|
||||
and authorization policies we want to use to actually protect the resources.
|
||||
|
||||
The purpose of this guide is keep things simple to get you started, so our newly created resource server has a single protected resource, as defined by the following configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
...
|
||||
"resources": [
|
||||
{
|
||||
"name": "Hello World Resource"
|
||||
}
|
||||
],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The *Hello World Resource* represents a set of one or more resources we want to protect. It can map to a single or to multiple resources in an application.
|
||||
|
||||
In order to protect it, we need to create the authorization policies and permissions we want to apply. Policies define the conditions that must be satisfied to grant a permission. Where a
|
||||
permission is the link between a resource and the policies(or conditions) we want to enforce when someone wants to access a resource.
|
||||
|
||||
In this example, we have a single policy *Only Special Users Policy*. This policy tells that only the specified users are allowed to access _something_ (we don't know what, yet. That is up to the permission).
|
||||
|
||||
[NOTE]
|
||||
{{book.project.name}} provides a few link:../policy/overview.html[policy types] that you can start using out-of-the-box. There are policies for RBAC, time constraints or even rules written using JavaScript or JBoss Drools.
|
||||
|
||||
The last step when protecting a resource is to define a permission. For that, we have defined a *Hello World Resource Permission* that links the resource we want to protect, _Hello World Resource_, with the
|
||||
policy we want to apply to that resource, _Only Special Users Policy_.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Hello World Resource Permission",
|
||||
"type": "resource",
|
||||
"config": {
|
||||
"resources": "[\"Hello World Resource\"]",
|
||||
"applyPolicies": "[\"Only Special Users Policy\"]"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
|
@ -1 +0,0 @@
|
|||
== Obtaining Permissions using the Entitlement API
|
456
topics/getting-started/hello-world-servlet-authz.adoc
Executable file
456
topics/getting-started/hello-world-servlet-authz.adoc
Executable file
|
@ -0,0 +1,456 @@
|
|||
== Securing a Servlet Application
|
||||
|
||||
This guide will show you how to:
|
||||
|
||||
* Create a realm with the necessary configuration to enable fine-grained authorization to a servlet application
|
||||
* Create a resource server and the resources that must be protected
|
||||
* Create permissions, authorization policies and how to apply them to your protected resources
|
||||
* Configure the {{book.project.name}} Authorization Enforcer Filter to your servlet application
|
||||
|
||||
The application we are using in this guide is one of the examples provided by the {{book.project.name}} Demo Distribution. You can find all the source code
|
||||
under *examples/authz/servlet-authz/*.
|
||||
|
||||
[NOTE]
|
||||
Before going further, make sure you followed all the instructions in the link:../getting-started/getting-started.html[Getting Started] guide.
|
||||
|
||||
=== About the Servlet Application
|
||||
|
||||
The application we are about to create is a very simple. In a nutshell, it implements the following security requirements:
|
||||
|
||||
* An _Administration Area_ that only administrators can access
|
||||
* An _User Premium Area_ that only users with a premium plan can access
|
||||
* A dynamic menu that is generated accordingly with the permissions issued by a {{book.project.name}} Server to an authenticated user
|
||||
|
||||
image:../../images/servlet-authz-app-structure.png[alt="Servlet Authz Application Structure"]
|
||||
|
||||
=== Creating the Servlet Authz Realm
|
||||
|
||||
For this guide, we are going to create a *servlet-authz* realm. Just import the following JSON file to create the new realm:
|
||||
|
||||
```json
|
||||
{
|
||||
"realm": "servlet-authz",
|
||||
"enabled": true,
|
||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"requiredCredentials": [
|
||||
"password"
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "alice",
|
||||
"enabled": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "alice"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user"
|
||||
],
|
||||
"clientRoles": {
|
||||
"servlet-authz-app": [
|
||||
"uma_authorization",
|
||||
"kc_entitlement"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "jdoe",
|
||||
"enabled": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "jdoe"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user",
|
||||
"user_premium"
|
||||
],
|
||||
"clientRoles": {
|
||||
"servlet-authz-app": [
|
||||
"uma_authorization",
|
||||
"kc_entitlement"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "admin",
|
||||
"enabled": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "admin"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user",
|
||||
"admin"
|
||||
],
|
||||
"clientRoles": {
|
||||
"realm-management": [
|
||||
"realm-admin"
|
||||
],
|
||||
"servlet-authz-app": [
|
||||
"uma_authorization",
|
||||
"kc_entitlement"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "service-account-servlet-authz-app",
|
||||
"enabled": true,
|
||||
"serviceAccountClientId": "servlet-authz-app",
|
||||
"realmRoles": [
|
||||
"uma_protection"
|
||||
]
|
||||
}
|
||||
],
|
||||
"roles": {
|
||||
"realm": [
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User privileges"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator privileges"
|
||||
},
|
||||
{
|
||||
"name": "user_premium",
|
||||
"description": "User Premium privileges"
|
||||
},
|
||||
{
|
||||
"name": "uma_protection",
|
||||
"description": "Allows access to the Protection API"
|
||||
}
|
||||
]
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "servlet-authz-app",
|
||||
"enabled": true,
|
||||
"publicClient": false,
|
||||
"baseUrl": "/servlet-authz-app",
|
||||
"adminUrl": "/servlet-authz-app",
|
||||
"bearerOnly": false,
|
||||
"serviceAccountsEnabled": true,
|
||||
"redirectUris": [
|
||||
"/servlet-authz-app/*"
|
||||
],
|
||||
"secret": "secret"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
=== Creating a Resource Server and Protecting Resources
|
||||
|
||||
Now that we have the *servlet-authz* realm properly configured, we need to enable the *servlet-authz-app* as a resource server. For that, click on the *Authorization* in the left menu bar.
|
||||
|
||||
image:../../images/gs-keycloak-authz-page.png[alt="Keycloak Authorization Page"]
|
||||
|
||||
To create a resource server you can click on the *Create* button.
|
||||
|
||||
image:../../images/gs-keycloak-authz-create-rs-page.png[alt="Create Resource Server"]
|
||||
|
||||
From that page you can create a resource server by manually filling that form or you can just import a JSON file with the configuration you want. For this guide, we'll just import a JSON file as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"clientId": "servlet-authz-app",
|
||||
"allowRemoteResourceManagement": true,
|
||||
"allowEntitlements": true,
|
||||
"policyEnforcementMode": "ENFORCING",
|
||||
"resources": [
|
||||
{
|
||||
"name": "Admin Resource",
|
||||
"uri": "/protected/admin/*",
|
||||
"type": "http://servlet-authz/protected/admin",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "urn:servlet-authz:protected:admin:access"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Protected Resource",
|
||||
"uri": "/*",
|
||||
"type": "http://servlet-authz/protected/resource",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "urn:servlet-authz:protected:resource:access"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Premium Resource",
|
||||
"uri": "/protected/premium/*",
|
||||
"type": "urn:servlet-authz:protected:resource",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "urn:servlet-authz:protected:premium:access"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Main Page",
|
||||
"type": "urn:servlet-authz:protected:resource",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "urn:servlet-authz:page:main:actionForAdmin"
|
||||
},
|
||||
{
|
||||
"name": "urn:servlet-authz:page:main:actionForUser"
|
||||
},
|
||||
{
|
||||
"name": "urn:servlet-authz:page:main:actionForPremiumUser"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"name": "Any Admin Policy",
|
||||
"description": "Defines that adminsitrators can do something",
|
||||
"type": "role",
|
||||
"config": {
|
||||
"roles": "[\"admin\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Any User Policy",
|
||||
"description": "Defines that any user can do something",
|
||||
"type": "role",
|
||||
"config": {
|
||||
"roles": "[\"user\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Only Premium User Policy",
|
||||
"description": "Defines that only premium users can do something",
|
||||
"type": "role",
|
||||
"logic": "POSITIVE",
|
||||
"config": {
|
||||
"roles": "[\"user_premium\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "All Users Policy",
|
||||
"description": "Defines that all users can do something",
|
||||
"type": "aggregate",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Any User Policy\",\"Any Admin Policy\",\"Only Premium User Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Premium Resource Permission",
|
||||
"description": "A policy that defines access to premium resources",
|
||||
"type": "resource",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"resources": "[\"Premium Resource\"]",
|
||||
"applyPolicies": "[\"Only Premium User Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Administrative Resource Permission",
|
||||
"description": "A policy that defines access to administrative resources",
|
||||
"type": "resource",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"resources": "[\"Admin Resource\"]",
|
||||
"applyPolicies": "[\"Any Admin Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Protected Resource Permission",
|
||||
"description": "A policy that defines access to any protected resource",
|
||||
"type": "resource",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"resources": "[\"Protected Resource\"]",
|
||||
"applyPolicies": "[\"All Users Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Action 1 on Main Page Resource Permission",
|
||||
"description": "A policy that defines access to action 1 on the main page",
|
||||
"type": "scope",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"scopes": "[\"urn:servlet-authz:page:main:actionForAdmin\"]",
|
||||
"applyPolicies": "[\"Any Admin Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Action 2 on Main Page Resource Permission",
|
||||
"description": "A policy that defines access to action 2 on the main page",
|
||||
"type": "scope",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"scopes": "[\"urn:servlet-authz:page:main:actionForUser\"]",
|
||||
"applyPolicies": "[\"Any User Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Action 3 on Main Page Resource Permission",
|
||||
"description": "A policy that defines access to action 3 on the main page",
|
||||
"type": "scope",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"scopes": "[\"urn:servlet-authz:page:main:actionForPremiumUser\"]",
|
||||
"applyPolicies": "[\"Only Premium User Policy\"]"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
[NOTE]
|
||||
All this configuration can also be done using the {{book.project.name}} Administration Console. We are using the import tool just for demonstration purposes
|
||||
|
||||
=== A Quick Overview of the Permissions and Policies
|
||||
|
||||
The resource server configuration tells a lot about what we are really protecting. It is basically describing the security requirements we have discussed earlier.
|
||||
|
||||
Fist of all, we define four resources:
|
||||
|
||||
* Admin Resource
|
||||
* Protected Resource
|
||||
* Premium Resource
|
||||
* Main Page
|
||||
|
||||
As the name implies, each of these resources are related with the requirements we previously discussed, representing the different areas or group of resources we want to protect.
|
||||
|
||||
As you may notice, each of these resources (except Main Page) defines an *uri* property. This property represents the path we want to protect and they map directly, or indirectly by using a pattern,
|
||||
to the resources served by the application.
|
||||
|
||||
Let's take the _Protected Resource_ as an example:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Protected Resource",
|
||||
"uri": "/*",
|
||||
"type": "http://servlet-authz/protected/resource",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "urn:servlet-authz:protected:resource:access"
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
This resource represents all resources in the application, as you can see from the pattern used in the *uri* property. It also defines a single scope/action to indicate that users, if granted, can access this resource.
|
||||
|
||||
Now, let's see what are the permissions and authorization policies configured to this resource:
|
||||
|
||||
```json
|
||||
...
|
||||
{
|
||||
"name": "Protected Resource Permission",
|
||||
"description": "A policy that defines access to any protected resource",
|
||||
"type": "resource",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"resources": "[\"Protected Resource\"]",
|
||||
"applyPolicies": "[\"All Users Policy\"]"
|
||||
}
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
The definition above is a permission that links the _Protected Resource_ with the policies we want to apply. In this case, we are applying a single _All Users Policy_.
|
||||
|
||||
Policies define the conditions to be meet in order to access something. In this case, the _All Users Policy_ is composed of two other policies, a special policy type called link:../policy/aggregated-policy.html[Aggregated Policies].
|
||||
|
||||
```json
|
||||
...
|
||||
{
|
||||
"name": "All Users Policy",
|
||||
"description": "Defines that all users can do something",
|
||||
"type": "aggregate",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Any User Policy\",\"Any Admin Policy\",\"Only Premium User Policy\"]"
|
||||
}
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
{{book.project.name}} provides a few built-in policy types (and their respective policy providers) implementing different access control mechanisms (RBAC, GBAC, Rule-based, Time-based, etc) that you can use to build your own policies and permissions.
|
||||
|
||||
Aggregated policies are very useful in order to group related policies together and make policy management less painful.
|
||||
|
||||
=== Configuring the Keycloak Enforcement Filter
|
||||
|
||||
Now that we have all the configuration for our resource server in place, we can configure the authorization enforcement filter to actually protected the resources.
|
||||
|
||||
Just like any other Servlet Filter, you just need to include the following configuration in your web application descriptor (WEB-INF/web.xml):
|
||||
|
||||
```xml
|
||||
<filter>
|
||||
<filter-name>Keycloak Authorization Enforcer</filter-name>
|
||||
<filter-class>org.keycloak.authorization.policy.enforcer.servlet.KeycloakAdapterEnforcementFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>Keycloak Authorization Enforcer</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
```
|
||||
The *org.keycloak.authorization.policy.enforcer.servlet.KeycloakAdapterEnforcementFilter* is shipped with the {{book.project.name}} OIDC Adapters distribution. In order to make it available to
|
||||
your application at runtime, you must create a *META-INF/jboss-deployment-structure.xml* at the application root directory. If you are using maven, this file can be placed under *src/main/webapp/META-INF/jboss-deployment-structure.xml*:
|
||||
|
||||
```xml
|
||||
<jboss-deployment-structure>
|
||||
<deployment>
|
||||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-authz-servlet-enforcer" services="import"/>
|
||||
<module name="org.jboss.resteasy.resteasy-jackson2-provider" services="import"/>
|
||||
</dependencies>
|
||||
<exclusions>
|
||||
<module name="org.jboss.resteasy.resteasy-jackson-provider"/>
|
||||
</exclusions>
|
||||
</deployment>
|
||||
</jboss-deployment-structure>
|
||||
```
|
||||
|
||||
For last, you need to create a *META-INF/keycloak-authz.json*. If you are using Maven, this file goes inside *src/main/resources*:
|
||||
|
||||
```json
|
||||
{
|
||||
"client": {
|
||||
"configurationUrl": "http://localhost:8080/auth/realms/servlet-authz/authz/uma_configuration",
|
||||
"clientId": "servlet-authz-app",
|
||||
"clientSecret": "secret"
|
||||
},
|
||||
"enforcer": {}
|
||||
}
|
||||
```
|
||||
|
||||
=== Running and Using the Application
|
||||
|
||||
All the source code for this application is at *${KEYCLOAK_DEMO_SERVER_DIR}/examples/authz/servlet-authz/*.
|
||||
|
||||
There you can execute the following command to _deploy_ the application to the running server:
|
||||
|
||||
```bash
|
||||
mvn clean package wildfly:deploy
|
||||
```
|
||||
That should be enough to get the application properly packaged and deployed to a _running_ {{book.project.name}} server.
|
||||
|
||||
If the application was properly deployed, you can try to access it at http://localhost:8080/auth[http://localhost:8080/servlet-authz-app] and use the following credentials to login into the application:
|
||||
|
||||
If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
|
||||
|
||||
* username: alice / password: alice (regular user)
|
||||
* username: jdoe / password: jdoe (premium user)
|
||||
* username: admin / password: admin (administrator)
|
||||
|
||||
To _undeploy_ the application, please execute the following command:
|
||||
|
||||
```bash
|
||||
mvn wildfly:undeploy
|
||||
```
|
|
@ -10,6 +10,9 @@ This guide will show you how to:
|
|||
The purpose of this guide is to give you a generic overview of {{book.project.name}} {{book.project.module}} so you can understand
|
||||
some core concepts and start protecting your applications and services despite the platform they are running on.
|
||||
|
||||
[NOTE]
|
||||
Before going further, make sure you followed all the instructions in the link:../getting-started/getting-started.html[Getting Started] guide.
|
||||
|
||||
=== Creating the Hello World AuthZ Realm
|
||||
|
||||
For this guide, we are going to create a *hello-world-authz* realm. Just import the following JSON file to create the new realm:
|
||||
|
@ -94,7 +97,7 @@ It must have a *client_id*, *client_secret* and *Service Account* enabled:
|
|||
"clients" : [
|
||||
{
|
||||
"clientId" : "hello-world-authz-service",
|
||||
"secret" : "7801be7c-437a-44ae-be34-67da32f024eb",
|
||||
"secret" : "password",
|
||||
"serviceAccountsEnabled" : true,
|
||||
...
|
||||
}
|
||||
|
@ -156,6 +159,9 @@ From that page you can create a resource server by manually filling that form or
|
|||
|
||||
```
|
||||
|
||||
[NOTE]
|
||||
All this configuration can also be done using the {{book.project.name}} Administration Console. We are using the import tool just for demonstration purposes
|
||||
|
||||
After importing the JSON file above, you would see a page like that:
|
||||
|
||||
image:../../images/gs-authz-hello-rs-created-page.png[alt="Resource Server Successfully Created"]
|
||||
|
|
Loading…
Reference in a new issue