Integrating Java CAS Server with Django Microservices

django microservices

Now a days Microservices are very popular and our industry tend to move to distributed architecture. I got an opportunity to implement CAS for Django microservices. I tried to find some descriptive tutorials on the subject, but didn’t find anything except for the official documentation. I just wanted to make other devs’ lives a little bit easier through this article.

The Central Authentication Service (CAS)

Before we dive into the main subject, lets discuss briefly what is CAS and How it works. The Central Authentication Service (CAS) is a single sign-on protocol for the web application that permits a user to access multiple applications by providing their credentials (such as username and password) only once.

How CAS protocol works

CAS contains two parts. They are the server part and the client part. Lets understand the process of the protocol with a simple real scenario. Say, your are going to a live concert of your favorite music crew.So, your application you want the users to authenticate to using the CAS protocol is the concert itself. There are ticket-agents that sell and validate tickets to the concert. The ticket-agent is the CAS server that gives the users permissions to access your application and validates their access credentials. And of course, people that go to the concert are CAS clients that get tickets and go to the concert.

  • The CAS server is responsible for authenticating users and granting accesses to applications.
  • The CAS clients protect the CAS applications and retrieve the identity of the granted users from the CAS server.
  • The TGT (Ticket Granting Ticket), stored in the CASTGC cookie, represents a SSO session for a user.
  • The ST (Service Ticket), transmitted as a GET parameter in urls, stands for the access granted by the CAS server to the CASified application for a specific user.

Prerequisites

In this tutorial, I will be using Django framework for microservices. To get to know about Django best practices please refer my previous article. And then I will use django-cas-ng packages. django-cas-ng is a CAS client authentication backend for Django. It is developed from the base of django-cas (which has not been updated since April 2013). ng stands for ‘Next Generation’. django-cas-ng supports :

  • Django 2.x and 3.x
  • Python 3.5+.

Installation

Install with pip

pip install django-cas-ng

Configuration

To integrate django-cas-ng with our django project, we need to configure some settings and add URL patterns. Lets go through one by one.

Add django-cas-ng as middleware, add authentication backends and installed apps in your settings. Make sure you also have the authentication middleware installed. Here’s an example:

  • Add django_cas_ng to INSTALLED_APPS:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_cas_ng',
)
  • Add django_cas_ng.middleware.CASMiddleware to MIDDLEWARE:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_cas_ng.middleware.CASMiddleware'
]
  • Add django_cas_ng.backends.CASBackend to AUTHENTICATION_BACKENDS:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'django_cas_ng.backends.CASBackend',
)

There are some more settings should be included inside settings.py file. Among them CAS_SERVER_UR is a mandatory configuration and others are not. Let’s concentrate only mandatory configuration here. Other configurations and their respective elaborations can be found here.

Make sure your project knows how to login and logout by adding these to your URL mappings.

# Django 2.0+
from django.urls import path
import django_cas_ng.views

urlpatterns = [
path('', views.index, name='index'),
path('admin/', admin.site.urls),
path('accounts/login', django_cas_ng.views.LoginView.as_view(), name='cas_ng_login'),
path('accounts/logout', django_cas_ng.views.LogoutView.as_view(), name='cas_ng_logout'),
]
# Django < 2.0
from django.conf.urls import url
import django_cas_ng.views

urlpatterns = [
url(r'^accounts/login$', django_cas_ng.views.LoginView.as_view(), name='cas_ng_login'),
url(r'^accounts/logout$', django_cas_ng.views.LogoutView.as_view(), name='cas_ng_logout'),
]

Create a new file named testsite/views.py and implement index method.

The app view will check user is authenticated by using request.user.is_authenticated. If it is authenticated, it will get logged user name from request.user.username

from django.http import HttpResponse


def index(request):
if request.user.is_authenticated:
return HttpResponse('<p>Welcome to <a href="https://djangocas.dev">django-cas-ng</a>.</p><p>You logged in as <strong>%s</strong>.</p><p><a href="/accounts/logout">Logout</a></p>' % request.user)
else:
return HttpResponse('<p>Welcome to <a href="https://djangocas.dev">django-cas-ng</a>.</p><p><a href="/accounts/login">Login</a></p>')

Database

Run ./manage.py syncdb (or ./manage.py migrate for Django 1.7+) to create Single Sign On and Proxy Granting Ticket tables.

On update you can just delete the django_cas_ng_sessionticket table and the django_cas_ng_proxygrantingticket before calling ./manage.py syncdb.

Finally : Run Test Server

Start your application using following command.

python manage.py runserver

By default your application will start on port number 8000. Then visit localhost:8000 to see it in action. If you go to localhost:8000/accounts/login , you should now see the login page for your chosen CAS server.

If you want to run your application on a specific host and port :

python manage.py runserver <hostname>:<port>

Enforcing Authentication

You often want to enforce that a user is authenticated before they may access a certain view. django_cas_ng offers a login_required function decorator for that very purpose.

For example, if you are using the sample application, you could protect the index page (testsite/views.py)by simply adding login_required decorator at the beginning of the function.

from django.http import HttpResponse

@login_required
def index(request):
if request.user.is_authenticated:
return HttpResponse('<p>Welcome to <a href="https://djangocas.dev">django-cas-ng</a>.</p><p>You logged in as <strong>%s</strong>.</p><p><a href="/accounts/logout">Logout</a></p>' % request.user)
else:
return HttpResponse('<p>Welcome to <a href="https://djangocas.dev">django-cas-ng</a>.</p><p><a href="/accounts/login">Login</a></p>')

Now when you visit the index page, you should be redirected to the login page first if you are not already authenticated.

And that’s it! Your app is now protected by CAS.

Happy Coding :)

Software Engineer @ hSenid Mobile | Former Software Engineering Intern @ WSO2 | Software Engineering Undergraduate @ IIT