Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jpmsilva/6f7ccdc8421d42eeab50d8ff19cdbb18 to your computer and use it in GitHub Desktop.
Save jpmsilva/6f7ccdc8421d42eeab50d8ff19cdbb18 to your computer and use it in GitHub Desktop.

Install and enable confluence_http_authenticator

Creative Commons License
Install and enable confluence_http_authenticator by Joao Silva is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at https://gist.github.com/jpmsilva/6f7ccdc8421d42eeab50d8ff19cdbb18.

These are the steps taken to enable authentication in Confluence by way of an OIDC compliant IdP.

These steps were tested with the following bill of materials:

The main focus of this article is on how to enable SSO in Confluence via oauth2/OpenID Connect. As such, the installation of Keycloak 11, the setup of a realm and the installation of oauth2-proxy will not be covered.

For our specific use-case, Keycloak was set up with user federation from the corporate LDAP.

Confluence was also configured with a user directory to read from the same LDAP, so that the same users will exist on both systems. In addition, Confluence will read groups and group memberships from LDAP, allowing us to create rich ACL models in Confluence.

Architecture


                          +--------------------------+     http     +---------------------+
                          |                          +------------->|   Keycloak node 1   |
              https       | Keycloak                 |              +---------------------+
                +-------->| Load balancer/web server |                        ...
                |         | SSL/TLS termination      |     http     +---------------------+
+------+        |         | kb.example.org           +------------->|   Keycloak node x   |
|      +--------+         +--------------------------+              +---------------------+
| User |
|      +--------+         +--------------------------+     http     +---------------------+     http     +--------------------------+     http     +---------------------+
+------+        |         |                          +------------->| oauth2-proxy node 1 +------------->|                          +------------->|  Confluence node 1  |
                |         | oauth2-proxy             |              +---------------------+              | Confluence               |              +---------------------+
                +-------->| Load balancer/web server |                        ...                        | Load balancer/web server |                        ...
              https       | SSL/TLS termination      |     http     +---------------------+     http     |                          |     http     +---------------------+
                          | id.example.org           +------------->| oauth2-proxy node x +------------->| confluence.example.org   +------------->|  Confluence node x  |
                          +--------------------------+              +---------------------+              +--------------------------+              +---------------------+

oauth2-proxy is a reverse proxy solution that will only allow request to be forwarded to the backend if a valid oauth2 access token is presented. If no such token is presented, a browser based oauth2 authentication flow will be triggered.

oauth2-proxy will ensure that requests are only forwarded to the upstream Confluence service if the client has been authenticated.

Note, though, that with the configuration presented here, oauth2-proxy only checks if a valid access token exists. It performs no other access control checks itself, even though it could also do group or role checks if needed. Access control is delegated entirely on Confluence.

The various pieces of the architecture (Confluence, Keycloak and oauth2-proxy) may be redundant. For such cases, load balancers may be required.

For security purposes it is assumed that at least the user facing components are exposed via https. SSL/TLS termination may be put in place, and the remaining communications can be over http, assuming they happen within a secure perimeter.

It SSL/TLS is not used at all, make sure to configure session cookies to not have the Secure flag. Each component uses their own type of session cookies.

Variables

Variables to change as needed:

  1. https://kb.example.org: the URL from which Confluence will be made available to end users, pointing to the oauth2-proxy load balancer (or directly to the service if only one node).

  2. https://id.example.org: the URL from which Keycloak will be made available to end users, pointing to the Keycloak load balancer (or directly to the service if only one node).

  3. http://confluence.example.org: the URL pointing directly to the Confluence load balancer (or directly to the service if only one node).

  4. corporaterealm: the oauth2 realm, defined in Keycloak.

  5. confluence-client-id: the JWT Client ID, defined in Keycloak.

  6. confluence-secret: the JWT Secret, defined in Keycloak (treat it as a secret).

  7. averylongstringofsecurecharater: a secret to encrypt oauth2-proxy cookies (make it a 32 character random string and treat it as a secret).

  8. $CONFLUENCE_HOME the folder where Confluence was installed.

Configure a client in Keycloak

  1. Access your Keycloak realm config and create a client. Take note of the Client ID (confluence-client-id).

  2. Configure the client with Access Type confidential.

  3. Configure the Valid Redirect URIs with the public facing URL of your Confluence setup as https://kb.example.org/oauth2/callback.

  4. From the Credentials tab take note of the secret (confluence-secret).

Configure an oauth2-proxy instance

  1. The following is the sample configuration for oauth2-proxy. Adjust to your needs as documented in https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#config-file. Just take care regarding the changes between CLI arguments and the respective configuration variables (such as --client-id becomes client_id).
