Skip to content

Commit

Permalink
Support for links to Keycloak admin console and account management (i…
Browse files Browse the repository at this point in the history
…f KC integration enabled)
  • Loading branch information
mposolda committed Feb 2, 2015
1 parent 78c8970 commit e2e8cb9
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 8 deletions.
Expand Up @@ -12,6 +12,7 @@
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import io.hawt.system.ConfigManager;
import io.hawt.util.IOHelper;
Expand All @@ -22,6 +23,7 @@
* Servlet, which aims to return:
* - whether keycloak is enabled (true/false) if path '/enabled' is used
* - keycloak.json to be used by keycloak JS adapter on frontend if path '/client-config' is used
* - validate if current JAAS logged subject is same like SSO user logged through keycloak if path '/validate-subject-matches' is used
*
*/
public class KeycloakServlet extends HttpServlet {
Expand Down Expand Up @@ -137,6 +139,31 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
} else {
renderJSONResponse(response, keycloakConfig);
}
} else if ("/validate-subject-matches".equals(pathInfo)) {
String keycloakUser = request.getParameter("keycloakUser");
if (keycloakUser == null || keycloakUser.length() == 0) {
LOG.warn("Parameter 'keycloakUser' not found");
}
boolean valid = validateKeycloakUser(request, keycloakUser);
renderJSONResponse(response, String.valueOf(valid));
}
}

protected boolean validateKeycloakUser(HttpServletRequest request, String keycloakUser) {
HttpSession session = request.getSession(false);

// No session available. No existing subject logged
if (session == null) {
return true;
}

String username = (String) session.getAttribute("user");
if (username != null && !username.equals(keycloakUser)) {
LOG.debug("Non matching username found. JAAS username: " + username + ", keycloakUsername: " + keycloakUser + ". Invalidating session");
session.invalidate();
return false;
} else {
return true;
}
}

