Skip to content

Commit

Permalink
Merge pull request #923 from liggitt/delete_token_on_logout
Browse files Browse the repository at this point in the history
Merged by openshift-bot
  • Loading branch information
OpenShift Bot committed Feb 5, 2015
2 parents a316d5f + 4a0470f commit dc262d1
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 65 deletions.
1 change: 1 addition & 0 deletions assets/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<script src="scripts/services/auth.js"></script>
<script src="scripts/services/data.js"></script>
<script src="scripts/services/login.js"></script>
<script src="scripts/services/logout.js"></script>
<script src="scripts/services/labelFilter.js"></script>
<script src="scripts/controllers/projects.js"></script>
<script src="scripts/controllers/project.js"></script>
Expand Down
1 change: 1 addition & 0 deletions assets/app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ angular
$httpProvider.interceptors.push('AuthInterceptor');

AuthServiceProvider.LoginService('RedirectLoginService');
AuthServiceProvider.LogoutService('DeleteTokenLogoutService');
// TODO: fall back to cookie store when localStorage is unavailable (see known issues at http://caniuse.com/#feat=namevalue-storage)
AuthServiceProvider.UserStore('LocalStorageUserStore');

Expand Down
30 changes: 22 additions & 8 deletions assets/app/scripts/controllers/util/logout.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,27 @@
* Controller of the openshiftConsole
*/
angular.module('openshiftConsole')
.controller('LogoutController', function ($rootScope, $scope, AuthService) {
// If clearing the user results in a change from authenticated to unauthenticated, force the page in response
AuthService.onUserChanged(function(){
console.log("LogoutController - user changed, reloading the page");
window.location.reload(false);
});
.controller('LogoutController', function ($scope, $log, AuthService) {
$log.debug("LogoutController");

// TODO: actually run the logout flow, delete the token, etc
AuthService.setUser(null, null);
if (AuthService.isLoggedIn()) {
$log.debug("LogoutController, logged in, initiating logout");
$scope.logoutMessage = "Logging out...";

AuthService.startLogout().finally(function(){
// Make sure the logout completed
if (AuthService.isLoggedIn()) {
$log.debug("LogoutController, logout failed, still logged in");
$scope.logoutMessage = 'You could not be logged out. Return to the <a href="/">console</a>.';
} else {
// TODO: redirect to configurable logout destination
$log.debug("LogoutController, logout completed, reloading the page");
window.location.reload(false);
}
});
} else {
// TODO: redirect to configurable logout destination
$log.debug("LogoutController, not logged in, logout complete");
$scope.logoutMessage = 'You are logged out. Return to the <a href="/">console</a>.';
}
});
78 changes: 60 additions & 18 deletions assets/app/scripts/services/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,45 @@ angular.module('openshiftConsole')
}
return _loginService;
};
var _logoutService = "";
this.LogoutService = function(logoutServiceName) {
if (logoutServiceName) {
_logoutService = logoutServiceName;
}
return _logoutService;
};

this.$get = function($q, $injector, $rootScope) {
var loadService = function(injector, name, setter) {
if (!name) {
throw setter + " not set";
} else if (angular.isString(name)) {
return injector.get(name);
} else {
return injector.invoke(name);
}
};

this.$get = function($q, $injector, $log, $rootScope) {
if (debug) { console.log('AuthServiceProvider.$get', arguments); }

var _loginCallbacks = $.Callbacks();
var _logoutCallbacks = $.Callbacks();
var _userChangedCallbacks = $.Callbacks();

var _loginPromise = null;
var _logoutPromise = null;

var userStore;
if (!_userStore) {
throw "AuthServiceProvider.UserStore() not set";
} else if (angular.isString(_userStore)) {
userStore = $injector.get(_userStore);
} else {
userStore = $injector.invoke(_userStore);
}

var loginService;
if (!_loginService) {
throw "AuthServiceProvider.LoginService() not set";
} else if (angular.isString(_loginService)) {
loginService = $injector.get(_loginService);
} else {
loginService = $injector.invoke(_loginService);
}
var userStore = loadService($injector, _userStore, "AuthServiceProvider.UserStore()");
var loginService = loadService($injector, _loginService, "AuthServiceProvider.LoginService()");
var logoutService = loadService($injector, _logoutService, "AuthServiceProvider.LogoutService()");

return {
// Returns true if currently logged in.
isLoggedIn: function() {
return !!userStore.getUser();
},

// Returns a promise of a user, which is resolved with a logged in user. Triggers a login if needed.
withUser: function() {
var user = userStore.getUser();
if (user) {
Expand Down Expand Up @@ -144,11 +155,42 @@ angular.module('openshiftConsole')
});
return _loginPromise;
},

startLogout: function() {
if (_logoutPromise) {
if (debug) { console.log("Logout already in progress"); }
return _logoutPromise;
}
var self = this;
var user = userStore.getUser();
var token = userStore.getToken();
var wasLoggedIn = this.isLoggedIn();
_logoutPromise = logoutService.logout(user, token).then(function() {
if (debug) { console.log("Logout service success"); }
}).catch(function(err) {
if (debug) { console.log("Logout service error", err); }
}).finally(function() {
// Clear the user and token
self.setUser(null, null);
// Make sure isLoggedIn() returns false before we fire logout callbacks
var isLoggedIn = self.isLoggedIn();
// Only fire logout callbacks if we transitioned from a logged in state to a logged out state
if (wasLoggedIn && !isLoggedIn) {
_logoutCallbacks.fire();
}
_logoutPromise = null;
});
return _logoutPromise;
},

// TODO: add a way to unregister once we start doing in-page logins
onLogin: function(callback) {
_loginCallbacks.add(callback);
},
// TODO: add a way to unregister once we start doing in-page logouts
onLogout: function(callback) {
_logoutCallbacks.add(callback);
},
// TODO: add a way to unregister once we start doing in-page user changes
onUserChanged: function(callback) {
_userChangedCallbacks.add(callback);
Expand Down
66 changes: 58 additions & 8 deletions assets/app/scripts/services/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,54 @@ angular.module('openshiftConsole')
}
};

// type: API type (e.g. "pods")
// name: API name, the unique name for the object
// context: API context (e.g. {project: "..."})
// opts: http - options to pass to the inner $http call
// Returns a promise resolved with response data or rejected with {data:..., status:..., headers:..., config:...} when the delete call completes.
DataService.prototype.delete = function(type, name, context, opts) {
opts = opts || {};
var deferred = $q.defer();
if (context.projectPromise && type !== "projects") {
var self = this;
context.projectPromise.done(function(project) {
$http(angular.extend({
method: 'DELETE',
url: self._urlForType(type, name, context, false, {namespace: project.metadata.name})
}, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data);
})
.error(function(data, status, headers, config) {
deferred.reject({
data: data,
status: status,
headers: headers,
config: config
});
});
});
}
else {
$http(angular.extend({
method: 'DELETE',
url: this._urlForType(type, name, context)
}, opts.http || {}))
.success(function(data, status, headerFunc, config, statusText) {
deferred.resolve(data);
})
.error(function(data, status, headers, config) {
deferred.reject({
data: data,
status: status,
headers: headers,
config: config
});
});
}
return deferred.promise;
};