provider = "oidc"
client_id = "confluence-client-id"
client_secret = "confluence-secret"
oidc_issuer_url = "https://id.example.org/auth/realms/corporaterealm"
email_domains = [ "*" ]
cookie_secret = "averylongstringofsecurecharater"
http_address = "http://:4180"
scope = "openid"
redirect_url = "https://kb.example.org/oauth2/callback"
reverse_proxy = "True"
cookie_secure = "True"
upstreams = [ "http://confluence.example.org/" ]
skip_provider_button = "True"
real_client_ip_header = "X-Forwarded-For"
skip_auth_regex = "^\\/((rest\\/token-auth\\/api\\/)|(download\\/token-auth\\/attachments\\/)|(plugins\\/servlet\\/imgFilter)|(rest\\/analytics\\/1.0\\/publish\\/bulk)|(s)|(download\\/attachments)|(rest\\/shortcuts\\/latest\\/shortcuts)|(rest\\/quickreload\\/latest)|(rest\\/webResources\\/1\\.0\\/resources)|(rest\\/gadgets\\/1\\.0\\/g\\/messagebundle)|(rest\\/nativemobile\\/1\\.0\\/info\\/)).*"
pass_basic_auth = "True"
pass_user_headers = "True"

This configuration may require adjustments. Notice that there is no configuration for SSL/TLS here, as in this configuration SSL termination is performed in the loadbalancer that sits in front of oauth2-proxy.

oauth2-proxy can also be configured to serve via https, by pointint to the security material in the configuration file. Note that if you don't have SSL/TLS downstream from oauth2-proxy, you may want to set cookie_secure to False.

Also note the property skip_auth_regex. This regex controls the URIs that will be passed directly to Confluence without requiring a valid access token. We did various tests to check everything that we may safely exclude this way. Some are well documented, while others we found by looking at 403 errors while browsing Confluence. Depending on the applications you have installed in Confluence you may require additional exclusions here.

  1. Launch oauth2-proxy. If you created the configuration file in /opt/oauth2-proxy/instances/confluence.cfg you can run it with /path/to/oauth2-proxy --config=/opt/oauth2-proxy/instances/confluence.cfg.

Install confluence_http_authenticator

  1. Download remoteUserAuth-2.7.3.jar from the available releases at https://github.com/chauth/confluence_http_authenticator/tree/master/releases and copy to $CONFLUENCE_HOME/confluence/WEB-INF/lib

  2. Create the file $CONFLUENCE_HOME/confluence/WEB-INF/classes/remoteUserAuthenticator.properties with the following content:

    local.login.supported=true
    create.users=false
    update.info=false
    update.last.login.date=true
    reload.config=false
    reload.config.check.interval=5000
    default.roles=confluence-users
    header.remote_user=X-Forwarded-Preferred-Username
    header.remote_user.strategy=2
    username.convertcase=true
    username.filter=CN=([A-Za-z0-9]*)
    update.roles=false
    convert.to.utf8=false
    dynamicroles.auto_create_role=false
    dynamicroles.output.tolowercase=true

    The configuration is taken from the sample provided at https://github.com/chauth/confluence_http_authenticator/blob/master/conf/remoteUserAuthenticator.properties.

    You should change it to better suite your needs. In our case, since we use LDAP as a read-only source of user information, we don't want to try to update user information via this plugin.

    header.remote_user defines the header set by oauth2-proxy that contains the username of the authenticated user, which is X-Forwarded-Preferred-Username.

    Local logins are allowed in this configuration, but there is really no way to log in using these accounts, as the IdP has no knowledge of them. Instead, we configured a restricted frontend webserver, that talks directly with the Confluence Tomcat server pool. We restrict this frontend to a range of allowed IP addresses. That way we retain the ability to login with a local admin, in the event of issues with the corporate LDAP.

  3. Edit the file $CONFLUENCE_HOME/confluence/WEB-INF/classes/seraph-config.xml.

    Comment out the default authenticator, and add the confluence_http_authenticator authenaticator:

        <!-- Default Confluence authenticator, which uses the configured user management for authentication. -->
        <!-- <authenticator class="com.atlassian.confluence.user.ConfluenceAuthenticator"/> -->
    
        <!-- Custom authenticators appear below. To enable one of them, comment out the default authenticator above and uncomment the one below. -->
    
        <!-- Authenticator with support for Crowd single-sign on (SSO). -->
        <!-- <authenticator class="com.atlassian.confluence.user.ConfluenceCrowdSSOAuthenticator"/> -->
    
        <!-- Specialised version of the default authenticator which adds authenticated users to confluence-users if they aren't already a member. -->
        <!-- <authenticator class="com.atlassian.confluence.user.ConfluenceGroupJoiningAuthenticator"/> -->
    
        <authenticator class="shibauth.confluence.authentication.shibboleth.RemoteUserAuthenticator"/>
  4. Restart Confluence

Update frontend

This step assumes that there is a frontend load balancer/web server in the architecture that acts as SSL/TLS termination for end users to access the service. The URL https://kb.example.org is served by this service.

If you set up oauth2-proxy to serve directly to your end users (with or without SSL/TLS) this step is not needed.

Change the backend configuration of https://kb.example.org to point to the oauth2-proxy backends instead of the Confluence backends.

Test

If all goes well, when you access https://kb.example.org you will now be redirected to https://id.example.org to complete the authentication steps dimmed necessary by the realm.

Once you succesfully complete authentication you will be redirected back to https://kb.example.org fully logged in to Confluence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment