session timeout improvements

This commit is contained in:
Bill Burke 2013-08-08 09:53:18 -04:00
parent 095b4c62fb
commit 3480cb5646
7 changed files with 73 additions and 92 deletions

View file

@ -1,8 +1,8 @@
{
"realm" : "demo",
"enabled" : true,
"tokenLifespan" : 6000,
"accessCodeLifespan" : 30,
"tokenLifespan" : 10,
"accessCodeLifespan" : 10,
"sslNotRequired" : true,
"cookieLoginAllowed" : true,
"privateKey" : "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",

View file

@ -22,7 +22,6 @@
<script src="lib/angular/angular-resource.js"></script>
<script src="lib/angular/ui-bootstrap-tpls-0.4.0.js"></script>
<script src="/auth-server/rest/saas/isLoggedIn.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/loaders.js"></script>
@ -63,13 +62,14 @@
<script src="lib/jquery/jquery.idletimeout.js" type="text/javascript"></script>
<script type="text/javascript">
$.idleTimeout('#idletimeout', '#idletimeout a', {
idleAfter: 5,
pollingInterval: 0,
keepAliveURL: '',
idleAfter: 300,
pollingInterval: 60,
keepAliveURL: '/auth-server/rest/saas/keepalive',
serverResponseEquals: '',
failedRequests: 1,
onTimeout: function(){
$(this).slideUp();
window.location = "timeout.html";
window.location = "/auth-server/rest/saas/logout";
},
onIdle: function(){
$(this).slideDown(); // show the warning bar
@ -84,35 +84,4 @@
</script>
</body>
<!--
<body data-ng-controller="GlobalCtrl">
<div id="idletimeout">
You will be logged off in <span></span>&nbsp;seconds due to inactivity.
<a id="idletimeout-resume" href="#">Click here to continue using this web page</a>.
</div>
<div class="alert-container" data-ng-show="notification" data-ng-click="notification = null">
<div class="alert alert-{{notification.type}}">{{notification.message}}</div>
</div>
<div id="wrap">
<div data-ng-include data-src="'partials/menu.html'"></div>
<div data-ng-view id="view" data-ng-hide="httpProviderError"></div>
<div id="httpProviderError" data-ng-show="httpProviderError">
<button class="btn btn-danger" data-ng-click="httpProviderError=null">
<strong>Error</strong> {{httpProviderError}}
</button>
</div>
<div id="loading">
<i class="icon-spinner icon-spin"></i> Loading...
</div>
</div>
</body>
-->
</html>

View file

@ -160,13 +160,19 @@ module.config(function($httpProvider) {
});
module.factory('errorInterceptor', function($q, $window, $rootScope, $location) {
module.factory('errorInterceptor', function($q, $window, $rootScope, $location, Auth) {
return function(promise) {
return promise.then(function(response) {
$rootScope.httpProviderError = null;
return response;
}, function(response) {
if (response.status == 401) {
console.log('session timeout?');
Auth.loggedIn = false;
$location.url('/');
} else {
$rootScope.httpProviderError = response.status;
}
return $q.reject(response);
});
};
@ -191,6 +197,7 @@ module.factory('spinnerInterceptor', function($q, $window, $rootScope, $location
};
});
/*
module.directive('kcInput', function() {
var d = {
scope : true,
@ -235,6 +242,7 @@ module.directive('kcEnter', function() {
});
};
});
*/
module.filter('remove', function() {
return function(input, remove, attribute) {

View file

@ -11,6 +11,13 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
};
$scope.auth = Auth;
$http.get('/auth-server/rest/saas/whoami').success(function(data, status) {
Auth.user = data;
Auth.loggedIn = true;
})
.error(function(data, status) {
Auth.loggedIn = false;
});
$scope.$watch(function() {
return $location.path();
@ -34,11 +41,11 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
}
if (showrealm) {
console.log('redirecting');
console.log('default redirect to realm: ' + id);
Current.realm = Current.realms[id];
$location.url("/realms/" + id);
} else {
console.log('not redirecting');
//console.log('not redirecting');
}
});
});

View file

@ -2,32 +2,14 @@
var module = angular.module('keycloak.services', [ 'ngResource' ]);
module.service('Auth', function($resource, $http, $location, $routeParams) {
module.service('Auth', function() {
var auth = {
loggedIn : keycloakCookieLoggedIn
loggedIn : false
};
auth.user = {
userId : null,
displayName : null
};
auth.logout = function() {
auth.user = {
userId : null,
displayName : null
};
auth.loggedIn = false;
$http.get('/auth-server/rest/saas/logout-cookie');
};
if (!auth.loggedIn) {
return auth;
}
$http.get('/auth-server/rest/saas/whoami').success(function(data, status) {
auth.user = data;
//alert(data.userId);
})
.error(function(data, status) {
alert("Failed!");
});
return auth;
});

View file

@ -82,9 +82,11 @@
_startTimer: function(){
var self = this;
if (this.options.pollingInterval > 0) {
this.timer = win.setTimeout(function () {
self._keepAlive();
}, this.options.pollingInterval * 1000);
}
},
_stopTimer: function(){
@ -103,6 +105,7 @@
// if too many requests failed, abort
if( !this.failedRequests ){
console.log('aborting...');
this._stopTimer();
options.onAbort.call( this.warning[0] );
return;
@ -112,12 +115,14 @@
timeout: options.AJAXTimeout,
url: options.keepAliveURL,
error: function(){
console.log('failure for keepalive');
self.failedRequests--;
},
success: function(response){
if($.trim(response) !== options.serverResponseEquals){
console.log('success for keepalive');
/* if($.trim(response) !== options.serverResponseEquals){
self.failedRequests--;
}
}*/
},
complete: function(){
if( recurse ){

View file

@ -1,5 +1,6 @@
package org.keycloak.services.resources;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
@ -11,27 +12,12 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.admin.RealmsAdminResource;
import javax.ws.rs.Consumes;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.net.URI;
/**
@ -87,22 +73,42 @@ public class SaasService {
}
}
@Path("whoami")
@Path("keepalive")
@GET
@Produces("application/json")
public Response whoAmI(final @Context HttpHeaders headers) {
@NoCache
public Response keepalive(final @Context HttpHeaders headers) {
logger.info("keepalive");
return new Transaction() {
@Override
public Response callImpl() {
logger.info("WHOAMI start.");
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
if (realm == null) throw new NotFoundException();
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
if (user == null) {
return Response.status(404).build();
return Response.status(401).build();
}
NewCookie refreshCookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
return Response.noContent().cookie(refreshCookie).build();
}
}.call();
}
@Path("whoami")
@GET
@Produces("application/json")
@NoCache
public Response whoAmI(final @Context HttpHeaders headers) {
return new Transaction() {
@Override
public Response callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
if (realm == null) throw new NotFoundException();
UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
if (user == null) {
return Response.status(401).build();
}
logger.info("WHOAMI: " + user.getLoginName());
return Response.ok(new WhoAmI(user.getLoginName(), user.getLoginName())).build();
}
}.call();
@ -111,6 +117,7 @@ public class SaasService {
@Path("isLoggedIn.js")
@GET
@Produces("application/javascript")
@NoCache
public String isLoggedIn(final @Context HttpHeaders headers) {
return new Transaction() {
@Override
@ -165,6 +172,7 @@ public class SaasService {
@Path("loginPage.html")
@GET
@NoCache
public void loginPage() {
new Transaction() {
@Override
@ -179,6 +187,7 @@ public class SaasService {
@Path("logout")
@GET
@NoCache
public void logout() {
new Transaction() {
@Override
@ -194,6 +203,7 @@ public class SaasService {
@Path("logout-cookie")
@GET
@NoCache
public void logoutCookie() {
logger.info("*** logoutCookie");
new Transaction() {
@ -205,6 +215,7 @@ public class SaasService {
}
public final static String loginFormPath = "/sdk/login.xhtml";
protected void forwardToLoginForm(RealmModel realm) {
request.setAttribute(RealmModel.class.getName(), realm);
URI action = uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processLogin").build();
@ -216,7 +227,6 @@ public class SaasService {
}
@Path("login")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)