In my application, it should not allow the user to open the application in multiple tabs for same browser. I need to implement this for some security purpose. How can i implement this?
Generate a session ID on server side every time a user opens your application. This session ID should be specific to the browser, IP, MAC and any data you receive as part of the initial request. For every subsequent request, validate the session ID.
Any link in your application should send a POST request, best would be submitting a form, and not a GET request so it does not open in another tab.
If a user intentionally opens your application in another tab, since you would know you already have a session ID generated for the requested data, invalidate the previously generated session ID, log the user out, and destroy the session.
A simpler way is to subscribe to localStorage notification and then update a node. Since events are not sent to the updating tab, it will only affect previously opened tabs.
Example in jquery:
$(window).on("storage", function(ev) {
if (ev.originalEvent.key == "tabsync") {
window.close(); // will probably not work if the user opened the tab
window.location = "/onetabonlyplease";
}
});
localStorage.setItem("tabsync", Date.now());
Related
I am working on a ServiceNow integration with a third party system. Using this integration a user can get the data from a third party system and use it to create a Service Request ticket. For this integration, we have created a widget on the Service Portal. This integration uses the authorization code flow for the authentication.
The widget is part of a catalog item which a user can request from the Service Portal. So the flow is like:
User logins to Service Portal and selects the item.
User selects a record in a reference field on the item. This item also has a button, on which when a user clicks he is presented with an authorization popup, where third party login UI appears. He enters his credentials for the third party system. If the authentication is successful, popup closes and tokens are saved in the 'oauth_credential' ServiceNow table.
What happens behind the scene is I am using the ServiceNow 'Get OAuth Token' functionality from the ServiceNow 'REST message' module. See below:
HTML
<button type="button" ng-click="checkAccess()" class="btn btn-default">Check Access</button>
Client Script
$scope.authorize = function() {
glideUserSession.loadCurrentUser().then(function(currentUser) {
var oauthRequestorSysId = currentUser.userID;
var oauthRequestorContext = 'sys_user';
var oauthProfileId = '59f05d7ddbf563003ca7da11cf961962';
var redirect = "https://dev000.service-now.com/oauth_redirect.do";
var oauth_initiator_url = '/oauth_initiator.do' +
'?oauth_requestor_context=' + oauthRequestorContext +
'&oauth_requestor=' + oauthRequestorSysId +
'&oauth_provider_profile=' + oauthProfileId +
'&response_type=code';
window.open(oauth_initiator_url, "", "height=500,width=800");
// additional code to use token once popup closes
});
}
I am able to achieve this till now. This popup saves the tokens into the ServiceNow.
Issue:
Once the authorization happens and popup up closes, the page refreshes. I don't want the page to refresh because the earlier selection made by user in the reference field is lost on page refresh.
I have more code in the same authorize function, where I will use the token generated by the authorization code pop up. But the issue is, if I add the code after popup, the popup opens up, but then it pauses and the next line of code gets executed. It seems like popup is asynchronous. Additional code functionality uses the token generated by popup to get data from the third party system.
I can't create two buttons, one for authorize and other one to use the tokens. I have to do this in a single button click.
Can I stop the page refresh once popup is closed? Can I add some logic after popup window line and this logic should be executed only once popup is closed.
This is just a guess as I don't have your code.
Since you said page is reloading when popup is closed, then there must be some code that is reloading the page as it will not happen automatically. The code could be in the 'message' event handler which is triggered using 'postMessage' (https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) from the popup. You can remove the reload logic from there.
Or
You might be using opener.reload in the popup window, you can remove that if used so your page doesn't reload after popup closed.
Thanks for suggestions. I got it working on the page load. On page load, I check for the token in the ServiceNow table, and if tokens are available and valid, I am skipping popup creation logic.
My goal is to make a modal window popup if a user clicks on a link to a page (or POSTs a form) for which he is unauthorized, as it is a better user experience than redirecting to a generic error page.
What I did is implement
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// ...
}
so that if the request is a non-AJAX request then it redirects to the same page (gives the illusion of staying on the same page) and appends the query string with "forbiddenRedirect=true" and then JavaScript opens the error modal. I'm trying to think of a better way than using the query string. From what I can tell, there's no way for JavaScript to access response headers, only the URL. That's why I went with the query string solution. But maybe in MVC there's some way I can redirect and pass some sort of token that the base controller can recognize and then add something to the view bag like ViewBag.IsRedirectFromUnauthorizedAction = true.
Any suggestions?
The user should never get to a page where they can post data without being authenticated and authorised!
If your users can get to forms where they can post information (lets go with a User Profile Page), they should be authenticated before they can even get there. So for example, you would lead the user to a Log in page before you allow them to access the Edit Profile page. Once they have authenticated themselves and you have checked they are authorised to perform a POST on a particular page, then you present them with the form.
But what if their session times out?
In the event that the user authenticates and gets to that page, then their session times out, you should redirect them back to the Log in page where they are prompted for their credentials again and deny their post request. In an ideal scenario, you should have an AJAX function running in the background every 30 seconds or so. If they are idle for a set period of time (lets say 5 minutes) then you can assume they have closed the browser or left their PC unattended. At this point, either ask the user (via modal window) if they'd like to stay logged in or be logged out in 30 seconds. If they click the Stay logged in button, leave them be. If they don't answer, you can log them out and automatically redirect them back to the Login page.
I am doing a SAML based authentication and want my user to be logged out of the system in case he closes the browser: I have written the following browser side code:
window.onbeforeunload =function(e){
deleteAllCookies();
var my_form=document.createElement('FORM');
my_form.name='my_form';
my_form.method='POST';
my_form.action="sessionExpired.do";
var hiddenText=document.createElement('INPUT');
hiddenText.type='HIDDEN';
hiddenText.name='crash';
hiddenText.ID='crash';
hiddenText.value='yes';
my_form.appendChild(hiddenText);
my_form.submit();
return;
};
This code calls my logout service and able to logg out of the system, in case one tab is opened, but the same doesn't work if along with my application multiple other tabs are opened.i.e in case of multiple tab, my server code gets called which invalidates session, but still session remains logged in and is not asked for authentication again.
There are limits to what you can do in a handler for beforeunload.
You can return text to prompt the user to ask if they're sure they want to leave.
But, you cannot force the window to stay open long enough to make the request to the server.
If you don't return a string, then the window will close immediately, and your form submission will not get processed.
If you do return a string, then the user will be asked if they're sure they want to close the window. If yes, the window will be closed, and your form submission will not get processed. If no, then the window will not be closed.
Deleting the cookies will probably work, but I don't think it will be possible to submit the form, or make a request to the server when the window is closed.
This question probably doesn't have an answer. But, I thought I'd give it a shot.
I wrote a great one-page application. When the application starts up, the open tab "registers" itself with the server, which stores is as an "active" tab.
If user A changes XYZ in the workspace, every tab opened on that workspace, by any user, receives a notification that XYZ was changed. That triggers a reload in the clients, which will magically be updated. At the moment, I am doing this by polling. However, when it all works I can use things like WS or Socket.io to make things even faster.
PROBLEM: every tab receives the notification. Even the tab that instigated it in the first place! (as a result, an already-updated screen gets updated)
I somehow need the server to know the tab ID of the tab making the request. Remember that a user might have 5 tabs open: if they change XYZ, all tabs should receive the notification, EXCEPT the one that actually triggered it!
At the moment, I am passing the workspace ID for every Ajax request ( a user might be logged in, and have access to several workspace at the same time).
Solution 1: append both workspace ID and tab ID for every request
Solution 2: only use the tab ID for every request. The app will work out the workspace ID from the tabID (which knows which workspace it belongs to)
Solution 3: ????? (Something that I am missing?)
Any ideas?
Instead of having the server worry about which tabs to send change notifications to you could have the tab that initiated the changes ignore the notification.
Two ways to do this come to mind:
After changing the content a tab will ingore all notifications for a brief period of time. (This will work fine unless changes on multiple tabs happen in a short amount of time.)
Have the tab create a "change id" that it sends to the server with the changes to xyz. The broadcast change notification contains this id and the sending tab recognizes it as the one it sent and ignores it.
You could experiment with HTML5 Visibility API with a fallback to window.onfocus & window.onblur events and suppress updating the page if it's currently visible/active.
I have an application URL which generates xyz named cookie for me if the user is logged in, in browser. I want to hit the URL programatically(using Java/JSP) to look if the user is logged in or not.
Now every time when I hit the url from my Java code it doesn't find that cookie (xyz) as it creates new session on every request. This is probably because I am hitting the url from my code. Now how can I come up with this situation so that my application will create cookie in browser and my code will look for that cookie.
The cookie is stored client-side by the browser of the user, so if you call the URL server-side it won't sent the cookie back with the response.
The way you are trying to know that user is logged in or not, can not be achieved through your approach.
Possible workaround for our case is :
Implement the HttpSessionAttributeListener and override the method attributeAdded and attributeRemoved method of it.
When ever session is getting created for logged in user, you would be saving the userName attribute is session most probably. Once the userName attribute is getting saved, attributeAdded method of your listner will get called and you can see the name of user there, once user is logged out, attributeRemoved method will get called by trigger of session invalidate method and your listener will get the notification . You can see the name of user who has logged out.
See below example for detail explanation.
http://www.roseindia.net/servlets/SessionAttributeListenerExample.shtml