// type: API type (e.g. "pods")
// name: API name, the unique name for the object
// context: API context (e.g. {project: "..."})
Expand Down Expand Up @@ -547,14 +595,16 @@ angular.module('openshiftConsole')
// an introspection endpoint that would give us this mapping
// https://github.com/openshift/origin/issues/230
var SERVER_TYPE_MAP = {
builds : apicfg.openshift,
deploymentConfigs : apicfg.openshift,
images : apicfg.openshift,
projects : apicfg.openshift,
users: apicfg.openshift,
pods : apicfg.k8s,
services : apicfg.k8s,
replicationControllers: apicfg.k8s
builds: apicfg.openshift,
deploymentConfigs: apicfg.openshift,
images: apicfg.openshift,
oAuthAccessTokens: apicfg.openshift,
projects: apicfg.openshift,
users: apicfg.openshift,

pods: apicfg.k8s,
replicationControllers: apicfg.k8s,
services: apicfg.k8s
};

DataService.prototype._urlForType = function(type, id, context, isWebsocket, params) {
Expand Down
28 changes: 28 additions & 0 deletions assets/app/scripts/services/logout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Logout strategies
angular.module('openshiftConsole')
.provider('DeleteTokenLogoutService', function() {

var debug = true;

this.$get = function($q, $injector) {
return {
logout: function(user, token) {
if (debug) { console.log("DeleteTokenLogoutService.logout()", user, token); }

// If we don't have a token, we're done
if (!token) {
if (debug) { console.log("DeleteTokenLogoutService, no token, returning immediately"); }
return $q.when({});
}

// Lazily get the data service. Can't explicitly depend on it or we get circular dependencies.
var DataService = $injector.get('DataService');
// Use the token to delete the token
// Never trigger a login when deleting our token
var opts = {http: {auth: {token: token, triggerLogin: false}}};
// TODO: Change this to return a promise that "succeeds" even if the token delete fails?
return DataService.delete("oAuthAccessTokens", token, {}, opts);
},
};
};
});
4 changes: 1 addition & 3 deletions assets/app/views/util/logout.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<div class="container">
<div>
<h1 style="margin-top: 10px;">Log out</h1>
<div>
You have been logged out. Return to the <a href="/">console</a>.
</div>
<div ng-bind-html="logoutMessage"></div>
</div>
</div>
1 change: 1 addition & 0 deletions assets/test/spec/controllers/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('Controller: ProjectController', function () {

angular.module('openshiftConsole').config(function(AuthServiceProvider) {
AuthServiceProvider.LoginService('RedirectLoginService');
AuthServiceProvider.LogoutService('DeleteTokenLogoutService');
AuthServiceProvider.UserStore('MemoryUserStore');
});

Expand Down
1 change: 1 addition & 0 deletions assets/test/spec/controllers/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('Controller: ProjectsController', function () {

angular.module('openshiftConsole').config(function(AuthServiceProvider) {
AuthServiceProvider.LoginService('RedirectLoginService');
AuthServiceProvider.LogoutService('DeleteTokenLogoutService');
AuthServiceProvider.UserStore('MemoryUserStore');
});

Expand Down
Loading

0 comments on commit dc262d1

Please sign in to comment.