We're running an install of Magento Enterprise which has built-in support for using Redis as a session handler.
For context: We're having with a module that implements PayPal payment method as an option for our users.
The module generates a lightbox with the PayPal form in it so that the user doesn't have to be redirected away from the page.
To do this, we have to generate a token, and save it to the session. The lightbox loads in the PayPal page with the token in the URL parameter.
When the user completes the form, the user is redirected to a confirm order page with the same token in the URL.
The URL token has to match the session token, or else the process fails.
This works fine when we disable redis and use normal file sessions (which we cannot do in our production environment).
Here is what we don't understand:
When we step through the code with xdebug with breakpoints, we see the token being set in the session in redis. The payment processing works fine.
When we don't step through the code, the process fails due to a token mismatch, and when we inspect the token key throughout the process, it originally sets it correctly, and then at the end, the token is we see is a token that was set several sessions ago.
The TTL on the session key is 24 minutes but don't think that should be an issue because it should be overwriting the value. Not sure why it works fine when we pause through the process with breakpoints.
Any ideas?
Is it the standard Magento PayPal module?
My first thought is that something else is storing an object to redis (and it should not do it) and later requests receive a cached value because this object is cached.
Maybe do a simple test:
Clear redis cache
Place an order and proceed to PayPal
Is at this point everything ok?
Check the token stored in Redis for this particular session and write it down
Place another order & proceed to Paypal
Verify whether the received token is the same as the previous one
Related
We have an issue with a asp.net core 3.1 MVC application. The application is using the built in asp.net Identity feature. The application is working well for existing users. If you hit any [Authorized] route, you are redirected to the login page as expected.
However, rather than have a registration process in our app, for new users, we onboard them via Stripe Checkout. Upon successful payment, stripe redirects to a specific route in our application /conversion/success/{sessionid} where sessionid is the Stripe session. This action is marked as [AllowAnonymous].
We then pull the necessary customer details from Stripe, create a user in our repository via UserManager<T>. We then call SignInManager<T>.SignInAsync() to sign in the new user, before redirecting the new user to the [Authorized] home page.
This process works perfectly when running locally on our test machines. Also, when running on our production server (Azure App Service) it also works perfectly when we hit the route manually through the browser.
However, when we actually run the process through Stripe, complete a payment and let Stripe redirect the customer, we get a strange behaviour.
The conversion route is hit, the user record is created, the sign in process completes but upon redirection to home page, the authentication middleware takes over, says it's not authenticated and redirects to the login page.
Just to compound matters further, if you then simply type in the home page route in the browser, the user is in fact logged in exactly as expected and the application works perfectly.
Using Fiddler to intercept the calls and look at headers, etc. we can't see why there would be a different behaviour when coming from Stripe as opposed to typing directly. We've even tried redirecting from a different website to our registration process and that works as expected too.
Any idea why we are seeing this behaviour?
---- Update ---
If, rather than redirect to home page at the end of the onboarding process, we simply show a simple View with an anchor link to home page, the user can then go to home page as expected.
Is it possible that you're rendering the page before authentication has been completed? Since UserManager uses a cookie to establish the user's session, authentication needs to complete before any response headers or body is set so that the Set-Cookie header can be sent in the response.
Based on what you described it sounds like the user is hitting the homepage after the redirect without having the authentication cookie. Where I'd start debugging this is by using your web inspector with "Preserve log" turned on and going through the Stripe Checkout process. Then, inspect the headers sent to the browser when you land on the redirect page & make sure the authentication cookie is set.
Between requests to Stripe and SignInAsync it seems possible that there might be a missing await, so the redirect is happening before the authentication context is updated. Hard to say more without seeing your code!
In implementation of Login, I want to make sure if a user is already logged in one tab of the browser and opens the same web site in another tab, he gets redirected to homepage rather than the log in page. It's an ideal scenario as it happens in all the web site. I am achieving the same by storing logged in unique user token in local storage. Is it the best way to achieve it? Kindly guide! is it safe? If not how to go about it?
Just consider everything on the client as tainted or possibly manipulated.
So basically you should always check on the server side if the client has a valid session and only then deliver the homepage to it.
I would use a cookie set by the server side - just a random id bound to the actual client session on the server.
So the client could mess with that, but would have a hard time to guess another (also random) session id.
The cookie should be cleared by the server if the user logs out.
Then I would check on every call if he has a valid session id and if not directly send him to the login page by a redirect. Additionally you could then send him from the login page to the homepage whenever he is already logged in.
I can redirect a user to home page upon session logout.. this was very simple. However, if an user had logged into the app and had the page open, even on session time out, he is able to perform all the functions(this is bad).
The redirect does not happen until the page is refreshed, or submitted to the server... there are some update functions that could be done by the user even if he is not currently logged in... I have done a lot of research but unable to fix this solution. I also found this thread but it seems to have no proper answer:
Spring Security 3.1 - Automatically redirect to login page when session-timeout occurs
For example, most of the banking sites log you out after a time out.. they do not wait until you come back and then submit a request before you are redirected to home page.
HTTP is stateless. To achieve some form of state the server can maintain a session for each user by giving them a session id on their first request. The user would have to resend that session id on each future request to identify that the other requests happen within the same session.
Because the session is maintained by the server, there is no way to notify the client that the session has timed out.
Instead, if the user makes a new request when the session is timed out, their session ID is no longer good and therefore you can take a particular action like redirect them to login page.
Assuming nothing works out. You may want to consider below mentioned approches:
Approach 1:
Create a cookie on browser and have encrypted timestamp in it that will contain last visited/request timestamp from browser, for each request first get get this cookie value and compare with the pre-defined session out time, if session-out time reached then redirect user to error page else serve the request. On logout delete the cookie.
Why encrypted value for timestamp: if somehow user gets to know about cookie used for session timeout then (s)he can change this value in browser and keep on sending this request.
Approach 2:
You can also achieve this by making an entry in your database for every logged-in user and updating timestamp in this database for each request. For each incoming request get this timestamp from database and compare it with pre-defined value for timeout and handle accordingly. On logout delete the entry.
In both the approaches explicitly perform response.redirect("errorPageUrl");
I have this web app written in AngularJs that uses cookies to authenticate the requests in a REST API.
Once the user logs in, the cookie is received and saved in the browser and all subsequent requests send the cookie along to the server. There is a 'User' service/object that saves the isLoggedIn and username values (for UI display/flow). Now, if I refresh the 'index' page, the app restarts. This means that my 'User' object will be cleared. I can check the existence of the cookie and, if it exists, I can re-set the User.isLoggeIn as true and go from there, but I still need to get the username, id, etc. So, my question is: should I create some sort of 'ping' endpoint in the API to verify if a cookie is valid? And if so, the API would send me back the user id and username... OR should I persist the user data in LocalStorage (or some similar cross-browser thing) and just assume the user is logged if the cookie exists? Any other subsequent requests to pages that need authentication would be automatically verified. So, this question really only applies to the scenario where the user refreshes the index page - hence, restarting the web app. I want to know the user data because I want to show a 'user homepage' instead of the 'public homepage'.
What do you think?
You should depend on the server for this. Creating something like GetCurrentUser method on the server. If the user is logged on this returns all the properties of the user.
You should even use this server api to get the user data after authentication completes. So the authentication become two step process first the user is authenticated, on success another call is made to server to get current users details.
Using client side local storage for this would not be ideal because you need to do lot of book keeping, in terms of cleaning the logged in user on log out or session expiration.
Also cookies from server would have expiration times an all, and making decision just based on cookie existing on local storage may not be optimal approach.
I'm maintaining a system built in ASP.
The login process is in SSL. Meaning, when the user clicks on "Login", his user name and password are sent securely to the server.
The login process produces a Session object, which is the ID of the now logged-in user.
After finishing the login process, the page redirects the browser to a non secure page. This page tries to access the ID Session object.
Until last week, this worked fine. Our system was running on IIS6.0, and the non-secure page could access this Secure ID Session object.
However, after switching over to IIS7.5, this inevitable security hole was closed(or so I assume). The non-secure page cannot access the Secure ID Session object anymore.
Access to the object is done simply like this:
string ID = Session(SESSION_USER_ID)
just to check things out, I tried access a non-secure Session object from the Secure login pages - this failed as well.
Is there any way to access a Secure Session object from a non-secure page?
BTW, I've probably mistaken with some of the terms here, but I think the scenario is more or less clear. Please tell me if this is not the case.
I've come across this problem before, I ended up getting around it by, when changing into or out of SSL, calling a function that would write the session variables to cookies, and then read back from the cookies into the SSL session variables.