Merge pull request #19119 from ahus1/is-CIAM-5056-move-documentation-to-main-repo

Move documentation to main repo
This commit is contained in:
Stian Thorgersen 2023-03-20 09:22:56 +01:00 committed by GitHub
commit f39c473866
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
829 changed files with 34485 additions and 0 deletions

View File

@ -0,0 +1,6 @@
:icons: font
:idprefix:
:idseparator: -
:project_buildType: latest
ifndef::asciidoctorconfigdir[:asciidoctorconfigdir: .]
include::{asciidoctorconfigdir}/topics/templates/document-attributes.adoc[]

20
docs/documentation/.gitattributes vendored Normal file
View File

@ -0,0 +1,20 @@
* text=auto
*.html text eol=lf
*.java text eol=lf
*.js text eol=lf
*.json text eol=lf
*.jsp text eol=lf
*.md text eol=lf
*.properties text eol=lf
*.svg text auto
*.xml text eol=lf
*.xsl text eol=lf
*.png binary
*.jpg binary
*.gif binary
*.ttf binary
*.eot binary
*.otf binary
*.woff binary

View File

@ -0,0 +1,40 @@
name: Bug Report
description: Report a non-security sensitive bug in Keycloak
labels: ["kind/bug", "status/triage"]
body:
- type: textarea
attributes:
label: Describe the bug
description: Provide a clear and concise description of what the problem is.
validations:
required: true
- type: input
attributes:
label: Version
description: What version of Keycloak are you running?
validations:
required: true
- type: textarea
attributes:
label: Expected behavior
description: Describe the expected behavior clearly and concisely.
validations:
required: false
- type: textarea
attributes:
label: Actual behavior
description: Describe the actual behavior clearly and concisely.
validations:
required: false
- type: textarea
attributes:
label: How to Reproduce?
description: Provide clear and concise steps to reproduce the problem.
validations:
required: false
- type: textarea
attributes:
label: Anything else?
description: Links? References? Anything that will give us more context about the issue you are encountering!
validations:
required: false

View File

@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Discussions
url: https://github.com/keycloak/keycloak/discussions
about: Propose new ideas, provide feedback, or ask for help here
- name: User mailing list
url: https://groups.google.com/forum/#!forum/keycloak-user
about: Ask and answer questions here
- name: Developer mailing list
url: https://groups.google.com/forum/#!forum/keycloak-dev
about: Propose new features and join in design discussions here

View File

@ -0,0 +1,31 @@
name: Enhancement Request
description: Request an enhancement to an existing feature
labels: ["kind/enhancement", "status/triage"]
body:
- type: textarea
attributes:
label: Description
description: Describe the enhancement at a high-level.
validations:
required: true
- type: input
attributes:
label: Discussion
description: |
If there has been a discussion around the enhancement, provide a link to the discussion.
Please note that larger enhancements should be discussed through [GitHub Discussion](https://github.com/keycloak/keycloak/discussions/categories/ideas).
validations:
required: false
- type: textarea
attributes:
label: Motivation
description: Describe why the feature should be added.
validations:
required: false
- type: textarea
attributes:
label: Details
description: More details? Implementation ideas? Anything that will give us more context about the enhancement you are proposing!
validations:
required: false

View File

@ -0,0 +1,32 @@
name: Epic
description: A large feature that is broken down into multiple linked issues.
labels: ["kind/epic", "status/triage"]
body:
- type: textarea
attributes:
label: Description
description: Describe the feature at a high-level.
validations:
required: true
- type: input
attributes:
label: Discussion
description: |
Provide a link to the GitHub Discussion for the feature.
validations:
required: true
- type: textarea
attributes:
label: Issues
description: List the issues related to this epic.
placeholder: |
- #1
- #2
validations:
required: false
- type: textarea
attributes:
label: Motivation
description: Provide a brief explanation of why the feature should be added.
validations:
required: false

View File

@ -0,0 +1,31 @@
name: Feature Request
description: Request a new feature to be added to Keycloak
labels: ["kind/feature", "status/triage"]
body:
- type: textarea
attributes:
label: Description
description: Describe the feature at a high-level.
validations:
required: true
- type: input
attributes:
label: Discussion
description: |
If there has been a discussion around the feature, provide a link to the discussion.
Please note that all, except small requests, should be discussed through [GitHub Discussion](https://github.com/keycloak/keycloak/discussions/categories/ideas).
validations:
required: false
- type: textarea
attributes:
label: Motivation
description: Describe why the feature should be added.
validations:
required: false
- type: textarea
attributes:
label: Details
description: Design ideas? Implementation ideas? Anything that will give us more context about the feature you are proposing!
validations:
required: false

View File

@ -0,0 +1,10 @@
name: Task
description: Any tasks that are not directly adding a new feature, enhancement or fixing a bug
labels: ["kind/task"]
body:
- type: textarea
attributes:
label: Description
description: Describe the task.
validations:
required: true

View File

@ -0,0 +1,26 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: External Links
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 5 * * *'
jobs:
test:
name: Verify links
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build
run: mvn install -B -DskipTests
- name: Test
run: mvn test -B -pl tests -Dtest=ExternalLinksTest

View File

@ -0,0 +1,25 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Test
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: Verify Keycloak documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build
run: mvn install -B -DskipTests
- name: Test
run: mvn test -B -pl tests -Dtest=!ExternalLinksTest

60
docs/documentation/.gitignore vendored Normal file
View File

@ -0,0 +1,60 @@
.verified-links
_book
node_modules
# Intellij
###################
.idea
*.iml
# Eclipse #
###########
.project
.settings
.classpath
# NetBeans #
############
nbactions.xml
nb-configuration.xml
catalog.xml
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built-in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
# Maven #
#########
target
build
html
# vim
######
*.swp
.vale.ini

View File

@ -0,0 +1,8 @@
StylesPath = /Users/bdooley/Documents/code/vale-boilerplate/styles
MinAlertLevel = error
Vocab = blog
[*.adoc]
BasedOnStyles = IBM, Vale, write-good

210
docs/documentation/License.html Executable file
View File

@ -0,0 +1,210 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<pre>
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
</pre>
</body>
</html>

49
docs/documentation/README.md Executable file
View File

@ -0,0 +1,49 @@
Keycloak Documentation
======================
Open Source Identity and Access Management for modern Applications and Services.
For more information about Keycloak visit the [Keycloak homepage](http://keycloak.org) and [Keycloak blog](https://www.keycloak.org/blog).
Contributing to Keycloak Documentation
----------------------------------------
See our [Contributor's Guide](internal_resources/contributing.adoc). The directory also includes a set of templates and other resources to help you get started.
If you want to file a bug report or tell us about any other issue with this documentation, you are invited to please use our [issue tracker](https://issues.redhat.com/projects/KEYCLOAK/).
Building Keycloak Documentation
---------------------------------
Ensure that you have [Maven installed](https://maven.apache.org/).
First, clone the Keycloak Documentation repository:
git clone https://github.com/keycloak/keycloak-documentation.git
cd keycloak-documentation
If you are using Windows, you need to run the following command with administrator privilege because this project uses symbolic links:
git clone -c core.symlinks=true https://github.com/keycloak/keycloak-documentation.git
To build Keycloak Documentation run:
mvn clean install
Or to build a specific guide run:
mvn clean install -f GUIDE_DIR
By default, an archive version of the documentation is built. To build the latest build run:
mvn clean install -Dlatest
You can then view the documentation by opening GUIDE_DIR/target/generated-docs/index.html.
License
-------
* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)

View File

@ -0,0 +1,238 @@
<style>
/* Top menu */
@media only screen and (min-width: 768px) {
div.top-menu-guides {
position: fixed;
display: inline-block;
top: 0;
left: 0;
z-index: 9999;
}
div.top-menu-guides p {
margin: 0;
padding: 0;
}
div.top-menu-guides .content {
margin: 0;
padding: 7px 20px 0 20px;
background-color: #ededed;
height: 48px;
width: 20em;
}
@media only screen and (max-width: 1280px) {
div.top-menu-guides .content {
width: 15em;
}
}
div.top-menu-guides .ulist {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
padding: 0px;
margin-top: 12px;
}
div.top-menu-guides .ulist ul {
list-style: none;
padding: 5px;
margin: 0;
}
div.top-menu-guides .ulist li {
padding: 5px 10px;
}
div.top-menu-guides:hover .ulist {
display: block;
}
div.top-menu-version {
position: fixed;
top: 0;
z-index: 9999;
}
div.top-menu-version .content {
padding: 0;
margin: 0;
background-color: #eee;
height: 48px;
padding: 7px;
}
.versionarchive {
display: inline-block;
}
.versionarchive p {
margin: 0;
padding: 2px 5px 2px 10px;
}
.versionarchive a {
background-color: #ffdd57;
padding: 0 5px;
font-style: normal;
border-radius: 5px;
margin-left: 10px;
}
.versionlatest {
display: inline-block;
}
.versionlatest p {
background-color: #eee;
border-radius: 5px;
margin: 0;
padding: 2px 5px 2px 10px;
}
.versionlatest em {
background-color: #23d160;
padding: 0 5px;
font-style: normal;
border-radius: 5px;
margin-left: 10px;
}
}
/* TOC */
#tocbot a.toc-link.node-name--H1{ font-style: italic }
@media screen{
#tocbot > ul.toc-list{ margin-bottom: 0.5em; margin-left: 0.125em }
#tocbot ul.sectlevel0, #tocbot a.toc-link.node-name--H1 + ul{
padding-left: 0 }
#tocbot a.toc-link{ height:100% }
.is-collapsible{ max-height:3000px; overflow:hidden; }
.is-collapsed{ max-height:0 }
.is-active-link{ font-weight:700 }
}
@media print{
#tocbot a.toc-link.node-name--H4{ display:none }
}
/* Fix scroll to anchor hides title */
h1::before, h2::before, h3::before, h4::before, h5::before, h6::before {
display: block;
content: " ";
height: 70px;
margin-top: -70px;
}
h1 {
border-bottom: none !important
}
#toc.toc2 {
top: 30px;
bottom: 0px;
height: unset;
}
body.toc2 {
padding-top: 30px;
}
@media only screen and (min-width:768px) {
#toc.toc2 {
top: 40px;
}
body.toc2 {
padding-top: 40px;
}
}
@media only screen and (min-width:1280px) {
#toc.toc2 {
top: 48px;
}
body.toc2 {
padding-top: 48px;
}
}
/* General Changes */
h1, h2, h3, #toctitle, .sidebarblock>.content>.title, h4, h5, h6 {
color: #444444;
font-weight: 500;
}
a {
color: #004670;
text-decoration: none;
}
a:hover {
color: #7da1dc;
}
body {
font-family: "Open Sans","DejaVu Sans",sans-serif;
color: #444444;
}
.subheader, .admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title {
color: #444444;
}
.admonitionblock td.content>.title, .audioblock>.title, .exampleblock>.title, .imageblock>.title, .listingblock>.title, .literalblock>.title, .stemblock>.title, .openblock>.title, .paragraph>.title, .quoteblock>.title, table.tableblock>.title, .verseblock>.title, .videoblock>.title, .dlist>.title, .olist>.title, .ulist>.title, .qlist>.title, .hdlist>.title {
font-family: "Open Sans","DejaVu Sans",sans-serif;
font-style: normal;
}
span.image img {
border:1px solid #ccc;
-webkit-box-shadow: 3px 3px 15px 0px rgba(0,0,0,0.5);
-moz-box-shadow: 3px 3px 15px 0px rgba(0,0,0,0.5);
box-shadow: 3px 3px 15px 0px rgba(0,0,0,0.5);
}
.sect1+.sect1 {
border-top: none;
}
.page-links {
border-bottom: 1px solid #efefed;
border-top: none;
background: none;
position: relative;
left: 0em;
width: 100%;
top: -5em;
height: 0;
margin: 0;
padding: 0;
}
.sect2 .page-links {
top: -3.5em;
}
.page-links .content {
background: #f8f8f7;
border: 1px solid #e0e0dc;
float: right;
font-size: 0.8em;
margin: 0;
padding: 5px;
}
.page-links a {
display: block;
padding: 5px;
}
</style>

