Fixed refresh token.

This fix corrects two things. Firstly, it corrects a bug in
scheduleRefresh where the current scheduled token id was being
compared against a function, resulting in a permanent false.
Secondly, it adds promise-checking to tryRefresh, so that the
system will never issue more than one token refresh request at
a time.

This should address intermittent logout issues in storyboard.

Change-Id: Ie929b061ab1389c21e9c1bfdf4d580b85a778832
This commit is contained in:
Michael Krotscheck
2014-12-01 12:31:48 -08:00
parent a9bc6c0478
commit 092d757896

View File

@@ -1,71 +1,76 @@
angular.module('sb.auth').service('RefreshManager',
function($q, $log, $timeout, preExpireDelta, AccessToken, OpenId) {
function ($q, $log, $timeout, preExpireDelta, AccessToken, OpenId) {
'use strict';
var currentRefresh = null;
var nextRefreshPromise = null;
var scheduledForToken = null;
// Try to refresh the expired access_token
var tryRefresh = function() {
var deferred = $q.defer();
var resolved = false;
var tryRefresh = function () {
var refresh_token = AccessToken.getRefreshToken();
if (!refresh_token) {
$log.info('No refresh token found. Aborting refresh.');
deferred.reject();
resolved = true;
}
if (!currentRefresh) {
// Create our promise, since we should always return one.
currentRefresh = $q.defer();
currentRefresh.promise.then(
function () {
currentRefresh = null;
},
function () {
currentRefresh = null;
}
);
if (!resolved && !AccessToken.isExpired() &&
!AccessToken.expiresSoon()) {
$log.info('No refresh is required for existing access token.');
deferred.resolve(true);
resolved = true;
}
var refresh_token = AccessToken.getRefreshToken();
var is_expired = AccessToken.isExpired();
var expires_soon = AccessToken.expiresSoon();
if (resolved) {
return deferred.promise;
}
// Do we have a refresh token to try?
if (!refresh_token) {
$log.info('No refresh token found. Aborting refresh.');
currentRefresh.reject();
} else if (!is_expired && !expires_soon) {
$log.info('No refresh required for current access token.');
currentRefresh.resolve(true);
} else {
$log.info('Trying to refresh token');
var params = {
grant_type: 'refresh_token',
refresh_token: refresh_token
};
OpenId.token(params).then(
function(data) {
AccessToken.setToken(data);
deferred.resolve(true);
scheduleRefresh();
},
function() {
AccessToken.clear();
deferred.reject();
$log.info('Trying to refresh token');
OpenId.token({
grant_type: 'refresh_token',
refresh_token: refresh_token
}).then(
function (data) {
AccessToken.setToken(data);
currentRefresh.resolve(true);
scheduleRefresh();
},
function () {
AccessToken.clear();
currentRefresh.reject();
}
);
}
);
return deferred.promise;
}
return currentRefresh.promise;
};
var scheduleRefresh = function() {
if (!AccessToken.getRefreshToken()) {
var scheduleRefresh = function () {
if (!AccessToken.getRefreshToken() || AccessToken.isExpired()) {
$log.info('Current token does not require deferred refresh.');
return;
}
var expiresAt = AccessToken.getIssueDate() +
AccessToken.getExpiresIn();
if (!!nextRefreshPromise &&
AccessToken.getAccessToken === scheduledForToken) {
AccessToken.getAccessToken() === scheduledForToken) {
$log.info('The refresh is already scheduled.');
return;
}
var now = Math.round((new Date()).getTime() / 1000);
var delay = (expiresAt - preExpireDelta - now) * 1000;
nextRefreshPromise = $timeout(tryRefresh, delay, false);