[thumbnail target=”_self” src=”https://sumglobal.com/wp-content/uploads/2016/05/AngularKeycloakWildfly.png”]
In previous posts, we have:
- Used vagrant to create a development environment
- Secured REST services with Keycloak
You can find the code on our GitHub site: https://github.com/sumglobal
Now let’s use Keycloak and AngularJS to create a secure web application
Once the REST services are secured, we will use Keycloak’s javascript adapter to secure the web application.
Configure a client through the keycloak admin console.
[thumbnail target=”_blank” src=”https://sumglobal.com/wp-content/uploads/2016/05/Keycloak_Admin_Console-1024×501.png”]
When configuring the client, we will select public for the Access Type field. Since we can’t use a client secret, you will also need to specify valid redirect uris. Once configured, click on the Installation tab and create a keycloak.json file that will be used to configure the client. If you’ve followed the previous posts, this will already be setup for you.
The keycloak.json file will look something like:
|
1 2 3 4 5 6 7 8 |
{ realm: "serenity", realm-public-key: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXk...", auth-server-url: "https://172.16.0.100/auth", ssl-required: "external", resource: "serenity-web", public-client: true } |
Next, we need to initialize the adapter inside our web application code like:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
(function() { 'use strict'; angular.element(document).ready(function () { var keycloakAuth = new Keycloak('keycloak.json'); keycloakAuth.init({ onLoad: 'check-sso' }).success(function () { angular .module('cortex') .factory('Auth', function() { return keycloakAuth; }); angular.bootstrap(document, ["cortex"]); }).error(function () { window.location.reload(); }); }); angular .module('cortex') .run(['$rootScope', '$location', 'Auth', runBlock]); /** @ngInject */ function runBlock($rootScope, $location, Auth) { $rootScope.$on( "event:auth-loginRequired", function() { Auth.login(); }); } })(); |
notice that we are passing check-sso to the init function. This will redirect to the auth server to check to see if the user is already logged in.
After logging in, our application will be able to make REST calls using bearer token authentication. In our angular application, we use interceptors to inject the bearer token into the headers as such:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
function authInterceptor($q, Auth) { return { request: function (config) { if (Auth.token) { var deferred = $q.defer(); Auth.updateToken(30).success(function() { config.headers = config.headers || {}; config.headers.Authorization = 'Bearer ' + Auth.token; deferred.resolve(config); }).error(function() { location.reload(); }); return deferred.promise; } else { return config; } } }; } function errorInterceptor($rootScope, $q) { return { responseError: function(response) { if (!response.config.ignoreAuthModule) { switch (response.status) { case 0: // cors issue case 401: var deferred = $q.defer(); $rootScope.$broadcast('event:auth-loginRequired', response); return deferred.promise; case 403: $rootScope.$broadcast('event:auth-forbidden', response); break; } } return $q.reject(response); } }; } |
The authInterceptor method takes an HTTP request and adds a bearer token to the Authorization header after verifying and updating the token. The errorInterceptor method takes an HTTP response to check for error codes. If an HTTP 401 is returned, a loginRequired event is broadcast. If an HTTP 403 is returned, an auth-forbidden event is broadcast meaning the user does not have sufficient privileges to access the service.
After starting the application, you should get a screen similar to:
[thumbnail target=”_blank” src=”https://sumglobal.com/wp-content/uploads/2016/05/hogwarts-1024×303.png”]
Clicking the User or Cargo links will redirect the application to the keycloak login page as such:
[thumbnail target=”_blank” src=”https://sumglobal.com/wp-content/uploads/2016/05/Log_in_to_serenity-1024×536.png”]
Once logged in, selecting the all seeing eye in the bottom right corner will display the current token value
[thumbnail target=”_blank” src=”https://sumglobal.com/wp-content/uploads/2016/05/hogwarts-1-1024×815.png”]
Wrapping Up
There you have it, in the last three posts we have:
- Created a reusable development environment using Vagrant and Ansible
- Used Ansible to download and install
- Wildfly
- Keycloak
- OpenLdap
- MySql
- Nginx
- Used Ansible to
- Load OpenLdap data into the server
- Load schema and test data into MySql
- Tuned and loaded database drivers for Wildfly
- Setup a working realm for Keycloak
- Setup SSL and proxying with Nginx
- Used Angular, Node, Npm, Bower and Gulp to create a test web application
Using these tools, we have been able to create reusable, scriptable and stable development environments that can be shared and used as a platform for development on multiple operating systems.






> case 0: // cors issue
Yes, how to solve that CORS issue?
This hack / workaround in the client is not a real solution.
Caused by WildFly not activating filters (that add cors headers) for ‘errors’, such as 401. http://stackoverflow.com/questions/31806351/servlet-response-filter-for-non-2xx-http-code
But how to solve?