« Previous 1 2 3 Next »
Single sign-on like the big guys
Authenticate Anything
Configuration and User Creation
Now you'll need configurations for:
- A test authentication realm
- A
client
for the native application - A
client
for the application authenticated through a proxy - A user that will log in against both clients
It might sound counterintuitive, but in Keycloak-speak a client is an application that authenticates against Keycloak, so always remember that when a client is mentioned, it can refer also to a service or server and not just to front-end web apps.
Once you are logged in, mouse over the Master section in the upper left corner and click Add realm ; enter testrealm as a name and submit.
Next, go to the Clients section and click Add Client
, set the Client ID to native
, and set the Root URL to http://localhost:5000
before clicking Save
. Once the settings are saved, switch the Access Type
to confidential
and save again.
Now repeat the last (add client) procedure, but this time set the Client ID to proxy
and the Root URL to http://localhost:4180
. Additionally, click on the Mappers
tab and create a mapper called audience
, of Audience
type, and select proxy
as the included target audience.
Finally, go to the Users section, click Add User , and fill in the form with anything you like (Figure 1). Set both Enabled and Email Verified to ON , then click Save . Before leaving this section, click on the Credentials tab and set a password for your newly created user.
A Native Authentication App
Keycloak used to provide libraries for several languages called Adapters . Since February 2022 they have been discontinued because a robust availability of independent OAuth2 and OIDC libraries has been reached.
As an example, I'll set up a Python app that uses Flask and the Flask-OIDC module. You'll need Python 3.8 or later, PIP, and Python-venv. On Ubuntu or Arch Linux type,
apt install python3 python3-venv python3-pip pacman -S python python-pip
respectively. Now create a file named app.py
with the content of Listing 2 and another called oidc-config.json
with the content of Listing 3.
Listing 3
oidc-config.json
01 { 02 "web": { 03 "client_id": "native", 04 "client_secret": "hu5t82LXfYKtr3XFcPeAYaCBWFK8DcI1", 05 "auth_uri": "http://localhost:8080/realms/testrealm/protocol/openid-connect/auth", 06 "token_uri": "http://localhost:8080/realms/testrealm/protocol/openid-connect/token", 07 "issuer": "http://localhost:8080/realms/testrealm", 08 "userinfo_uri": "http://localhost:8080/realms/testrealm/protocol/openid-connect/userinfo", 09 "redirect_uris": [ 10 "http://localhost:5000/oidc/callback" 11 ] 12 } 13 }
Listing 2
app.py (Native)
01 # Import dependencies 02 from flask import Flask, g 03 from flask_oidc import OpenIDConnect 04 05 # Create a Flask app and set the OpenID connect config params 06 app = Flask(__name__) 07 app.secret_key = 'hu5t82LXfYKtr3XFcPeAYaCBWFK8DcI1' 08 app.config['OIDC_CLIENT_SECRETS'] = 'oidc-config.json' 09 app.config['OIDC_COOKIE_SECURE'] = False 10 11 # Instantiate a flask_oidc object that will be used to handle the authentication flow 12 oidc = OpenIDConnect(app) 13 14 # Function decorators to set the app route and the required login 15 @app.route('/') 16 @oidc.require_login 17 def index(): 18 # Check if user is authenticated 19 if oidc.user_loggedin: 20 # If user is authenticated, run this code 21 return 'Welcome %s' % oidc.user_getfield('preferred_username') 22 else: 23 # If he's not, run this code 24 return 'Not logged in'
Note that for the authentication flow to work, you must replace line 7 of Listing 2 and line 4 of Listing 3 with the client key found in the Credentials tab of the Keycloak native client created for this example.
To create the environment to run the application, enter
python -m venv .venv && source .venv/bin/activate pip install flask flask-oidc itsdangerous==2.0.1
and run the application with the flask run
command before heading to http://localhost:5000
.
If everything was done correctly, you should be redirected automatically to the Keycloak instance, where you are asked to authenticate. If the authentication is successful, you will be brought back to the sample application, where the username is printed (Figure 2).
As you may have guessed, the application will have access to a wide range of information on the authenticated user. Such information can be used to template your app or apply further conditions according to the user roles (authorization).
Authentication by Proxy
Sometimes you cannot customize the application for the described mechanism to be implemented, as could certainly be the case for proprietary applications or scenarios where messing with the code is simply not possible. In this case, you can use a reverse proxy that performs the authentication flow on behalf of the application it's serving, forwarding only requests from logged-in users (Figure 3).
One example is OAuth2 Proxy [3], a mature project that aims to provide a layer of authentication in front of an existing application. It doesn't necessarily features all the bells and whistles of more renowned solutions such as Nginx, but it can be used in conjunction with it and is natively cloud friendly, providing Docker images and Kubernetes operators.
To test OAuth2 Proxy, I'll first write a trivial web app (Listing 4) and, as before, run it with
flask run -p 9190
Listing 4
app.py (Proxied)
01 from flask import Flask, g 02 app = Flask(__name__) 03 @app.route('/') 04 def hello(): 05 return("Hello world")
The app is now freely accessible at http://localhost:9190 .
To add the authentication layer, you will need to create an OAuth2 Proxy config file (Listing 5) modifying the client_id
and client_secret
with the information from the Keycloak proxy
client created earlier. The reason for setting the audience
mapper is that OAuth2 Proxy expects said OIDC field valued with the same name of the configured client_id
.
Listing 5
oauth2proxy.cfg
# Ports to listen to http_address = ":4180" redirect_url = "http://localhost:4180/oauth2/callback" # The http url(s) of the upstream endpoint. upstreams = [ "http://localhost:9190" ] # Accept requests from all user email domains email_domains = "*" # Keycloak configuration oidc_issuer_url = "http://localhost:8080/realms/testrealm" provider = "keycloak-oidc" client_id = "proxy" client_secret = "t1BmFL4HHk7xC6nPYJEMfiprMfw1QK7b" # Cookie settings cookie_name = "_oauth2_proxy" cookie_secret = "4235342623623623"
Now spin up an instance of the service through a convenient Docker container:
docker run --network host -v $(pwd)/oauth2proxy.conf:/etc/oauth2-proxy.cfg bitnami/oauth2-proxy:7.2.1 --config=/etc/oauth2-proxy.cfg
Point your browser at http://localhost:4180 . If everything went according to the plan, you should be asked by OAuth2 Proxy to authenticate (Figure 4). After a successful procedure, you should be brought back to the trivial "Hello World" app.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)