View File

@ -0,0 +1,37 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.js"></script>
<script>
const oldtoc = document.getElementById('toctitle').nextElementSibling;
const newtoc = document.createElement('div');
newtoc.setAttribute('id', 'tocbot');
newtoc.setAttribute('class', 'js-toc');
oldtoc.parentNode.replaceChild(newtoc, oldtoc);
tocbot.init({ contentSelector: '#content',
headingSelector: 'h2, h3, h4',
smoothScroll: false
});
const handleTocOnResize = function() {
const width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
if (width < 768) {
tocbot.refresh({
contentSelector: '#content',
headingSelector: 'h2, h3, h4',
collapseDepth: 6,
activeLinkClass: 'ignoreactive',
throttleTimeout: 1000,
smoothScroll: false
});
}
else {
tocbot.refresh({
contentSelector: '#content',
headingSelector: 'h2, h3, h4',
smoothScroll: false
});
}
};
window.addEventListener('resize', handleTocOnResize);
handleTocOnResize();
</script>

View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak.documentation</groupId>
<artifactId>documentation-parent</artifactId>
<version>999.0.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<name>Aggregation</name>
<artifactId>aggregation</artifactId>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak.documentation</groupId>
<artifactId>api-documentation</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.keycloak.documentation</groupId>
<artifactId>authorization-services</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.keycloak.documentation</groupId>
<artifactId>securing-apps</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.keycloak.documentation</groupId>
<artifactId>server-admin</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.keycloak.documentation</groupId>
<artifactId>server-development</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.keycloak.documentation</groupId>
<artifactId>release-notes</artifactId>
<version>${project.version}</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<outputDirectory>../target</outputDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-api_documentation</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/api_documentation/</outputDirectory>
<resources>
<resource>
<directory>../api_documentation/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-authorization_services</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/authorization_services/</outputDirectory>
<resources>
<resource>
<directory>../authorization_services/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-getting_started</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/getting_started/</outputDirectory>
<resources>
<resource>
<directory>../getting_started/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-securing_apps</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/securing_apps/</outputDirectory>
<resources>
<resource>
<directory>../securing_apps/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-server_admin</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/server_admin/</outputDirectory>
<resources>
<resource>
<directory>../server_admin/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-server_development</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/server_development/</outputDirectory>
<resources>
<resource>
<directory>../server_development/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-release_notes</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/release_notes/</outputDirectory>
<resources>
<resource>
<directory>../release_notes/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-upgrading</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/upgrading/</outputDirectory>
<resources>
<resource>
<directory>../upgrading/target/generated-docs</directory>
<include>**/**</include>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-index</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/</outputDirectory>
<resources>
<resource>
<directory>src</directory>
<include>*.html</include>
<include>*.png</include>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>echo-output-aggregation</id>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echo>OUTPUT (no-frames): file://${project.build.outputDirectory}/index.html</echo>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Documentation Index</title>
</head>
<style>
body {
background-color: #ededed;
font-family: sans-serif;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
padding: 5px;
}
li a {
color: #004670;
text-align: center;
padding: 5px 16px;
text-decoration: none;
}
li a:hover {
color: #428bca;
}
</style>
<body>
<img src="keycloak_logo.png"/>
<ul>
<li><a href="securing_apps/${masterFile}.html">Securing Apps</a></li>
<li><a href="server_admin/${masterFile}.html">Server Admin</a></li>
<li><a href="server_development/${masterFile}.html">Server Development</a></li>
<li><a href="authorization_services/${masterFile}.html">Authorization Services</a></li>
<li><a href="upgrading/${masterFile}.html">Upgrading</a></li>
<li><a href="release_notes/${masterFile}.html">Release Notes</a></li>
</ul>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,8 @@
include::topics/templates/document-attributes.adoc[]
:api_documentation:
:linkattrs:
= {apidocs_name}
include::topics.adoc[]

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak.documentation</groupId>
<artifactId>documentation-parent</artifactId>
<version>999.0.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<name>API Documentation</name>
<artifactId>api-documentation</artifactId>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.keycloak.documentation</groupId>
<artifactId>header-maven-plugin</artifactId>
<executions>
<execution>
<id>add-file-headers</id>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<executions>
<execution>
<id>asciidoc-to-html</id>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>echo-output</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1 @@
include::topics/overview.adoc[]

View File

@ -0,0 +1,12 @@
include::templates/making-open-source-more-inclusive.adoc[]
== {project_name} API Documentation
=== JavaDocs Documentation
{apidocs_javadocs_link}[{apidocs_javadocs_name}]
=== Admin REST API Documentation
{apidocs_adminrest_link}[{apidocs_adminrest_name}]

View File

@ -0,0 +1 @@
../../topics/templates

View File

@ -0,0 +1 @@
../aggregation/navbar.html

View File

@ -0,0 +1 @@
../aggregation/navbar-head.html

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -0,0 +1,20 @@
:toc: left
:toclevels: 3
:sectanchors:
:linkattrs:
include::topics/templates/document-attributes.adoc[]
:authorization_services_guide:
:context: authorization_services_guide
= {authorizationguide_name}
:release_header_guide: {authorizationguide_name_short}
:release_header_latest_link: {authorizationguide_link_latest}
include::topics/templates/release-header.adoc[]
include::topics.adoc[]
:context:

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak.documentation</groupId>
<artifactId>documentation-parent</artifactId>
<version>999.0.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<name>Authorization Services</name>
<artifactId>authorization-services</artifactId>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.keycloak.documentation</groupId>
<artifactId>header-maven-plugin</artifactId>
<executions>
<execution>
<id>add-file-headers</id>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<executions>
<execution>
<id>asciidoc-to-html</id>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>echo-output</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,121 @@
include::topics/auth-services-overview.adoc[leveloffset=+1]
include::topics/auth-services-architecture.adoc[leveloffset=+2]
include::topics/auth-services-terminology.adoc[leveloffset=+2]
include::topics/getting-started-overview.adoc[leveloffset=+1]
include::topics/hello-world-overview.adoc[leveloffset=+2]
include::topics/hello-world-create-realm.adoc[leveloffset=+2]
include::topics/hello-world-create-resource-server.adoc[leveloffset=+2]
include::topics/hello-world-deploy.adoc[leveloffset=+2]
include::topics/authorization-quickstarts.adoc[leveloffset=+2]
include::topics/resource-server-overview.adoc[leveloffset=+1]
include::topics/resource-server-create-client.adoc[leveloffset=+2]
include::topics/resource-server-enable-authorization.adoc[leveloffset=+2]
include::topics/resource-server-default-config.adoc[leveloffset=+2]
include::topics/resource-server-import-config.adoc[leveloffset=+2]
include::topics/resource-overview.adoc[leveloffset=+1]
include::topics/resource-view.adoc[leveloffset=+2]
include::topics/resource-create.adoc[leveloffset=+2]
include::topics/policy-overview.adoc[leveloffset=+1]
include::topics/policy-user-policy.adoc[leveloffset=+2]
include::topics/policy-role-policy.adoc[leveloffset=+2]
include::topics/policy-role-policy-required-role.adoc[leveloffset=+3]
include::topics/policy-js-policy.adoc[leveloffset=+2]
include::topics/policy-time-policy.adoc[leveloffset=+2]
include::topics/policy-aggregated-policy.adoc[leveloffset=+2]
include::topics/policy-client-policy.adoc[leveloffset=+2]
include::topics/policy-group-policy.adoc[leveloffset=+2]
include::topics/policy-group-policy-extend-children.adoc[leveloffset=+3]
include::topics/policy-client-scope-policy.adoc[leveloffset=+2]
include::topics/policy-client-scope-policy-required-client-scope.adoc[leveloffset=+3]
include::topics/policy-regex-policy.adoc[leveloffset=+2]
include::topics/policy-logic.adoc[leveloffset=+2]
include::topics/policy-evaluation-api.adoc[leveloffset=+2]
include::topics/permission-overview.adoc[leveloffset=+1]
include::topics/permission-create-resource.adoc[leveloffset=+2]
include::topics/permission-typed-resource-permission.adoc[leveloffset=+3]
include::topics/permission-create-scope.adoc[leveloffset=+2]
include::topics/permission-decision-strategy.adoc[leveloffset=+2]
include::topics/policy-evaluation-tool-overview.adoc[leveloffset=+1]
include::topics/service-overview.adoc[leveloffset=+1]
include::topics/service-authorization-discovery-document.adoc[leveloffset=+2]
include::topics/service-authorization-obtaining-permission.adoc[leveloffset=+2]
include::topics/service-authorization-obtaining-permission-authentication.adoc[leveloffset=+3]
include::topics/service-authorization-pushing-claims.adoc[leveloffset=+3]
include::topics/service-authorization-obtaining-permission-uma.adoc[leveloffset=+2]
include::topics/service-authorization-uma-authz-process.adoc[leveloffset=+3]
include::topics/service-authorization-uma-submiting-permission-requests.adoc[leveloffset=+3]
include::topics/service-authorization-uma-account-my-resources.adoc[leveloffset=+3]
include::topics/service-protection-protection-api.adoc[leveloffset=+2]
include::topics/service-protection-whatis-obtain-pat.adoc[leveloffset=+3]
include::topics/service-protection-resources-api-papi.adoc[leveloffset=+3]
include::topics/service-protection-permission-api-papi.adoc[leveloffset=+3]
include::topics/service-protection-policy-api.adoc[leveloffset=+3]
include::topics/service-rpt-overview.adoc[leveloffset=+2]
include::topics/service-rpt-token-introspection.adoc[leveloffset=+3]
include::topics/service-client-api.adoc[leveloffset=+2]
include::topics/enforcer-overview.adoc[leveloffset=+1]
include::topics/enforcer-keycloak-enforcement-filter.adoc[leveloffset=+2]
include::topics/enforcer-claim-information-point.adoc[leveloffset=+2]
include::topics/enforcer-authorization-context.adoc[leveloffset=+2]
include::topics/enforcer-js-adapter.adoc[leveloffset=+2]
include::topics/enforcer-https.adoc[leveloffset=+2]

View File

@ -0,0 +1,130 @@
[[_overview_architecture]]
= Architecture
image:images/authz-arch-overview.png[alt="{project_name} AuthZ architecture overview"]
From a design perspective, Authorization Services is based on a well-defined set of authorization patterns providing these capabilities:
* **Policy Administration Point (PAP)**
+
Provides a set of UIs based on the {project_name} Administration Console to manage resource servers, resources, scopes, permissions, and policies.
Part of this is also accomplished remotely through the use of the <<_service_protection_api, Protection API>>.
+
* **Policy Decision Point (PDP)**
+
Provides a distributable policy decision point to where authorization requests are sent and policies are evaluated accordingly with the permissions being requested.
For more information, see <<_service_obtaining_permissions, Obtaining Permissions>>.
+
* **Policy Enforcement Point (PEP)**
+
Provides implementations for different environments to actually enforce authorization decisions at the resource server side.
{project_name} provides some built-in <<_enforcer_overview, Policy Enforcers>>.
+
* **Policy Information Point (PIP)**
+
Being based on {project_name} Authentication Server, you can obtain attributes from identities and runtime environment during the evaluation of authorization policies.
== The authorization process
Three main processes define the necessary steps to understand how to use {project_name} to enable fine-grained authorization to your applications:
* *Resource Management*
* *Permission and Policy Management*
* *Policy Enforcement*
=== Resource management
*Resource Management* involves all the necessary steps to define what is being protected.
image:images/resource-mgmt-process.png[alt="Resource management overview"]
First, you need to specify {project_name} what are you looking to protect, which usually represents a web application or a set of one or more services. For more information on resource servers see <<_overview_terminology, Terminology>>.
Resource servers are managed using the {project_name} Administration Console. There you can enable any registered client application as a resource server and start managing the resources and scopes you want to protect.
image:images/rs-r-scopes.png[alt="Resource Server overview"]
A resource can be a web page, a RESTFul resource, a file in your file system, an EJB, and so on. They can represent a group of resources (just like a Class in Java) or they can represent a single and specific resource.
For instance, you might have a _Bank Account_ resource that represents all banking accounts and use it to define the authorization policies that are common to all banking accounts. However, you might want to define specific policies for _Alice Account_ (a resource instance that belongs to a customer), where only the owner is allowed to access some information or perform an operation.
Resources can be managed using the {project_name} Administration Console or the <<_service_protection_api, Protection API>>. In the latter case, resource servers are able to manage their resources remotely.
Scopes usually represent the actions that can be performed on a resource, but they are not limited to that. You can also use scopes to represent one or more attributes within a resource.
=== Permission and policy management
Once you have defined your resource server and all the resources you want to protect, you must set up permissions and policies.
This process involves all the necessary steps to actually define the security and access requirements that govern your resources.
image:images/policy-mgmt-process.png[alt="Permission and policy management overview"]
Policies define the conditions that must be satisfied to access or perform operations on something (resource or scope), but they are not tied to what they are protecting. They are generic and can be reused to build permissions or even more complex policies.
For instance, to allow access to a group of resources only for users granted with a role "User Premium", you can use RBAC (Role-based Access Control).
{project_name} provides a few built-in policy types (and their respective policy providers) covering the most common access control mechanisms. You can even create policies based on rules written using JavaScript.
Once you have your policies defined, you can start defining your permissions. Permissions are coupled with the resource they are protecting. Here you specify
what you want to protect (resource or scope) and the policies that must be satisfied to grant or deny permission.
=== Policy enforcement
*Policy Enforcement* involves the necessary steps to actually enforce authorization decisions to a resource server. This is achieved by enabling a *Policy Enforcement Point* or PEP at the resource server that is capable of communicating with the authorization server, ask for authorization data and control access to protected resources based on the decisions and permissions returned by the server.
image:images/pep-pattern-diagram.png[alt="PEP overview"]
{project_name} provides some built-in <<_enforcer_overview, Policy Enforcers>> implementations that you can use to protect your applications depending on the platform they are running on.
== Authorization services
Authorization services consist of the following RESTFul endpoints:
* *Token Endpoint*
* *Resource Management Endpoint*
* *Permission Management Endpoint*
Each of these services provides a specific API covering the different steps involved in the authorization process.
=== Token endpoint
OAuth2 clients (such as front end applications) can obtain access tokens from the server using the token endpoint and use
these same tokens to access resources protected by a resource server (such as back end services). In the same way,
{project_name} Authorization Services provide extensions to OAuth2 to allow access tokens to be issued based on the processing
of all policies associated with the resource(s) or scope(s) being requested. This means that resource servers can enforce access
to their protected resources based on the permissions granted by the server and held by an access token. In {project_name} Authorization Services
the access token with permissions is called a Requesting Party Token or RPT for short.
[role="_additional-resources"]
.Additional resources
* <<_service_obtaining_permissions, Obtaining Permissions>>
=== Protection API
The *Protection API* is a set of https://docs.kantarainitiative.org/uma/wg/oauth-uma-federated-authz-2.0-09.html[UMA-compliant] endpoint-providing operations
for resource servers to help them manage their resources, scopes, permissions, and policies associated with them. Only resource servers are allowed to access this API, which also requires a
*uma_protection* scope.
The operations provided by the Protection API can be organized in two main groups:
* *Resource Management*
** Create Resource
** Delete Resource
** Find by Id
** Query
* *Permission Management*
** Issue Permission Tickets
[NOTE]
By default, Remote Resource Management is enabled. You can change that using the {project_name} Administration Console and only allow resource management through the console.
When using the UMA protocol, the issuance of Permission Tickets by the Protection API is an important part of the whole authorization process. As described in a subsequent section, they represent the permissions being requested by the client and that are sent to the server to obtain a final token with all permissions granted during the evaluation of the permissions and policies associated with the resources and scopes being requested.
[role="_additional-resources"]
.Additional resources
* <<_service_protection_api, Protection API>>

View File

@ -0,0 +1,38 @@
[[_overview]]
= Authorization services overview
:tech_feature_name: Authorization Services
{project_name} supports fine-grained authorization policies and is able to combine different access control
mechanisms such as:
* **Attribute-based access control (ABAC)**
* **Role-based access control (RBAC)**
* **User-based access control (UBAC)**
* **Context-based access control (CBAC)**
* **Rule-based access control**
** Using JavaScript
* **Time-based access control**
* **Support for custom access control mechanisms (ACMs) through a Service Provider Interface (SPI)**
{project_name} is based on a set of administrative UIs and a RESTful API, and provides the necessary means to create permissions
for your protected resources and scopes, associate those permissions with authorization policies, and enforce authorization decisions in your applications and services.
Resource servers (applications or services serving protected resources) usually rely on some kind of information to decide if access should be granted to a protected resource. For RESTful-based resource servers, that information is usually obtained from a security token, usually sent as a bearer token on every request to the server. For web applications that rely on a session to authenticate users, that information is usually stored in a user's session and retrieved from there for each request.
Frequently, resource servers only perform authorization decisions based on role-based access control (RBAC), where the roles granted to the user trying to access protected resources are checked against the roles mapped to these same resources. While roles are very useful and used by applications, they also have a few limitations:
* Resources and roles are tightly coupled and changes to roles (such as adding, removing, or changing an access context) can impact multiple resources
* Changes to your security requirements can imply deep changes to application code to reflect these changes
* Depending on your application size, role management might become difficult and error-prone
* It is not the most flexible access control mechanism. Roles do not represent who you are and lack contextual information. If you have been granted a role, you have at least some access.
Considering that today we need to consider heterogeneous environments where users are distributed across different regions, with different local policies,
using different devices, and with a high demand for information sharing, {project_name} Authorization Services can help you improve the authorization capabilities of your applications and services by providing:
* Resource protection using fine-grained authorization policies and different access control mechanisms
* Centralized Resource, Permission, and Policy Management
* Centralized Policy Decision Point
* REST security based on a set of REST-based authorization services
* Authorization workflows and User-Managed Access
* The infrastructure to help avoid code replication across projects (and redeploys) and quickly adapt to changes in your security requirements.

View File

@ -0,0 +1,76 @@
[[_overview_terminology]]
= Terminology
Before going further, it is important to understand these terms and concepts introduced by {project_name} Authorization Services.
[[_overview_terminology_resource_server]]
== Resource Server
Per OAuth2 terminology, a resource server is the server hosting the protected resources and capable of accepting and responding to protected resource requests.
Resource servers usually rely on some kind of information to decide whether access to a protected resource should be granted. For RESTful-based resource servers,
that information is usually carried in a security token, typically sent as a bearer token along with every request to the server. Web applications that rely on a session to
authenticate users usually store that information in the user's session and retrieve it from there for each request.
In {project_name}, any *confidential* client application can act as a resource server. This client's resources and their respective scopes are protected and governed by a set of authorization policies.
== Resource
A resource is part of the assets of an application and the organization. It can be a set of one or more endpoints, a classic web resource such as an HTML page, and so on.
In authorization policy terminology, a resource is the _object_ being protected.
Every resource has a unique identifier that can represent a single resource or a set of resources. For instance, you can manage a _Banking Account Resource_ that represents and defines a set of authorization policies for all banking accounts. But you can also have a different resource named _Alice's Banking Account_, which represents a single resource owned by a single customer, which can have its own set of authorization policies.
== Scope
A resource's scope is a bounded extent of access that is possible to perform on a resource. In authorization policy terminology, a scope is one of the potentially many _verbs_ that can logically apply to a resource.
It usually indicates what can be done with a given resource. Example of scopes are view, edit, delete, and so on. However, scope can also be related to specific information provided by a resource. In this case, you can have a project resource and a cost scope, where the cost scope is used to define specific policies and permissions for users to access a project's cost.
== Permission
Consider this simple and very common permission:
A permission associates the object being protected with the policies that must be evaluated to determine whether access is granted.
* *X* CAN DO *Y* ON RESOURCE *Z*
** where ...
*** *X* represents one or more users, roles, or groups, or a combination of them. You can also use claims and context here.
*** *Y* represents an action to be performed, for example, write, view, and so on.
*** *Z* represents a protected resource, for example, "/accounts".
{project_name} provides a rich platform for building a range of permission strategies ranging from simple to very complex, rule-based dynamic permissions. It provides flexibility and helps to:
* Reduce code refactoring and permission management costs
* Support a more flexible security model, helping you to easily adapt to changes in your security requirements
* Make changes at runtime; applications are only concerned about the resources and scopes being protected and not how they are protected.
== Policy
A policy defines the conditions that must be satisfied to grant access to an object. Unlike permissions, you do not specify the object being protected
but rather the conditions that must be satisfied for access to a given object (for example, resource, scope, or both).
Policies are strongly related to the different access control mechanisms (ACMs) that you can use to protect your resources.
With policies, you can implement strategies for attribute-based access control (ABAC), role-based access control (RBAC), context-based access control, or any combination of these.
{project_name} leverages the concept of policies and how you define them by providing the concept of aggregated policies, where you can build a "policy of policies" and still control the behavior of the evaluation.
Instead of writing one large policy with all the conditions that must be satisfied for access to a given resource, the policies implementation in {project_name} Authorization Services follows the divide-and-conquer technique.
That is, you can create individual policies, then reuse them with different permissions and build more complex policies by combining individual policies.
== Policy provider
Policy providers are implementations of specific policy types. {project_name} provides built-in policies, backed by their corresponding
policy providers, and you can create your own policy types to support your specific requirements.
{project_name} provides an SPI (Service Provider Interface) that you can use to plug in your own policy provider implementations.
[[_overview_terminology_permission_ticket]]
== Permission ticket
A permission ticket is a special type of token defined by the User-Managed Access (UMA) specification that provides an opaque structure whose form is determined by the authorization server. This
structure represents the resources and/or scopes being requested by a client, the access context, as well as the policies that must be applied to a request for authorization data (requesting party token [RPT]).
In UMA, permission tickets are crucial to support person-to-person sharing and also person-to-organization sharing. Using permission tickets for authorization workflows enables a range of scenarios from simple to complex, where resource owners and resource servers have complete control over their resources based on fine-grained policies that govern the access to these resources.
In the UMA workflow, permission tickets are issued by the authorization server to a resource server, which returns the permission ticket to the client trying to access a protected resource. Once the client receives the ticket, it can make a request for an RPT (a final token holding authorization data) by sending the ticket back to the authorization server.
For more information on permission tickets, see <<_service_user_managed_access, User-Managed Access>> and the https://docs.kantarainitiative.org/uma/wg/oauth-uma-grant-2.0-09.html[UMA] specification.

View File

@ -0,0 +1,35 @@
[[_authorization_quickstarts]]
= Authorization quickstarts
In addition to the *app-authz-jee-vanilla* quickstart that was used as a sample application in the previous section, the
link:{quickstartRepo_link}[{quickstartRepo_name}] contains other applications that make use of the authorization services
described in this documentation.
The authorization quickstarts have been designed so that authorization services are displayed in different scenarios and
using different technologies and integrations. It is not meant as a comprehensive set of all the possible use cases involving
authorization but they should provide a starting point for users interested in understanding how the authorization services
can be used in their own applications.
Each quickstart has a `README` file with instructions on how to build, deploy, and test the sample application. The following
table provides a brief description of the available authorization quickstarts:
.Authorization quickstarts
|===
|Name |Description
| {quickstartRepo_link}/tree/latest/app-authz-jee-servlet[app-authz-jee-servlet]
| Demonstrates how to enable fine-grained authorization to a Jakarta EE application in order to protect specific resources and build a dynamic menu based on the permissions obtained from a {Project_Name} Server.
| {quickstartRepo_link}/tree/latest/app-authz-jee-vanilla[app-authz-jee-vanilla]
| Demonstrates how to enable fine-grained authorization to a Jakarta EE application and use the default authorization settings to protect all resources in the application.
| {quickstartRepo_link}/tree/latest/app-authz-rest-springboot[app-authz-rest-springboot]
| Demonstrates how to protect a SpringBoot REST service using {Project_Name} Authorization Services.
| {quickstartRepo_link}/tree/latest/app-authz-springboot[app-authz-springboot]
| Demonstrates how to write a SpringBoot Web application where both authentication and authorization aspects are managed by {Project_Name}.
| {quickstartRepo_link}/tree/latest/app-authz-uma-photoz[app-authz-uma-photoz]
| A simple application based on HTML5+AngularJS+JAX-RS that demonstrates how to enable User-Managed Access to your application and let users manage permissions for their resources.
|===

View File

@ -0,0 +1,71 @@
[[_enforcer_authorization_context]]
= Obtaining the authorization context
When policy enforcement is enabled, the permissions obtained from the server are available through `org.keycloak.AuthorizationContext`.
This class provides several methods you can use to obtain permissions and ascertain whether a permission was granted for a particular resource or scope.
Obtaining the Authorization Context in a Servlet Container
```java
HttpServletRequest request = ... // obtain javax.servlet.http.HttpServletRequest
KeycloakSecurityContext keycloakSecurityContext =
(KeycloakSecurityContext) request
.getAttribute(KeycloakSecurityContext.class.getName());
AuthorizationContext authzContext =
keycloakSecurityContext.getAuthorizationContext();
```
[NOTE]
For more details about how you can obtain a `KeycloakSecurityContext` consult the adapter configuration. The example above should be sufficient
to obtain the context when running an application using any of the servlet containers supported by {project_name}.
The authorization context helps give you more control over the decisions made and returned by the server. For example, you can use it
to build a dynamic menu where items are hidden or shown depending on the permissions associated with a resource or scope.
```java
if (authzContext.hasResourcePermission("Project Resource")) {
// user can access the Project Resource
}
if (authzContext.hasResourcePermission("Admin Resource")) {
// user can access administration resources
}
if (authzContext.hasScopePermission("urn:project.com:project:create")) {
// user can create new projects
}
```
The `AuthorizationContext` represents one of the main capabilities of {project_name} Authorization Services. From the examples above, you can see that the protected resource is not directly associated with the policies that govern them.
Consider some similar code using role-based access control (RBAC):
```java
if (User.hasRole('user')) {
// user can access the Project Resource
}
if (User.hasRole('admin')) {
// user can access administration resources
}
if (User.hasRole('project-manager')) {
// user can create new projects
}
```
Although both examples address the same requirements, they do so in different ways. In RBAC, roles only _implicitly_ define access for their resources. With {project_name} you gain the capability to create more manageable code that focuses directly on your resources whether you are using RBAC, attribute-based access control (ABAC), or any other BAC variant. Either you have the permission for a given resource or scope, or you don't.
Now, suppose your security requirements have changed and in addition to project managers, PMOs can also create new projects.
Security requirements change, but with {project_name} there is no need to change your application code to address the new requirements. Once your application is based on the resource and scope identifier, you need only change the configuration of the permissions or policies associated with a particular resource in the authorization server. In this case, the permissions and policies associated with the `Project Resource` and/or the scope `urn:project.com:project:create` would be changed.
= Using the AuthorizationContext to obtain an Authorization Client Instance
The ```AuthorizationContext``` can also be used to obtain a reference to the <<_service_client_api, Authorization Client API>> configured to your application:
```java
ClientAuthorizationContext clientContext = ClientAuthorizationContext.class.cast(authzContext);
AuthzClient authzClient = clientContext.getClient();
```
In some cases, resource servers protected by the policy enforcer need to access the APIs provided by the authorization server. With an ```AuthzClient``` instance in hands, resource servers can interact with the server in order to create resources or check for specific permissions programmatically.

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, 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 a 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 MyClaimInformationPointProvider(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

@ -0,0 +1,18 @@
[[_enforcer_filter_using_https]]
= Configuring TLS/HTTPS
When the server is using HTTPS, ensure your adapter is configured as follows:
.keycloak.json
```json
{
"truststore": "path_to_your_trust_store",
"truststore-password": "trust_store_password"
}
```
The configuration above enables TLS/HTTPS to the Authorization Client, making possible to access a
{project_name} Server remotely using the HTTPS scheme.
[NOTE]
It is strongly recommended that you enable TLS/HTTPS when accessing the {project_name} Server endpoints.

View File

@ -0,0 +1,149 @@
[[_enforcer_js_adapter]]
= JavaScript integration
The {project_name} Server comes with a JavaScript library you can use to interact with a resource server protected by a policy enforcer.
This library is based on the {project_name} JavaScript adapter, which can be integrated to allow your client to obtain permissions from a {project_name} Server.
You can obtain this library from a running a {project_name} Server instance by including the following `script` tag in your web page:
[source,html,subs="attributes+"]
----
<script src="http://...{kc_js_path}/keycloak-authz.js"></script>
----
Once you do that, you can create a `KeycloakAuthorization` instance as follows:
```javascript
const keycloak = ... // obtain a Keycloak instance from keycloak.js library
const authorization = new KeycloakAuthorization(keycloak);
```
The *keycloak-authz.js* library provides two main features:
* Obtain permissions from the server using a permission ticket, if you are accessing a UMA protected resource server.
* Obtain permissions from the server by sending the resources and scopes the application wants to access.
In both cases, the library allows you to easily interact with both resource server and {project_name} Authorization Services to obtain tokens with
permissions your client can use as bearer tokens to access the protected resources on a resource server.
== Handling authorization responses from a UMA-Protected resource server
If a resource server is protected by a policy enforcer, it responds to client requests based on the permissions carried along with a bearer token.
Typically, when you try 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.
[source,bash,subs="attributes+"]
----
HTTP/1.1 401 Unauthorized
WWW-Authenticate: UMA realm="${realm}",
as_uri="https://${host}:${port}{kc_realms_path}/${realm}",
ticket="016f84e8-f9b9-11e0-bd6f-0021cc6004de"
----
See <<_service_uma_authorization_process, UMA Authorization Process>> for more information.
What your client needs to do is extract the permission ticket from the ```WWW-Authenticate``` header returned by the resource server
and use the library to send an authorization request as follows:
```javascript
// prepare a authorization request with the permission ticket
const authorizationRequest = {};
authorizationRequest.ticket = ticket;
// send the authorization request, if successful retry the request
Identity.authorization.authorize(authorizationRequest).then(function (rpt) {
// onGrant
}, function () {
// onDeny
}, function () {
// onError
});
```
The `authorize` function is completely asynchronous and supports a few callback functions to receive notifications from the server:
* `onGrant`: The first argument of the function. If authorization was successful and the server returned an RPT with the requested permissions, the callback receives the RPT.
* `onDeny`: The second argument of the function. Only called if the server has denied the authorization request.
* `onError`: The third argument of the function. Only called if the server responds unexpectedly.
Most applications should use the `onGrant` callback to retry a request after a 401 response. Subsequent requests should include the RPT as a bearer token for retries.
== Obtaining entitlements
The ```keycloak-authz.js``` library provides an `entitlement` function that you can use to obtain an RPT from the server by providing
the resources and scopes your client wants to access.
.Example about how to obtain an RPT with permissions for all resources and scopes the user can access
```javascript
authorization.entitlement('my-resource-server-id').then(function (rpt) {
// onGrant callback function.
// If authorization was successful you'll receive an RPT
// with the necessary permissions to access the resource server
});
```
.Example about how to obtain an RPT with permissions for specific resources and scopes
```javascript
authorization.entitlement('my-resource-server', {
"permissions": [
{
"id" : "Some Resource"
}
]
}).then(function (rpt) {
// onGrant
});
```
When using the `entitlement` function, you must provide the _client_id_ of the resource server you want to access.
The `entitlement` function is completely asynchronous and supports a few callback functions to receive notifications from the server:
* `onGrant`: The first argument of the function. If authorization was successful and the server returned an RPT with the requested permissions, the callback receives the RPT.
* `onDeny`: The second argument of the function. Only called if the server has denied the authorization request.
* `onError`: The third argument of the function. Only called if the server responds unexpectedly.
== Authorization request
Both ```authorize``` and ```entitlement``` functions accept an authorization request object. This object can be set with the following
properties:
* *permissions*
+
An array of objects representing the resource and scopes. For instance:
+
```javascript
const authorizationRequest = {
"permissions": [
{
"id" : "Some Resource",
"scopes" : ["view", "edit"]
}
]
}
```
+
* *metadata*
+
An object where its properties define how the authorization request should be processed by the server.
+
** *response_include_resource_name*
+
A boolean value indicating to the server if resource names should be included in the RPT's permissions. If false, only the resource
identifier is included.
** *response_permissions_limit*
+
An integer N that defines a limit for the amount of permissions an RPT can have. When used together with
`rpt` parameter, only the last N requested permissions will be kept in the RPT
+
* *submit_request*
+
A boolean value indicating whether the server should create permission requests to the resources and scopes referenced by a permission ticket.
This parameter will only take effect when used together with the `ticket` parameter as part of a UMA authorization process.
== Obtaining the RPT
If you have already obtained an RPT using any of the authorization functions provided by the library, you can always obtain the RPT as follows from the authorization object (assuming that it has been initialized by one of the techniques shown earlier):
```javascript
const rpt = authorization.rpt;
```

View File

@ -0,0 +1,166 @@
[[_enforcer_filter]]
= Configuration
To enable policy enforcement for your application, add the following property to your *keycloak.json* file:
.keycloak.json
```json
{
"policy-enforcer": {}
}
```
Or a little more verbose if you want to manually define the resources being protected:
```json
{
"policy-enforcer": {
"user-managed-access" : {},
"enforcement-mode" : "ENFORCING",
"paths": [
{
"path" : "/someUri/*",
"methods" : [
{
"method": "GET",
"scopes" : ["urn:app.com:scopes:view"]
},
{
"method": "POST",
"scopes" : ["urn:app.com:scopes:create"]
}
]
},
{
"name" : "Some Resource",
"path" : "/usingPattern/{id}",
"methods" : [
{
"method": "DELETE",
"scopes" : ["urn:app.com:scopes:delete"]
}
]
},
{
"path" : "/exactMatch"
},
{
"name" : "Admin Resources",
"path" : "/usingWildCards/*"
}
]
}
}
```
Here is a description of each configuration option:
* *policy-enforcer*
+
Specifies the configuration options that define how policies are actually enforced and optionally the paths you want to protect. If not specified, the policy enforcer queries the server
for all resources associated with the resource server being protected. In this case, you need to ensure the resources are properly configured with a <<_resource_create_uri, URIS>> property that matches the paths you want to protect.
+
** *user-managed-access*
+
Specifies that the adapter uses the UMA protocol. If specified, the adapter queries the server for permission tickets and returns them to clients according to the UMA specification. If not specified, the policy enforcer will be able to enforce permissions based on regular access tokens or RPTs. In this case,
before denying access to the resource when the token lacks permission, the policy enforcer will try to obtain permissions directly from the server.
+
** *enforcement-mode*
+
Specifies how policies are enforced.
+
*** *ENFORCING*
+
(default mode) Requests are denied by default even when there is no policy associated with a given resource.
+
*** *PERMISSIVE*
+
Requests are allowed even when there is no policy associated with a given resource.
+
*** *DISABLED*
+
Completely disables the evaluation of policies and allows access to any resource. When `enforcement-mode` is `DISABLED`
applications are still able to obtain all permissions granted by {project_name} through the <<_enforcer_authorization_context, Authorization Context>>
+
** *on-deny-redirect-to*
+
Defines a URL where a client request is redirected when an "access denied" message is obtained from the server. By default, the adapter responds with a 403 HTTP status code.
+
** *path-cache*
+
Defines how the policy enforcer should track associations between paths in your application and resources defined in {project_name}. The cache is needed to avoid
unnecessary requests to a {project_name} server by caching associations between paths and protected resources.
+
*** *lifespan*
+
Defines the time in milliseconds when the entry should be expired. If not provided, default value is *30000*. A value equal to 0 can be set to completely disable the cache. A value equal to -1 can be set to disable the expiry of the cache.
+
*** *max-entries*
+
Defines the limit of entries that should be kept in the cache. If not provided, default value is *1000*.
+
** *paths*
+
Specifies the paths to protect. This configuration is optional. If not defined, the policy enforcer will discover all paths by fetching the resources you defined to your application in {project_name}, where these resources are defined with `URIS` representing some paths in your application.
+
*** *name*
+
The name of a resource on the server that is to be associated with a given path. When used in conjunction with a *path*, the policy enforcer ignores the resource's *URIS* property and uses the path you provided instead.
*** *path*
+
(required) A URI relative to the application's context path. If this option is specified, the policy enforcer queries the server for a resource with a *URI* with the same value.
Currently a very basic logic for path matching is supported. Examples of valid paths are:
+
**** Wildcards: `/*`
**** Suffix: `/*.html`
**** Sub-paths: `/path/*`
**** Path parameters: /resource/{id}
**** Exact match: /resource
**** Patterns: /{version}/resource, /api/{version}/resource, /api/{version}/resource/*
+
*** *methods*
+
The HTTP methods (for example, GET, POST, PATCH) to protect and how they are associated with the scopes for a given resource in the server.
+
**** *method*
+
The name of the HTTP method.
+
**** *scopes*
+
An array of strings with the scopes associated with the method. When you associate scopes with a specific method, the client trying to access a protected resource (or path) must provide an RPT that grants permission to all scopes specified in the list. For example, if you define a method _POST_ with a scope _create_, the RPT must contain a permission granting access to the _create_ scope when performing a POST to the path.
+
**** *scopes-enforcement-mode*
+
A string referencing the enforcement mode for the scopes associated with a method. Values can be *ALL* or *ANY*. If *ALL*,
all defined scopes must be granted in order to access the resource using that method. If *ANY*, at least one scope should be
granted in order to gain access to the resource using that method. By default, enforcement mode is set to *ALL*.
+
*** *enforcement-mode*
+
Specifies how policies are enforced.
+
**** *ENFORCING*
+
(default mode) Requests are denied by default even when there is no policy associated with a given resource.
+
**** *DISABLED*
+
*** *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
enforcer is going to fetch resources on-demand accordingly with the path being requested. This configuration is specially useful
when you don't want to fetch all resources from the server during deployment (in case you have provided no `paths`) or in case
you have defined only a sub set of `paths` and want to fetch others on-demand.
+
** *http-method-as-scope*
+
Specifies how scopes should be mapped to HTTP methods. If set to *true*, the policy enforcer will use the HTTP method from the current request to
check whether or not access should be granted. When enabled, make sure your resources in {project_name} are associated with scopes representing each HTTP method you are protecting.
+
** *claim-information-point*
+
Defines a set of one or more *global* 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.

View File

@ -0,0 +1,32 @@
[[_enforcer_overview]]
= Policy enforcers
Policy Enforcement Point (PEP) is a design pattern and as such you can implement it in different ways. {project_name} provides all the necessary means
to implement PEPs for different platforms, environments, and programming languages. {project_name} Authorization Services presents a RESTful API,
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.
Permissions are enforced depending on the protocol you are using. When using UMA, the policy enforcer always expects an RPT as a bearer token in order
to decide whether or not a request can be served. That means clients should first obtain an RPT from {project_name} before sending requests to the resource server.
However, if you are not using UMA, you can also send regular access tokens to the resource server. In this case, the policy enforcer will try to obtain permissions directly from the server.
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 to 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.

View File

@ -0,0 +1,26 @@
[[_getting_started_overview]]
= Getting started
Before you can use this tutorial, you need to complete the installation of {project_name} and create the initial admin user as shown in the link:{gettingstarted_link}[{gettingstarted_name}] tutorial.
There is one caveat to this. You have to run a separate {appserver_name} instance on the same machine as {project_name} Server. This separate instance will run your Java Servlet application. Because of this you will have to run the {project_name} under a different port so that there are no port conflicts when running on the same machine. Use the `jboss.socket.binding.port-offset` system property on the command line. The value of this property is a number that will be added to the base value of every port opened by {project_name} Server.
To boot {project_name} Server:
.Linux/Unix
[source]
----
$ .../bin/kc.sh start-dev --http-port 8180
----
.Windows
[source]
----
> ...\bin\kc.bat start-dev --http-port 8180
----
After installing and booting both servers you should be able to access {project_name} Admin Console at http://localhost:8180/auth/admin/ and also the {appserver_name} instance at
http://localhost:8080.
[role="_additional-resources"]
.Additional resources
* For more details about installing and configuring {appserver_name} instances, see link:{adapterguide_link}[{adapterguide_name}].

View File

@ -0,0 +1,15 @@
= Before you start
This guide is based on the *{project_name} Demo Distribution*. Download the demo distribution before proceeding.
[NOTE]
This guide assumes that you are already familiar with {project_name} and that you are able to install and boot a {project_name} Server. For more information, see https://keycloak.gitbooks.io/getting-started-tutorials/content/[the Getting Started tutorials].
Ensure you have a {project_name} instance running; the default configuration is http://localhost:8080/auth[http://localhost:8080/auth]. After logging in to the
Administration Console, a page similar to this one is displayed:
.{project_name} Admin Console
image:images/getting-started/kc-start-page.png[alt="{project_name} Admin Console"]
The source code for the getting started tutorials can be obtained from the demo distributions. The authorization-related examples
are located at *${KEYCLOAK_DEMO_SERVER_DIR}/examples/authz*.

View File

@ -0,0 +1,33 @@
[[_getting_started_hello_world_create_realm]]
= Creating a realm and a user
The first step in this tutorial is to create a realm and a user in that realm. Then, within the realm we will create a single client application, which then becomes a <<_overview_terminology, resource server>> for which you need to enable authorization services.
.Procedure
. Create a realm with a name *hello-world-authz*. Once created, a page similar to the following is displayed:
+
.Realm hello-world-authz
image:images/getting-started/hello-world/create-realm.png[alt="Realm hello-world-authz"]
. Click *Users*.
+
The user list page displays where you can create a user.
. Click *Create user*.
. Complete the *Username*, *Email*, *First Name*, and *Last Name* fields.
. Toggle *User Enabled* to *ON*.
. Click *Create*.
+
.Add User
image:images/getting-started/hello-world/create-user.png[alt="Add User"]
. Set a password for the user by clicking the *Credentials* tab.
+
.Set user password
image:images/getting-started/hello-world/reset-user-pwd.png[alt="Set user password"]
. Complete the *New Password* and *Password Confirmation* fields and toggle *Temporary* to *OFF*.
. Click *Save*.
. Click *Save password*.

View File

@ -0,0 +1,39 @@
[[_getting_started_hello_world_enabling_authz_services]]
= Enabling authorization services
You can enable authorization services in an existing client application configured to use the OpenID Connect Protocol. You can also create a client using the following procedure.
.Procedure
. Click *Clients* in the menu.
. Fill in the *Client type*.
. Click *Next*.
. Toggle *Client authentication* to *ON*.
. Toggle *Authorization* to *ON*.
. Click *Save*.
. Scroll down to the *Capability config* section.
. Fill in the *Root URL* field.
. Click *Save*.
+
.Create client application
image:images/getting-started/hello-world/create-client.png[alt="Create client application"]
+
A new *Authorization* tab is displayed for the client.
+
.Client Settings
image:images/getting-started/hello-world/enable-authz.png[alt="Client Settings"]
. Click the *Authorization* tab.
+
An Authorization Settings page similar to the following is displayed:
+
.Authorization settings
image:images/getting-started/hello-world/authz-settings.png[alt="Authorization settings"]
When you enable authorization services for a client application, {project_name} automatically creates several default settings for your client authorization configuration.
[role="_additional-resources"]
.Additional resources
* <<_resource_server_enable_authorization, Enabling authorization services>>
* <<_resource_server_default_config, Default configuration>>

View File

@ -0,0 +1,129 @@
[[_getting_started_hello_world_deploy]]
= Build, deploy, and test your application
Now that the *app-authz-vanilla* resource server (or client) is properly configured and authorization services are enabled, it can be deployed to the server.
The project and code for the application you are going to deploy is available in link:{quickstartRepo_link}[{quickstartRepo_name}]. You will need the following
installed on your machine and available in your PATH before you can continue:
* Java JDK 8
* Apache Maven 3.1.1 or higher
* Git
ifeval::[{project_community}==true]
You can obtain the code by cloning the repository at {quickstartRepo_link}. The quickstarts are designed to work with the most recent Keycloak release.
endif::[]
ifeval::[{project_product}==true]
You can obtain the code by cloning the repository at {quickstartRepo_link}. Use the branch matching the version of {project_name} in use.
endif::[]
Follow these steps to download the code.
.Clone Project
[source, subs="attributes"]
----
$ git clone {quickstartRepo_link}
----
The application we are about to build and deploy is located at
[source, subs="attributes"]
----
$ cd {quickstartRepo_dir}/app-authz-jee-vanilla
----
== Obtaining the adapter configuration
You must first obtain the adapter configuration before building and deploying the application.
.Procedure
. Log into the Admin Console.
. Click *Clients* in the menu.
. In the client listing, click the *app-authz-vanilla* client application. The Client Settings page opens.
+
.Client Settings
image:images/getting-started/hello-world/enable-authz.png[alt="Client Settings"]
. From the *Action* list, select *Download adapter config*.
. From the Format Option list, select *Keycloak OIDC JSON*.
+
The adapter configuration is displayed in JSON format.
. Click *Download*.
+
.Adapter configuration
image:images/getting-started/hello-world/adapter-config.png[alt="Adapter configuration"]
. Move the file `keycloak.json` to the `app-authz-jee-vanilla/config` directory.
. Optionally, specify a redirection URL.
+
By default, the policy enforcer responds with a `403` status code when the user lacks permission to access protected resources on the resource server. However, you can also specify a redirection URL for unauthorized users. To specify a redirection URL, edit the *keycloak.json* file that you updated and replace the `policy-enforcer` configuration with the following:
+
```json
"policy-enforcer": {
"on-deny-redirect-to" : "/app-authz-vanilla/error.jsp"
}
```
+
This change specifies to the policy enforcer to redirect users to a `/app-authz-vanilla/error.jsp` page if a user does not have the necessary permissions to access a protected resource, rather than an unhelpful `403 Unauthorized` message.
== Building and deploying the application
To build and deploy the application execute the following command:
[source, subs="attributes"]
----
$ cd {quickstartRepo_dir}/app-authz-jee-vanilla
$ mvn clean package wildfly:deploy
----
== Testing the application
If your application was successfully deployed, you can access it at http://localhost:8080/app-authz-vanilla[http://localhost:8080/app-authz-vanilla]. The {project_name} Login page opens.
.Login page
image:images/getting-started/hello-world/login-page.png[alt="Login page"]
.Procedure
. Log in as *alice* using the password you specified for that user. The following page is displayed:
+
.Hello World Authz main page
image:images/getting-started/hello-world/main-page.png[alt="Hello World Authz main page"]
+
The <<_resource_server_default_config, default settings>> defined by {project_name} when you enable authorization services for a client application provide a simple
policy that always grants access to the resources protected by this policy.
You can start by changing the default permissions and policies and test how your application responds, or even create new policies using the different
<<_policy_overview, policy types>> provided by {project_name}.
There are a plenty of things you can do now to test this application. For example, you can change the default policy by clicking
the `Authorization` tab for the client, then client on the `Policies` tab, then click on the `Default Policy` in the list.
Now we are going to change the `Logic` to `Negative` using the dropdown list in this page.
. Log out of the demo application and log in again.
+
You can no longer access the application.
+
image:images/getting-started/hello-world/access-denied-page.png[alt="Access Denied page"]
[role="_additional-resources"]
.Additional resources
* <<_policy_overview, Policy types>>
== Next steps
There are additional things you can do, such as:
* Create a scope, define a policy and permission for it, and test it on the application side. Can the user perform an action (or anything else represented by the scope you created)?
* Create different types of policies and associate these policies with the `Default Permission`.
* Apply multiple policies to the `Default Permission` and test the behavior. For example, combine multiple policies and change the `Decision Strategy` accordingly.
[role="_additional-resources"]
.Additional resources
* For more information about how to view and test permissions inside your application see <<_enforcer_authorization_context, Obtaining the authorization context>>.

View File

@ -0,0 +1,14 @@
[[_getting_started_hello_world_overview]]
= Securing a servlet application
The purpose of this getting started guide is to get you up and running as quickly as possible so that you can experiment with and test various authorization features provided by {project_name}.
This quick tour relies heavily on the default database and server configurations and does not cover complex deployment options.
For more information on features or configuration options, see the appropriate sections in this documentation.
This guide explains key concepts about {project_name} Authorization Services:
* Enabling fine-grained authorization for a client application
* Configuring a client application to be a resource server, with protected resources
* Defining permissions and authorization policies to govern access to protected resources
* Enabling policy enforcement in your applications.

View File

@ -0,0 +1,42 @@
[[_permission_create_resource]]
= Creating resource-based permission
A resource-based permission defines a set of one or more resources to protect using a set of one or more authorization policies.
To create a new resource-based permission, select *Create resource-based permission* from the *Create permission* dropdown.
.Add Resource Permission
image:images/permission/create-resource.png[alt="Add Resource Permission"]
== Configuration
* *Name*
+
A human-readable and unique string describing the permission. A best practice is to use names that are closely related to your business and security requirements, so you
can identify them more easily.
+
* *Description*
+
A string containing details about this permission.
[[_permission_create_resource_apply_resource_type]]
* *Apply To Resource Type*
+
Specifies if the permission is applied to all resources with a given type. When selecting this field, you are prompted to enter the resource type to protect.
+
** Resource Type
+
Defines the resource type to protect. When defined, this permission is evaluated for all resources matching that type.
+
* *Resources*
+
Defines a set of one or more resources to protect.
* *Policy*
+
Defines a set of one or more policies to associate with a permission. To associate a policy you can either select an existing policy
or create a new one by selecting the type of the policy you want to create.
* *Decision Strategy*
+
The <<_permission_decision_strategies, Decision Strategy>> for this permission.

View File

@ -0,0 +1,37 @@
[[_permission_create_scope]]
= Creating scope-based permissions
A scope-based permission defines a set of one or more scopes to protect using a set of one or more authorization policies. Unlike resource-based permissions, you can use this permission type to create permissions not only for a resource, but also for the scopes associated with it, providing more granularity when defining the permissions that govern your resources and the actions that can be performed on them.
To create a new scope-based permission, select *Create scope-based permission* from the *Create permission* dropdown.
.Add Scope Permission
image:images/permission/create-scope.png[alt="Add Scope Permission"]
== Configuration
* *Name*
+
A human-readable and unique string describing the permission. A best practice is to use names that are closely related to your business and security requirements, so you
can identify them more easily.
+
* *Description*
+
A string containing details about this permission.
+
* *Resource*
+
Restricts the scopes to those associated with the selected resource. If none is selected, all scopes are available.
+
* *Scopes*
+
Defines a set of one or more scopes to protect.
* *Policy*
+
Defines a set of one or more policies to associate with a permission. To associate a policy you can either select an existing policy
or create a new one by selecting the type of the policy you want to create.
* *Decision Strategy*
+
The <<_permission_decision_strategies, Decision Strategy>> for this permission.

View File

@ -0,0 +1,16 @@
[[_permission_decision_strategies]]
= Policy decision strategies
When associating policies with a permission, you can also define a decision strategy to specify how to evaluate the outcome of the associated policies to determine access.
* *Unanimous*
+
The default strategy if none is provided. In this case, _all_ policies must evaluate to a positive decision for the final decision to be also positive.
+
* *Affirmative*
+
In this case, _at least one_ policy must evaluate to a positive decision for the final decision to be also positive.
+
* *Consensus*
+
In this case, the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative decisions is equal, the final decision will be negative.

Some files were not shown because too many files have changed in this diff Show More