In this article let’s look at how we can design a robust authentication framework that could cater for heterogeneous identity management requirements in an enterprise landscape. Authentication is just one but an important aspect of a wider security implementation and it is always advisable to consider the “big picture” of security when it comes to framework design and technology selection.
It is not the intension of this article to cover the fundamentals but what really is authentication? In simple terms it is the process of identifying your self to a service provider before receiving the service. Term authentication is often used in conjunction with the term authorisation which is concerned with agreeing which services the user has access to.
Authentication may be achieved in several different ways depending on the type of application and the context in which it is used.
There are number of protocols used for authentication such as Kerberos, SSL, Microsoft NTLM, PAP and SPAP, CHAP and MS-CHAP, EAP, RADIUS, Certificate services etc.
In designing modern applications an area of interest would be API authentication. In a service driven architecture, the client applications would obtain services through the service APIs and the services need some mechanism to build trust with the client. Some common approaches used are,
Enabling authentication is not that difficult given the technologies and the tools available, but designing for the needs of the enterprise is lot more complicated. It requires taking a broad view towards the stake holders requirements and building a robust and a scalable framework. Following are some key aspects that needs to be looked into during the design phase.
Authentication as a Service or AaaS is aimed at centralising the authentication logic and making it available as a service to other applications in the system landscape. AaaS should support standards such as OpenID Connect, SAML etc. and should provide the identity services typically through an API. This approach simplifies application development as the only requirement is to consume the authentication service.
In the heart of an AaaS model would be an authentication server providing an internal identity store as well as integration to 3rd party identity providers such as LDAP servers, social platforms etc.
In a typical authentication flow the application requiring authentication would redirect the user to a login page hosted by the auth server. Auth server would then validate the user credentials and issue an auth token which would then be passed on to the client application. However there can be alternative approaches where the client application uses the auth server API to validate credentials and obtain the auth token.
There are couple of important points to note with the AaaS model
There are couple of approaches that could be taken to enable AaaS for your application. Firstly you can consider developing the Auth server and the ecosystem from the scratch. For example, to enable OAuth capability you can use following libraries depending on the type of stack you are running. Whilst this approach may offer you flexibility you are likely to be reinventing the wheel to some extent given the range of off-the-shelf auth server implementations available. If you make the right choice you can benefit from the best practices the product would naturally bring. So my advice is to adopt an existing product unless your requirements are very different to the rest of the world.
During our research we looked number of solutions including Keycloak, CloudFoundry UAA, Keystone, Forgerock, Midpoint and Apache syncope. Some interesting comparison is available at https://compare.evolveum.com/features-table.html
Keycloak by far was our first choice as it seems to satisfy most number of requirements. It’s an open source product maintained under the stewardship of Red Hat. From an integration perspective, one of the biggest advantages of using Keycloak has been the availability of adaptors which does most of the heavy lifting when it comes to token validation, token refresh etc.
Keycloak integration allowed us to facilitate an identity store internal to the product and also offered the flexibility to federate identity from external stores such as LDAP servers. Keycloak comes with a built-in LDAP/AD plugin and could be extended to use other identity servers through the service provider interface (SPI).
If you are interested in getting your hands dirty with keycloak authentication, please continue. Let’s look at how we can configure keycloak authentication server with minimal settings and enable security in the applications. The application considered is a web application where the content is served through a Express.js web server and the java based backend is accessed through a REST API protected by spring security.
Note that keycloak documentation is comprehensive and the steps below would only be explaining the mandatory steps.
Installation and configuration
Linux/Unix$ unzip keycloak-4.1.0.Final.zipor$ tar -xvzf keycloak-4.1.0.Final.tar.gz
Windows> unzip keycloak-4.1.0.Final.zip
Linux/Unix$ …/bin/standalone.sh
Windows> …\bin\standalone.bat
Note the following important settings
Protecting the front-end
In-order to simplify integration with the auth server, there are adapters made available for various platforms. Full list of adaptors are available here
The front-end would be protected by the keycloak Node.js adapter.
{
"realm": "${env.KEYCLOAK_DEFAULT_REALM_REF}",
"auth-server-url": "${env.KEYCLOAK_SERVER_URL}",
"ssl-required": "external",
"resource": "my-frontend",
"public-client": true,
"confidential-port": 0
}
var Keycloak = require('keycloak-connect');
var memoryStore = new session.MemoryStore();
app.use(session({
secret: 'mySecret',
resave: false,
saveUninitialized: true,
store: memoryStore
}));
var keycloak = new Keycloak({
store: memoryStore
});
app.use(keycloak.middleware({
logout: '/signout',
admin: '/adm'
}));
app.get(‘/profile’, keycloak.protect(), myRenderFunctionHere());
Protecting the backend
It is assumed that application backend is protected by spring security. Keycloak spring security adapter enables keycloak authentication for the java backend.
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>${keycloak.version}</version>
</dependency>
{
"realm": "${env.KEYCLOAK_DEFAULT_REALM_REF}",
"bearer-only": true,
"auth-server-url": "${env.KEYCLOAK_SERVER_URL}",
"ssl-required": "external",
"resource": "my-backend",
"confidential-port": 0
}
keycloak.auth-server-url=${KEYCLOAK_SERVER_URL}
keycloak.realm=${KEYCLOAK_DEFAULT_REALM_REF}
keycloak.resource=my-backend
keycloak.realmKey = ${KEYCLOAK_REALM_KEY}
keycloak.bearer-only = true
keycloak.credentials.secret = ${KEYCLOAK_CLIENT_SECRET}
keycloak.ssl-required = external
keycloak.cors = true
public class CustomKeycloakAuthenticationProvider extends KeycloakAuthenticationProvider {@Autowired
UserService userService;@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken)authentication;
CustomKeycloakAuthenticationToken customToken = new CustomKeycloakAuthenticationToken(token.getAccount(), token.isInteractive(),null);
KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) token.getPrincipal();
KeycloakSecurityContext securityContext = keycloakPrincipal.getKeycloakSecurityContext();
AccessToken accessToken = securityContext.getToken();
User user = userService.findByUserName(accessToken.getPreferredUsername());
customToken.setSubject(user);
return customToken;
}
public class CustomKeycloakAuthenticationToken extends KeycloakAuthenticationToken {private User subject;public CustomKeycloakAuthenticationToken(KeycloakAccount account, boolean interactive, Collection<? extends GrantedAuthority> authorities) {
super(account,interactive,authorities);}public User getSubject() {
return subject;
}public void setSubject(User subject) {
this.subject = subject;
}
}
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="customkeycloakAuthenticationProvider" />
</sec:authentication-manager><bean id="customkeycloakAuthenticationProvider" class="[FQN of the auth provider class]" /><bean id="keycloakAuthenticationProcessingFilter" class="org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter">
<constructor-arg name="authenticationManager" ref="authenticationManager" />
</bean>
Thats it really. You have now setup an auth server and connected you application to be authenticated by keycloak.
As stated before the key to a successful authentication framework depends a lot on the design. You should invest your time wisely to understand the big picture, define scope and select the right technology. There is rarely a “one size fits all” solution