<!--
  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
  ~ and other contributors as indicated by the @author tags.
  ~
  ~ 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.
  -->

<chapter id="proxy">
    <title>Keycloak Security Proxy</title>
    <para>
        Keycloak has an HTTP(S) proxy that you can put in front of web applications and services where it is not possible
        to install the keycloak adapter.  You can set up URL filters so that certain URLs are secured either by browser login
        and/or bearer token authentication.  You can also define role constraints for URL patterns within your applications.
    </para>
    <section>
        <title>Proxy Install and Run</title>
        <para>Download the keycloak proxy distribution from the Keycloak download pages and unzip it.
<programlisting>
$ unzip keycloak-proxy-dist.zip
</programlisting>
        </para>
        <para>
            To run it you must have a proxy config file (which we'll discuss in a moment).
<programlisting>
$ java -jar bin/launcher.jar [your-config.json]
</programlisting>
        </para>
        <para>
            If you do not specify a path to the proxy config file, the launcher will look in the current working directory
            for the file named <literal>proxy.json</literal>
        </para>
    </section>
    <section>
        <title>Proxy Configuration</title>
        <para>
            Here's an example configuration file.
<programlisting><![CDATA[
{
    "target-url": "http://localhost:8082",
    "send-access-token": true,
    "bind-address": "localhost",
    "http-port": "8080",
    "https-port": "8443",
    "keystore": "classpath:ssl.jks",
    "keystore-password": "password",
    "key-password": "password",
    "applications": [
        {
            "base-path": "/customer-portal",
            "error-page": "/error.html",
            "adapter-config": {
                "realm": "demo",
                "resource": "customer-portal",
                "realm-public-key": "MIGfMA0GCSqGSIb",
                "auth-server-url": "http://localhost:8081/auth",
                "ssl-required" : "external",
                "principal-attribute": "name",
                "credentials": {
                    "secret": "password"
                }
            }
            ,
            "constraints": [
                {
                    "pattern": "/users/*",
                    "roles-allowed": [
                        "user"
                    ]
                },
                {
                    "pattern": "/admins/*",
                    "roles-allowed": [
                        "admin"
                    ]
                },
                {
                    "pattern": "/users/permit",
                    "permit": true
                },
                {
                    "pattern": "/users/deny",
                    "deny": true
                }
            ]
        }
    ]
}]]>
</programlisting>
        </para>
        <section>
            <title>Basic Config</title>
        <para>
            The basic configuration options for the server are as follows:
            <variablelist>
                <varlistentry>
                    <term>target-url</term>
                    <listitem>
                        <para>
                            The URL this server is proxying <emphasis>REQUIRED.</emphasis>.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>send-access-token</term>
                    <listitem>
                        <para>
                            Boolean flag.  If true, this will send the access token via the KEYCLOAK_ACCESS_TOKEN header to the
                            proxied server. <emphasis>OPTIONAL.</emphasis>.  Default is false.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>bind-address</term>
                    <listitem>
                        <para>
                            DNS name or IP address to bind the proxy server's sockets to.
                            <emphasis>OPTIONAL.</emphasis>.  The default value is <emphasis>localhost</emphasis>
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>http-port</term>
                    <listitem>
                        <para>
                            Port to listen for HTTP requests.  If you do not specify this value, then the proxy will
                            not listen for regular HTTP requests.
                            <emphasis>OPTIONAL.</emphasis>.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>https-port</term>
                    <listitem>
                        <para>
                            Port to listen for HTTPS requests.  If you do not specify this value, then the proxy will
                            not listen for HTTPS requests.
                            <emphasis>OPTIONAL.</emphasis>.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>keystore</term>
                    <listitem>
                        <para>
                            Path to a Java keystore file that contains private key and certificate for the server to be
                            able to handle HTTPS requests.  Can be a file path, or, if you prefix it with <literal>classpath:</literal>
                            it will look for this file in the classpath.
                            <emphasis>OPTIONAL.</emphasis>.  If you have enabled HTTPS, but have not defined a keystore, the proxy
                            will auto-generate a self-signed certificate and use that.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>buffer-size</term>
                    <listitem>
                        <para>
                            HTTP server socket buffer size.  Usually the default is good enough. <emphasis>OPTIONAL.</emphasis>.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>buffers-per-region</term>
                    <listitem>
                        <para>
                            HTTP server socket buffers per region.  Usually the default is good enough. <emphasis>OPTIONAL.</emphasis>.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>io-threads</term>
                    <listitem>
                        <para>
                            Number of threads to handle IO.  Usually default is good enough.  <emphasis>OPTIONAL.</emphasis>.
                            The default is the number of available processors * 2.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>worker-threads</term>
                    <listitem>
                        <para>
                            Number of threads to handle requests.  Usually the default is good enough. <emphasis>OPTIONAL.</emphasis>.
                            The default is the number of available processors * 16.
                        </para>
                    </listitem>
                </varlistentry>
            </variablelist>
        </para>
        </section>
        <section>
            <title>Application Config</title>
            <para>
                Next under the <literal>applications</literal> array attribute, you can define one or more applications per host you are proxying.
                <variablelist>
                    <varlistentry>
                        <term>base-path</term>
                        <listitem>
                            <para>
                                The base context root for the application.  Must start with '/' <emphasis>REQUIRED.</emphasis>.
                            </para>
                        </listitem>
                    </varlistentry>
                    <varlistentry>
                        <term>error-page</term>
                        <listitem>
                            <para>
                                If the proxy has an error, it will display the target application's error page relative URL <emphasis>OPTIONAL.</emphasis>.
                                This is a relative path to the base-path.  In the example above it would be <literal>/customer-portal/error.html</literal>.
                            </para>
                        </listitem>
                    </varlistentry>
                    <varlistentry>
                        <term>adapter-config</term>
                        <listitem>
                            <para>
                                <emphasis>REQUIRED.</emphasis>.  Same configuration as any other keycloak adapter.  See <link linkend='adapter-config'>Adapter Config</link>
                            </para>
                        </listitem>
                    </varlistentry>
                </variablelist>
            </para>
            <section>
                <title>Constraint Config</title>
                <para>
                    Next under each application you can define one or more constraints in the <literal>constraints</literal> array attribute.
                    A constraint defines a URL pattern relative to the base-path.  You can deny, permit, or require authentication for
                    a specific URL pattern.  You can specify roles allowed for that path as well.  More specific constraints will take
                    precedence over more general ones.
                    <variablelist>
                        <varlistentry>
                            <term>pattern</term>
                            <listitem>
                                <para>
                                    URL pattern to match relative to the base-path of the application.  Must start with '/' <emphasis>REQUIRED.</emphasis>.
                                    You may only have one wildcard and it must come at the end of the pattern.  Valid <literal>/foo/bar/*</literal> and  <literal>/foo/*.txt</literal>
                                    Not valid: <literal>/*/foo/*</literal>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>roles-allowed</term>
                            <listitem>
                                <para>
                                    Array of strings of roles allowed to access this url pattern. <emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>methods</term>
                            <listitem>
                                <para>
                                    Array of strings of HTTP methods that will exclusively match this pattern and HTTP request. <emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>excluded-methods</term>
                            <listitem>
                                <para>
                                    Array of strings of HTTP methods that will be ignored when match this pattern. <emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>deny</term>
                            <listitem>
                                <para>
                                    Deny all access to this URL pattern. <emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>permit</term>
                            <listitem>
                                <para>
                                    Permit all access without requiring authentication or a role mapping. <emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>permit-and-inject</term>
                            <listitem>
                                <para>
                                    Permit all access, but inject the headers, if user is already authenticated.<emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                        <varlistentry>
                            <term>authenticate</term>
                            <listitem>
                                <para>
                                    Require authentication for this pattern, but no role mapping. <emphasis>OPTIONAL.</emphasis>.
                                </para>
                            </listitem>
                        </varlistentry>
                    </variablelist>
                </para>
            </section>
        </section>
        <section>
            <title>Header Names Config</title>
            <para>
            Next under the list of applications you can override the defaults for the names of the header fields injected by the proxy (see Keycloak Identity Headers).
            This mapping is optional.
            <variablelist>
                <varlistentry>
                    <term>keycloak-subject</term>
                    <listitem>
                        <para>
                            e.g. MYAPP_USER_ID
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>keycloak-username</term>
                    <listitem>
                        <para>
                            e.g. MYAPP_USER_NAME
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>keycloak-email</term>
                    <listitem>
                        <para>
                            e.g. MYAPP_USER_EMAIL
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>keycloak-name</term>
                    <listitem>
                        <para>
                            e.g. MYAPP_USER_ID
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>keycloak-access-token</term>
                    <listitem>
                        <para>
                            e.g. MYAPP_ACCESS_TOKEN
                        </para>
                    </listitem>
                </varlistentry>
            </variablelist>
            </para>
        </section>
    </section>
    <section>
        <title>Keycloak Identity Headers</title>
        <para>
            When forwarding requests to the proxied server, Keycloak Proxy will set some additional headers with values from the
            OIDC identity token it received for authentication.
            <variablelist>
                <varlistentry>
                    <term>KEYCLOAK-SUBJECT</term>
                    <listitem>
                        <para>
                            User id. Corresponds to JWT <literal>sub</literal> and will be the user id Keycloak uses to store
                            this user.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>KEYCLOAK-USERNAME</term>
                    <listitem>
                        <para>
                            Username. Corresponds to JWT <literal>preferred_username</literal>
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>KEYCLOAK-EMAIL</term>
                    <listitem>
                        <para>
                            Email address of user if set.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>KEYCLOAK-NAME</term>
                    <listitem>
                        <para>
                            Full name of user if set.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>KEYCLOAK-ACCESS-TOKEN</term>
                    <listitem>
                        <para>
                            Send the access token in this header if the proxy was configured to send it.  This token can
                            be used to make bearer token requests.
                        </para>
                    </listitem>
                </varlistentry>
            </variablelist>
            Header field names can be configured using a map of <literal>header-names</literal> in configuration file:
            <programlisting><![CDATA[
{
    "header-names" {
        "keycloak-subject": "MY-SUBJECT"
    }
}
            ]]></programlisting>
        </para>
    </section>
</chapter>