So, my current task involves a site where people can sign in, and view a series of training videos on a particular topic. I developed this within CodeIgniter. The only trouble is that once I have them log in, and I create a session, that session seems to mysteriously disappear after a few minutes, and they're mysteriously bounced back to the login page (which is what happens if someone is on the training video page without being signed in. This is the block of code in my config.php page:
$config['sess_cookie_name'] = 'cc_session';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'cc_sessions';
$config['sess_match_ip'] = TRUE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 3000000;
Why is sess_time_to_update set so high? At first, I thought that was the culprit, updating the session after 5 minutes. I have set the session to record to a database, and all that good stuff. Please, ask me questions, and help me get to the bottom of this!
I should point out that I have an iFrame that is on the course page that is sending a "ping" back to a server this way...
<iframe id="timerAddEnd" style="display:none;" src="http://www.example.com/course/finish/<?=$course->intKey?>/ping" >
</iframe>
<script type="text/javascript">
var auto_refresh = setInterval( function ()
{
var iframe = document.getElementById('timerAddEnd');
iframe.src = iframe.src;
}, 60000);
// refresh every minute
</script>
Could THIS be the culprit? I was hoping this would be a quick and dirty fix to the initial problem.
Are you using Firefox and Firebug with extensions (like FirePHP) installed? Because if you are having such a setup, when you open/close the Firebug console, the user-agent string changes, and your session is no longer recognized by CI.
My workaround was to disable FirePHP. Try checking your user-agent string and see if you have something extra besides the default browser user-agent. You should be able to identify it easily. if there is one.
Well, this may not be a full "answer" per se, but I did come up with a workaround of sorts.
I knew that the problem involved CodeIgniter handling sessions with... how do I put it... stuff running in the background. Originally I was using a CI page within the iFrame. Those "pings" back to the system were what was causing the lockout. So, I now use a regular, flat ol' PHP page within the iFrame. It connects to the database, but doesn't go through CI to do it. I get my "pings" to the table in question, but I don't break the session.
I had the same problem with session data getting "randomly" destroyed in CodeIgniter and I spent alot of time finding out what was wrong. Now I think i found MY problem, and it seemed as the $this->session->set_flashdata was the culprit.
I noticed that I got logged out on pages where this were used. I also noticed that if you do:
$this->session->set_flashdata('thisItem', 'value');
and later on the same page have the same variable again:
$this->session->set_flashdata('thisItem', 'new value');
then it will destroy the session data every time. Now I removed all the set_flashdata from my site, I havent been logged out since.. hoping this was my problem. When I have the time I will try to rewrite my flashing system to maybe something like if (!isset('thisItem)) { set it; } and stuff like this to prevent it from happening again, because I really want the flash messages.
Related
I'm working on an identityserver4 login site (server UI) with .NET Identity in .NET Core 2.2 Razor Pages, I have a javascript modal alert that warns users of a pending idle timeout, and then when reaching timeout it redirects the user to the logout screen by setting window.location
The trouble I have is that the OnGet in the quick start sample shows a user prompt to log out as at this point logoutId is null. I want to log out without prompting the user.
For the time being I have worked around this by passing an "autoLogout" parameter to my Logout page which bypasses the check for logoutId and sets ShowLogoutPrompt = false. I'm aware that this somewhat defeats the purpose of checking for logoutId to ensure that it is safe to sign-out without prompt.
Is there a better way to do what I'm trying to do?
Edit 16 Jul 2019:
It seems as though the "right" way to handle idle timeout is to set the application cookie's token expiry (to say 20 minutes) and enable SlidingExpiration so that the token is renewed when the user refreshes. For good info on this see this blog post, this github issue thread (including comments from Brock Allen), and this info in the MS docs.
My trouble is that this solution has two huge drawbacks.
SlidingExpiration only refreshes the cookie if the user is >50% through the token's TimeSpan (see SlidingExpiration info in MS docs here). So if they refresh 9m59s into a 20 minute token they will timeout after just 10 minutes instead of 20. One workaround would be to set the token lifetime to 40 minutes, which would give the user at least 20 minutes of idle time, but they could have up to 40 minutes of idle time which is not acceptable.
One of my requirements is a modal to warn the user of an impending timeout and give them the option to continue/log out. To do this using this cookie approach I would need to read the token expiry time from the cookie in my Javascript (or at least in my Razor Page in C#) to enable me to time when to show the warning. Even without the modal requirement I'd need to know when the token has expired so that I could cause a page refresh to send the user to the login screen. I'm attempting to read the expiry time using the following code but it fails to read the correct expiry time after a token refresh until the page is refreshed a second time, I don't know why.
#(DateTime.Parse(((await Context.AuthenticateAsync()).Properties.Items)[".expires"]))
Another less significant drawback to the cookies approach is that if I manage to implement a modal popup and the user opts to continue, then the page will need a refresh to get a new token, at which point any unsaved data would be lost. I guess if they time out then unsaved data would be lost anyway though so this is a relatively minor point compared with the above.
I'm thinking of going back to my original solution which has the desired functionality but would be open to abuse by an attacker who noticed my autoLogout parameter in the idle timeout javascript and could then use it to provide a hotlink to the logout page. At the moment taking that risk feels like my best option.
I feel like I've been down a rabbit hole on this one and still have no good solution. It amazes me that what I imagine to be a common use case (idle timeout with a warning allowing the user to continue/log out) is so poorly catered for with this authentication technology. Am I missing something? Do I have the wrong end of the stick?
I'm posting my final solution here. It works but I don't like it much. For references, details on why I think it's a bit hacky, and of what I think the main drawbacks are see the 16th Jul edit to my original question above.
In ConfigureServices after adding identityserver I set the cookie's SlidingExpiration = true; ExpireTimeSpan = AppSettings.IdleTimeoutMins (see this blog for how I set up AppSettings):
// Rename the .AspNetCore.Identity.Application cookie and set up for idle timeout
services.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = "xxxx.Application";
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(_config.GetValue<int>("AppSettings:" + nameof(AppSettings.IdleTimeoutMins)));
});
I have a Partial Razor Page in which I have javascript code to display a modal alert to the user with a count down timer. I get the timeoutSeconds from AppSettings.IdleTimeoutMins and also have a setting to determine when to show the warning. For more detail on this bit (and its pros and cons) see my other question and answer here: How to get ASP.NET Identity authentication ticket expiry in Razor Page? The warning message gives the user the option to "Continue" which refreshes the page (and therefore the authentication ticket) or "Log Out", which sends them to the Log Out confirmation page. If the clock runs down then the page is refreshed, which causes them to be returned to the Log In screen.
At the top of the Partial:
#inject RussellLogin.Services.IAppSettings AppSettings;
#using Microsoft.AspNetCore.Authentication;
Getting the (assumed) number of seconds remaining on the ticket:
secondsRemaining = "#(DateTime.Parse(((await AuthenticationHttpContextExtensions
.AuthenticateAsync(Context))
.Properties
.Items)[".expires"])
.Subtract(DateTime.Now)
.TotalSeconds)";
// If secondsRemaining is less than half the expiry timespan then assume it will be re-issued
if (secondsRemaining < timeoutSeconds / 2) {
secondsRemaining = timeoutSeconds;
}
Has anyone experienced the "Trying to login before initializing." error?
It seems like there is a limit to the number of calls you can make to the API but I have not hit the 1000 per hour by any means.
This even occurs after I authenticate once. Once I refresh the page, I get the message above. I end up waiting a little bit (usually a few mins) then I can authenticate again.
I would like this to go away or at least save the authentication within a cookie or something like that.
Can anyone lead me in the right direction?
Appreciate the help in advance.
I was getting that same error message when setting appId to null or undefined in PDK.init. Maybe you are doing the init logic before the actual value is assigned.
I'd recommend using environment variables to keep the App ID outside of your code and inject it at build time, similar to how Create React App does it: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables
I consider two scenarios:
User clicks on "log out" hyperlink, which call "logout.php" (that is easy)
User closes tab (window) or closes browser.
And here I do not know, what should I do.
There is a event: window.onunload which can be used perhaps like this (not tested):
<script>
var logout_php = function () {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "logout.php", true);
xhttp.send();
}
window.onunload = logout_php ;
</script>
But when the user opens more tabs and closes just one of them, he will be logged out. Probably it will log out even, when somebody refreshes the same page.
I considered to count all opened tabs with the same domain address, and if there is only one left, then will be the final logout. But this is not possible, because you can not access another windows (tabs) opened in browser.
I am sure, it must be a common problem, but I can not find appropriate answer.
thanx
Sessions are used to handle these kind of things. If you logout then your session is destroyed and if someone closes the window directly then in that case their session is destroyed as well. So, as long as you are using sessions, there is nothing to worry about.
You can try a keep_live ajax function that calls your server every 1 minute or so updating the last_checkin variable in database or so. If the tab is closed, said function is no longer being called.
In the beginning of every request check if last_checkin is within the last minute (+ some time for connection). If not, redirect to log out (and destroy session if it exists).
This is similar to session timeout. You can have this done every 5 seconds or so. If someone closes his tab and then (for some weird reason) someone else sits on the PC and opens previously closed tabs. Most likely the x time has passed since last check in and user is now logged out.
The down side is the traffic between user and server but it's not a big deal. This is how you check for chat updates anyway so it is done in many services.
I've been trying to figure out a way to use notifications on a background process and couldnt find anything online about it. So, I figured out one way around it and wanted to share (Not sure if this is the best way to go about doing this but here goes:)
Problem: I want to notify the user of new info when the page is running but in the background (blurred). I could use alert('new info!'); to get the taskbar icon to flash, but then you have to manually dismiss it (tried it and it's hella annoying). I really liked the notifications, but they only work if the user performs an action, so not helpful...
I hope I won't be telling something stupid, but from where I see it (and remember from school) that's basically how http works : a request is sent to the server, which issues a response eventually after executing some server-side code.
Basically you're asking for a "PUSH" functionality from server to client, and in that case you can't make use of HTTP.
Some tricks exist to work around this limitation, but basically they're all issuing requests at a certain frequency (Dave's answer does exactly that). If your site doesn't change that much, that means a lot of requests are issued for no reason (nothing has changed), consuming bandwith for nothing.
From what I know, the answer to this is called Websockets, which are supported by recent browsers only. I never had the chance to use it though so I couldn't tell much more about it. This allows full duplex communication, thus allowing server to "push" data to the client. I guess that's what SO uses for "new message" notifications (top left of the screen - you see immediately when you receive a new message)
My solution: I made a chrome extension that runs in the background and triggers the notifications. It's a little limited in scope as you need to have chrome to do it, but it does what i need it to, and for the purposes of the problem i'm working on, i can just make my user group use chrome ;D
The specifics: The extension only has two components, the manifest and a script. Currently, i setup the manifest so that it only works on my site using the match identifier... and i set the permissions to include notifications.
The JS script has a window.setinterval that looks for an element in the page with the id NOTIFIER. If it's empty, it does nothing, otherwise it creates a notification based on the content and then clears the content to prevent showing the same notification multiple times... (I tried using .onchange for that element, but couldn't get the event to trigger... I'd prefer to do this on an event rather then setInterval)
Notify.js
function onExtLoad() {
var timer = setInterval(refresh,1000);
}
document.addEventListener('DOMContentLoaded', onExtLoad());
function refresh() {
if (document.getElementById('NOTIFIER').innerHTML == "") {
//do nothing?
} else {
var notification = webkitNotifications.createNotification("",
"You got a new message",
document.getElementById('NOTIFIER').innerHTML);
notification.show();
document.getElementById('NOTIFIER').innerHTML = "";
}
}
Then, all i need to do is have the JS on the page control when it adds info the the NOTIFIER and voila! notifications!
Hope this helps someone else.
#ExpertSystem: I messed around with the MutationObserver but I can only get it to trigger once. Here's a JSFiddle: http://jsfiddle.net/BTX8x/1/
Am I missing something? Is there a way to reset it?
EDIT: Figured it out, i needed subtree:true
I am trying to use periodic refresh(ajax)/polling on my site by XMLHttp(XHR) to check if a user has a new message on the database every 10 seconds, then if there is inform him/her by creating a div dynamically like this:
function shownotice() {
var divnotice = document.createElement("div");
var closelink = document.createElement("a");
closelink.onclick = this.close;
closelink.href = "#";
closelink.className = "close";
closelink.appendChild(document.createTextNode("close"));
divnotice.appendChild(closelink);
divnotice.className = "notifier";
divnotice.setAttribute("align", "center");
document.body.appendChild(divnotice);
divnotice.style.top = document.body.scrollTop + "px";
divnotice.style.left = document.body.scrollLeft + "px";
divnotice.style.display = "block";
request(divnotice);
}
Is this a reliable or stable way to check message specifically since when I look under firebug, a lot of request is going on to my database? Can this method make my database down because of too much request? Is there another way to do this since when I login to facebook and check under firebug, no request is happening or going on but I know they are using periodic refresh too... how do they do that?
You can check for new data every 10 seconds, but instead of checking the db, you need to do a lower impact check.
What I would do is modify the db update process so that when it makes a change to some data, it also updates the timestamp on a file to show that there is a recent change.
If you want better granularity than "something changed somewhere in the db" you can break it down by username (or some other identifier). The file(s) to be updated would then be the username for each user who might be interested in the update.
So, when you script asks the server if there is any information for user X newer than time t, instead of making a DB query, the server side script can just compare the timestamp of a file with the time parameter and see if there is anything new in the database.
In the process that is updating the DB, add code that (roughly) does:
foreach username interested in this update
{
touch the file \updates\username
}
Then your function to see if there is new data looks something like:
function NewDataForUser (string username, time t)
{
timestamp ts = GetLastUpdateTime("\updates\username");
return (ts > t);
}
Once you find that there is new data, you can then do a full blown DB query and get whatever information you need.
I left facebook open with firebug running and I'm seeing requests about once a minute, which seems like plenty to me.
The other approach, used by Comet, is to make a request and leave it open, with the server dribbling out data to the client without completing the response. This is a hack, and violates every principle of what HTTP is all about :). But it does work.
This is quite unreliable and probably far too taxing on the server in most cases.
Perhaps you should have a look into a push interface: http://en.wikipedia.org/wiki/Push_technology
I've heard Comet is the most scalable solution.
I suspect Facebook uses a Flash movie (they always download one called SoundPlayerHater.swf) which they use to do some comms with their servers. This does not get caught by Firebug (might be by Fiddler though).
This is not a better approach. Because you ended up querying your server in every 10 seconds even there is no real updates.
Instead of this polling approach, you can simulate the server push (reverrse AJAX or COMET) approach. This will compeletly reduce the server workload and only the client is updated if there is an update in server side.
As per wikipedia
Reverse Ajax refers to an Ajax design
pattern that uses long-lived HTTP
connections to enable low-latency
communication between a web server and
a browser. Basically it is a way of
sending data from client to server and
a mechanism for pushing server data
back to the browser.
For more info, check out my other response to the similar question