Expand Down
14 changes: 13 additions & 1 deletion hawtio-web/src/main/webapp/app/core/js/app.ts
Expand Up @@ -78,7 +78,7 @@ module Core {
* @param {*} jolokiaUrl
* @param {*} branding
*/
export var AppController = _module.controller("Core.AppController", ["$scope", "$location", "workspace", "jolokia", "jolokiaStatus", "$document", "pageTitle", "localStorage", "userDetails", "lastLocation", "jolokiaUrl", "branding", "ConnectOptions", "$timeout", "locationChangeStartTasks", "$route", ($scope, $location:ng.ILocationService, workspace, jolokia, jolokiaStatus, $document, pageTitle:Core.PageTitle, localStorage, userDetails, lastLocation:{ url:string }, jolokiaUrl, branding, ConnectOptions:Core.ConnectOptions, $timeout:ng.ITimeoutService, locationChangeStartTasks:Core.ParameterizedTasks, $route:ng.route.IRouteService) => {
export var AppController = _module.controller("Core.AppController", ["$scope", "$location", "$window", "workspace", "jolokia", "jolokiaStatus", "$document", "pageTitle", "localStorage", "userDetails", "lastLocation", "jolokiaUrl", "branding", "ConnectOptions", "$timeout", "locationChangeStartTasks", "$route", "keycloakContext", ($scope, $location:ng.ILocationService, $window:ng.IWindowService, workspace, jolokia, jolokiaStatus, $document, pageTitle:Core.PageTitle, localStorage, userDetails, lastLocation:{ url:string }, jolokiaUrl, branding, ConnectOptions:Core.ConnectOptions, $timeout:ng.ITimeoutService, locationChangeStartTasks:Core.ParameterizedTasks, $route:ng.route.IRouteService, keycloakContext:Core.KeycloakContext) => {

$scope.collapse = '';
$scope.match = null;
Expand All @@ -90,6 +90,7 @@ module Core {
$scope.connectFailure = {};

$scope.showPrefs = false;
$scope.keycloakEnabled = keycloakContext.enabled;

$scope.logoClass = () => {
if (branding.logoOnly) {
Expand Down Expand Up @@ -289,6 +290,17 @@ module Core {
function defaultPage() {
return Perspective.defaultPage($location, workspace, jolokia, localStorage);
}

$scope.redirectToKeycloakAccountMgmt = () => {
keycloakContext.keycloak.accountManagement();
};

$scope.redirectToKeycloakAdminConsole = () => {
var realm: string = encodeURIComponent(keycloakContext.keycloak.realm);
var redirectURI: string = keycloakContext.keycloak.authServerUrl + '/admin/' + realm + '/console/index.html';
$window.location.href = redirectURI;
};

}]);

}
38 changes: 33 additions & 5 deletions hawtio-web/src/main/webapp/app/core/js/keycloakLogin.ts
Expand Up @@ -6,7 +6,7 @@ module Core {

var log = Logger.get('Keycloak');

// log.setLevel(Logger.DEBUG);
log.setLevel(Logger.DEBUG);

var checkKeycloakEnabled = function(callback: Function) {
var keycloakEnabledUrl: string = "keycloak/enabled";
Expand All @@ -15,7 +15,7 @@ module Core {
$.ajax(keycloakEnabledUrl, <JQueryAjaxSettings> {
type: "GET",
success: function (response) {
log.debug("Got user response for check if keycloak is enabled: ", response);
log.debug("Got response for check if keycloak is enabled: ", response);
var keycloakEnabled: boolean = response;

var keycloakContext: KeycloakContext = createKeycloakContext(keycloakEnabled);
Expand Down Expand Up @@ -50,6 +50,7 @@ module Core {
return keycloakContext;
};


var initKeycloakIfNeeded = function(keycloakContext: KeycloakContext, nextTask: Function) {
if (keycloakContext.enabled) {
log.debug('Keycloak authentication required. Initializing Keycloak');
Expand All @@ -64,9 +65,14 @@ module Core {
}

keycloak.init(kcInitOptions).success(function () {
log.debug("Keycloak authentication finished! Continue next task");
// Continue next registered task and bootstrap Angular
nextTask();
var keycloakUsername: string = keycloak.tokenParsed.preferred_username;
log.debug("Keycloak authenticated with Subject " + keycloakUsername + ". Validating subject matches");

validateSubjectMatches(keycloakUsername, function() {
log.debug("Keycloak authentication finished! Continue next task");
// Continue next registered task and bootstrap Angular
nextTask();
});
}).error(function () {
log.warn("Keycloak authentication failed!");
notification('error', 'Failed to log in to Keycloak');
Expand All @@ -78,6 +84,28 @@ module Core {
}
};


/**
* Validate if subject authenticated through Keycloak matches with SSO
*/
var validateSubjectMatches = function(keycloakUser: string, callback: Function) {
var keycloakValidateUrl: string = "keycloak/validate-subject-matches?keycloakUser=" + encodeURIComponent(keycloakUser);

// Send ajax request to KeycloakServlet to figure out if keycloak integration is enabled
$.ajax(keycloakValidateUrl, <JQueryAjaxSettings> {
type: "GET",
success: function (response) {
log.debug("Got response for validate subject matches: ", response);
callback();
},
error: function (xhr, textStatus, error) {
// Just fallback to false if we couldn't figure userDetails
log.debug("Failed to validate subject matches: ", error);
callback();
}
});
}

/**
* Prebootstrap task, which handles Keycloak OAuth flow. It will first check if keycloak is enabled and then possibly init keycloak.
* It will continue with Angular bootstrap just when Keycloak authentication is successfully finished
Expand Down
12 changes: 12 additions & 0 deletions hawtio-web/src/main/webapp/index.html
Expand Up @@ -187,6 +187,18 @@
</a>
</li>

<li ng-show="keycloakEnabled">
<a href="" title="Manage my account" data-placement="bottom" ng-click="redirectToKeycloakAccountMgmt()">
<i class="fixme"></i> Manage my account
</a>
</li>

<li ng-show="keycloakEnabled">
<a href="" title="Keycloak admin console" data-placement="bottom" ng-click="redirectToKeycloakAdminConsole()">
<i class="fixme"></i> Keycloak admin console
</a>
</li>

</ul>
</li>

Expand Down
2 changes: 1 addition & 1 deletion sample-keycloak-integration/README.md
Expand Up @@ -74,7 +74,7 @@ features:uninstall hawtio-core
features:removeurl mvn:io.hawt/hawtio-karaf/1.2-redhat-379/xml/features
```

* Install new hawtio with keycloak integration (Replace with the correct version where is Keycloak integration available. It should be 1.4.47 or 1.5-redhat-048 or newer)
* Install new hawtio with keycloak integration (Replace with the correct version where is Keycloak integration available. It should be 1.4.47 or newer)

```
features:chooseurl hawtio 1.4.47
Expand Down
13 changes: 12 additions & 1 deletion sample-keycloak-integration/demorealm.json
Expand Up @@ -40,6 +40,9 @@
"users" : [
{
"username" : "john",
"firstName" : "John",
"lastName" : "Anthony",
"email" : "john@hawt.io",
"enabled" : true,
"credentials" : [
{
Expand All @@ -54,6 +57,9 @@
},
{
"username" : "mary",
"firstName" : "Mary",
"lastName" : "Kelly",
"email" : "mary@hawt.io",
"enabled" : true,
"credentials" : [
{
Expand All @@ -67,6 +73,9 @@
},
{
"username" : "root",
"firstName" : "Root",
"lastName" : "Root",
"email" : "root@hawt.io",
"enabled" : true,
"credentials" : [
{
Expand All @@ -76,14 +85,16 @@
],
"realmRoles" : [ "jmxAdmin" ],
"applicationRoles": {
"account" : [ "view-profile", "manage-account" ]
"account" : [ "view-profile", "manage-account" ],
"realm-management" : [ "realm-admin" ]
}
}
],
"applications" : [
{
"name" : "hawtio-client",
"surrogateAuthRequired" : false,
"fullScopeAllowed" : false,
"enabled" : true,
"redirectUris" : [ "http://localhost:8080/hawtio/*", "http://localhost:8181/hawtio/*", "http://localhost:8081/hawtio/*" ],
"webOrigins" : [ "http://localhost:8080", "http://localhost:8181", "http://localhost:8081" ],
Expand Down

0 comments on commit e2e8cb9

Please sign in to comment.