mirror of
https://github.com/OpenBankProject/API-Manager.git
synced 2026-02-06 14:56:47 +00:00
Add auto-logout function.
Add an auto logout function that makes a call to the /obp/v5.1.0/ui/suggested-session-timeout to find the suggested session timeout time. Failing this, we default to a timeout of 300 seconds. A timer can be seen next to the logout button which shows the time remaining before logout.
This commit is contained in:
parent
eec9ed8022
commit
d73c16efa2
@ -89,20 +89,6 @@ MIDDLEWARE = [
|
||||
# 'django.middleware.cache.FetchFromCacheMiddleware',
|
||||
]
|
||||
|
||||
# Content Security Policy - External Urls for scripts, styles, and images should be included here
|
||||
#TODO these outside scripts should really just be loaded when we run "manage.py collectstatic"
|
||||
# Or the whole static folder could be uploaded to github, this prevents API manager breaking when
|
||||
# we run it on a server that may not connect to these sites
|
||||
|
||||
# Inline styles loaded by jsoneditor.min.js have been allowed by adding their hashes to CSP_STYLE_SRC
|
||||
|
||||
CSP_IMG_SRC = ("'self' data:", 'https://static.openbankproject.com')
|
||||
CSP_STYLE_SRC = ("'self' 'sha256-z2a+NIknPDE7NIEqE1lfrnG39eWOhJXWsXHYGGNb5oU=' 'sha256-Dn0vMZLidJplZ4cSlBMg/F5aa7Vol9dBMHzBF4fGEtk=' 'sha256-sA0hymKbXmMTpnYi15KmDw4u6uRdLXqHyoYIaORFtjU=' 'sha256-jUuiwf3ITuJc/jfynxWHLwTZifHIlhddD8NPmmVBztk=' 'sha256-RqzjtXRBqP4i+ruV3IRuHFq6eGIACITqGbu05VSVXsI='", 'https://cdnjs.cloudflare.com', )
|
||||
CSP_SCRIPT_SRC = ("'self' 'sha256-4Hr8ttnXaUA4A6o0hGi3NUGNP2Is3Ep0W+rvm+W7BAk=' 'sha256-GgQWQ4Ejk4g9XpAZJ4YxIgZDgp7CdQCmqjMOMh9hD2g=' 'sha256-05NIAwVBHkAzKcXTfkYqTnBPtkpX+AmQvM/raql3qo0='", 'http://code.jquery.com', 'https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/', 'https://cdnjs.cloudflare.com')
|
||||
CSP_FONT_SRC = ("'self'", 'http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/')
|
||||
CSP_FRAME_ANCESTORS = ("'self'")
|
||||
CSP_FORM_ACTION = ("'self'")
|
||||
|
||||
#cache the view page, we set 60s = 1m,
|
||||
# CACHE_MIDDLEWARE_SECONDS = 60
|
||||
|
||||
@ -353,3 +339,19 @@ if not OAUTH_CONSUMER_KEY:
|
||||
raise ImproperlyConfigured('Missing settings for OAUTH_CONSUMER_KEY')
|
||||
if not OAUTH_CONSUMER_SECRET:
|
||||
raise ImproperlyConfigured('Missing settings for OAUTH_CONSUMER_SECRET')
|
||||
|
||||
#This has been moved to after API_HOST is imported so that connections to the API are allowed by the csp
|
||||
# Content Security Policy - External Urls for scripts, styles, and images should be included here
|
||||
#TODO these outside scripts should really just be loaded when we run "manage.py collectstatic"
|
||||
# Or the whole static folder could be uploaded to github, this prevents API manager breaking when
|
||||
# we run it on a server that may not connect to these sites
|
||||
|
||||
# Inline styles loaded by jsoneditor.min.js have been allowed by adding their hashes to CSP_STYLE_SRC
|
||||
|
||||
CSP_IMG_SRC = ("'self' data:", 'https://static.openbankproject.com')
|
||||
CSP_STYLE_SRC = ("'self' 'sha256-z2a+NIknPDE7NIEqE1lfrnG39eWOhJXWsXHYGGNb5oU=' 'sha256-Dn0vMZLidJplZ4cSlBMg/F5aa7Vol9dBMHzBF4fGEtk=' 'sha256-sA0hymKbXmMTpnYi15KmDw4u6uRdLXqHyoYIaORFtjU=' 'sha256-jUuiwf3ITuJc/jfynxWHLwTZifHIlhddD8NPmmVBztk=' 'sha256-RqzjtXRBqP4i+ruV3IRuHFq6eGIACITqGbu05VSVXsI='", 'https://cdnjs.cloudflare.com', )
|
||||
CSP_SCRIPT_SRC = ("'self' 'sha256-4Hr8ttnXaUA4A6o0hGi3NUGNP2Is3Ep0W+rvm+W7BAk=' 'sha256-GgQWQ4Ejk4g9XpAZJ4YxIgZDgp7CdQCmqjMOMh9hD2g=' 'sha256-05NIAwVBHkAzKcXTfkYqTnBPtkpX+AmQvM/raql3qo0='", 'http://code.jquery.com', 'https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/', 'https://cdnjs.cloudflare.com')
|
||||
CSP_FONT_SRC = ("'self'", 'http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/')
|
||||
CSP_FRAME_ANCESTORS = ("'self'")
|
||||
CSP_FORM_ACTION = ("'self'")
|
||||
CSP_CONNECT_SRC = (API_HOST)
|
||||
|
||||
39
apimanager/base/static/js/inactivity-timer.js
Normal file
39
apimanager/base/static/js/inactivity-timer.js
Normal file
@ -0,0 +1,39 @@
|
||||
function addSeconds(date, seconds) {
|
||||
let oldDate = date;
|
||||
let addSeconds = seconds;
|
||||
var newSeconds = oldDate + addSeconds;
|
||||
//console.log(addSeconds);
|
||||
date.setSeconds(date.getSeconds() + seconds);
|
||||
return date;
|
||||
}
|
||||
|
||||
export function showCountdownTimer() {
|
||||
|
||||
// Get current date and time
|
||||
var now = new Date().getTime();
|
||||
let distance = countDownDate - now;
|
||||
// Output the result in an element with id="countdown-timer-span"
|
||||
let elementId = ("countdown-timer-span");
|
||||
document.getElementById(elementId).innerHTML = "in " + Math.floor(distance / 1000) + "s";
|
||||
|
||||
// If the count down is over release resources
|
||||
if (distance < 0) {
|
||||
destroyCountdownTimer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set the date we're counting down to
|
||||
let countDownDate = addSeconds(new Date(), 5);
|
||||
|
||||
let showTimerInterval = null;
|
||||
|
||||
export function destroyCountdownTimer() {
|
||||
clearInterval(showTimerInterval);
|
||||
}
|
||||
|
||||
export function resetCountdownTimer(seconds) {
|
||||
destroyCountdownTimer(); // Destroy previous timer if any
|
||||
countDownDate = addSeconds(new Date(), seconds); // Set the date we're counting down to
|
||||
showTimerInterval = setInterval(showCountdownTimer, 1000); // Update the count down every 1 second
|
||||
}
|
||||
107
apimanager/base/static/js/inactivity.js
Normal file
107
apimanager/base/static/js/inactivity.js
Normal file
@ -0,0 +1,107 @@
|
||||
import * as countdownTimer from './inactivity-timer.js'
|
||||
|
||||
// holds the idle duration in ms (current value = 301 seconds)
|
||||
var timeoutIntervalInMillis = 5 * 60 * 1000 + 1000;
|
||||
// holds the timeout variables for easy destruction and reconstruction of the setTimeout hooks
|
||||
var timeHook = null;
|
||||
|
||||
function initializeTimeHook() {
|
||||
// this method has the purpose of creating our timehooks and scheduling the call to our logout function when the idle time has been reached
|
||||
if (timeHook == null) {
|
||||
timeHook = setTimeout( function () { destroyTimeHook(); logout()}.bind(this), timeoutIntervalInMillis);
|
||||
}
|
||||
}
|
||||
|
||||
function destroyTimeHook() {
|
||||
// this method has the sole purpose of destroying any time hooks we might have created
|
||||
clearTimeout(timeHook);
|
||||
timeHook = null;
|
||||
}
|
||||
|
||||
function resetTimeHook(event) {
|
||||
// this method replaces the current time hook with a new time hook
|
||||
destroyTimeHook();
|
||||
initializeTimeHook();
|
||||
countdownTimer.resetCountdownTimer(timeoutIntervalInMillis / 1000);
|
||||
// show event type, element and coordinates of the click
|
||||
// console.log(event.type + " at " + event.currentTarget);
|
||||
// console.log("Coordinates: " + event.clientX + ":" + event.clientY);
|
||||
console.log("Reset inactivity of a user");
|
||||
}
|
||||
|
||||
function setupListeners() {
|
||||
// here we setup the event listener for the mouse click operation
|
||||
document.addEventListener("click", resetTimeHook);
|
||||
document.addEventListener("mousemove", resetTimeHook);
|
||||
document.addEventListener("mousedown", resetTimeHook);
|
||||
document.addEventListener("keypress", resetTimeHook);
|
||||
document.addEventListener("touchmove", resetTimeHook);
|
||||
console.log("Listeners for user inactivity activated");
|
||||
}
|
||||
|
||||
function destroyListeners() {
|
||||
// here we destroy event listeners for the mouse click operation
|
||||
document.removeEventListener("click", resetTimeHook);
|
||||
document.removeEventListener("mousemove", resetTimeHook);
|
||||
document.removeEventListener("mousedown", resetTimeHook);
|
||||
document.removeEventListener("keypress", resetTimeHook);
|
||||
document.removeEventListener("touchmove", resetTimeHook);
|
||||
console.log("Listeners for user inactivity deactivated");
|
||||
}
|
||||
|
||||
function logout() {
|
||||
destroyListeners();
|
||||
countdownTimer.destroyCountdownTimer();
|
||||
console.log("Logging you out due to inactivity..");
|
||||
const logoffButton = document.getElementById("logout");
|
||||
logoffButton.click();
|
||||
}
|
||||
|
||||
async function makeObpApiCall() {
|
||||
let timeoutInSeconds;
|
||||
try {
|
||||
let obpApiHost = document.getElementById("api_home_link");
|
||||
if(obpApiHost) {
|
||||
obpApiHost = obpApiHost.href.split("?")[0];
|
||||
}
|
||||
console.log(obpApiHost);
|
||||
const response = await fetch(`${obpApiHost}/obp/v5.1.0/ui/suggested-session-timeout`);
|
||||
const json = await response.json();
|
||||
if(json.timeout_in_seconds) {
|
||||
timeoutInSeconds = json.timeout_in_seconds;
|
||||
console.log(`Suggested value ${timeoutInSeconds} is used`);
|
||||
} else {
|
||||
timeoutInSeconds = 5 * 60 + 1; // Set default value to 301 seconds
|
||||
console.log(`Default value ${timeoutInSeconds} is used`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
timeoutInSeconds = 5 * 60 + 1; // Set default value to 301 seconds, even if the session timeout endpoint is not reachable for whatever reason
|
||||
console.log(`Default value ${timeoutInSeconds} is used`);
|
||||
}
|
||||
return timeoutInSeconds;
|
||||
}
|
||||
|
||||
async function getSuggestedSessionTimeout() {
|
||||
if(!sessionStorage.getItem("suggested-session-timeout-in-seconds")) {
|
||||
let timeoutInSeconds = await makeObpApiCall();
|
||||
sessionStorage.setItem("suggested-session-timeout-in-seconds", timeoutInSeconds);
|
||||
}
|
||||
return sessionStorage.getItem("suggested-session-timeout-in-seconds") * 1000 + 1000; // We need timeout in millis
|
||||
}
|
||||
|
||||
// self executing function to trigger the operation on page load
|
||||
(async function () {
|
||||
timeoutIntervalInMillis = await getSuggestedSessionTimeout(); // Try to get suggested value
|
||||
const logoffButton = document.getElementById("countdown-timer-span");
|
||||
if(logoffButton) {
|
||||
// to prevent any lingering timeout handlers preventing memory leaks
|
||||
destroyTimeHook();
|
||||
// setup a fresh time hook
|
||||
initializeTimeHook();
|
||||
// setup initial event listeners
|
||||
setupListeners();
|
||||
// Reset countdown timer
|
||||
countdownTimer.resetCountdownTimer(timeoutIntervalInMillis / 1000);
|
||||
}
|
||||
})();
|
||||
@ -31,7 +31,7 @@
|
||||
<div id="navbar" class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li> <a class="obp-home-button" href="{% url 'home' %}"><img src="{{ logo_url }}" alt="brand"></a></li>
|
||||
<li><a href="{{ API_PORTAL }}">{% trans "Home" %}</a></li>
|
||||
<li><a id="api_home_link" href="{{ API_PORTAL }}">{% trans "Home" %}</a></li>
|
||||
{% url "consumers-index" as consumers_index_url %}
|
||||
<li {% if consumers_index_url in request.path %} class="active" {% endif %}><a href="{{ consumers_index_url }}">{% trans "Consumers" %}</a></li>
|
||||
{% url "entitlementrequests-index" as entitlementrequests_index_url %}
|
||||
@ -104,7 +104,11 @@
|
||||
{% endif %}
|
||||
<li>
|
||||
{% if user.is_authenticated %}
|
||||
<p class="navbar-right button-select"><span id="navbar-login-username">{{API_USERNAME}}</span> <a href="/logout" class="btn btn-default">{% trans "Logout" %} </a></p>
|
||||
<p class="navbar-right button-select">
|
||||
<span id="navbar-login-username">{{API_USERNAME}}</span>
|
||||
<a id="logout" href="/logout" class="btn btn-default">{% trans "Logout" %}</a>
|
||||
<span class="badge badge-secondary" id="countdown-timer-span"></span>
|
||||
</p>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li class="language-select language_underline_format"><a>Language
|
||||
@ -146,6 +150,7 @@
|
||||
<script type="text/javascript" src="{% static 'js/jquery.tablesorter.min.js' %}"></script>
|
||||
<script src="{% static 'js/base.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jsoneditor.min.js' %}"></script>
|
||||
<script type="module" defer src="{% static 'js/inactivity.js' %}"></script>
|
||||
{% block extrajs %}{% endblock extrajs %}
|
||||
</body>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user