How can I transfer some data between ActionMethods without using TempData or the Db - asp.net-mvc

I have a controller action which returns a password protected zip file to the user when the click a link. The password is generated randomly.
If the download is successful, I'd like to then call another action method on the controller to get the password and display it on the screen. I'd be happy to do it all in one request but it doesn't feel possibly in a non horrible way.
I'm using this library to download the file jquery download library
I can't use tempdata or session state and hitting the database feels a little bit like using a hammer to crack a nut. I've thought about storing it in the response or a cookie but that feels a bit wrong too.

URL or hidden field should do (that is, they are both user-stored either as part of POST or GET request).
The question is, how can you return the password to the client and start the download at the same time. If there's no server storage you can't do it, since they are separate HTTP requests (unless you use cookie). I think this is the best way to do it:
Open your download page, and generate the password at that time,
so you can put it in hidden field (for successCallback of jquery
download library)
When calling your server to download the file,
pass the password as get or post to the download URL, and use this
password to compress
Once download finishes, you know what the
password was, so you can redirect to another page and show it.
Actually, since you already have it on the page, you can show it
right after download using javascript. Or maybe you can just show
the password right away, while download is still happening.
So, this is probably reversal of your architecture. And possibly this is not acceptable (you may want to generate secure passwords and guarantee users don't mess with them - that's possible if you pass the password in the download request). But that's the only way without server or cookie storage.

use
return RedirectToAction("Action", new { id = 99 });

Related

Prevent browser from caching link destination

I have an ASP.MVC application. There are some sites in the application which are accesible only with certain user permissions. If user doesn't have required permissions I am redirecting to another controller and displaying page with Not authorized message.
When user without permission tries to visit restricted page using a link, browser caches destination. So always after clicking this link user will be redirected to Not Authorized page, even if permissions are granted. Browser skips directly to cached destination.
I have disabled caching on server side but, this doesn't seem to work in this case, any ideas how I can prevent browser from remembering links destination?
Thanks in advance,
Konrad
There's no logical reason for such a behavior to occur. First, check to make sure that the user is authorized like you think they are and that your redirect code is functioning properly (such that it only redirects if indeed the user is unauthorized). Short of that, make sure you're using a temporary redirect, and not redirect permanent. Although the browser shouldn't decide to just cache the resulting page indefinitely either way, it would perhaps have more cause to think it could if you're sending a permanent redirect.
Without seeing your code I'm not entirely sure there isn't something else going on, but here's a thought:
You can programmatically construct a hyperlink in your razor page to build a unique URL each time the page is refreshed. Just tack on a ?token=#uniqueVar onto the end of the url. The token need not be used in any place in your code, but if your uniqueVar is a timestamp or a Guid or something, your URL will be different every time.

multipartFile request from a redirect

Is it possible to run a request command on a set of multipartFile objects for a set of selected files that has been passed to an second action from an initial action that received them from an type file input html tag.
I can access the multipartfile object as a string in the redirected (second) action -
Such as:
form:org.springframework.web.multipart.commons.CommonsMultipartFile#35d79259
But I am unable to run a request command such as request.getFiles - also I cannot cast it as a MultipartFile.
The redirect to intentional - let me explain what I'm trying to do in more detail:
I have a file upload web page with an input form that sends the selected files (multpartFile objects) to the action. Prior to uploading the files from the client I want the user to have a web page where he adds extra data to each file prior to uploading (metadata tags). To do this I was going to redirect to another action that displays a web page with the list of the files (having transferred the params data that contain the files selected from the original web page to the redirected action) and input fields for the user to add tags. In short the redirect is intentional.
I guess the correct way to do this is using js on the original web page - just wanted to see if I could do it this way instead?
-mike
In general redirects use GET, so there's nowhere for the form body and uploaded file(s) to go. POST/UPDATE/DELETE actions make changes, and a redirect is typically an indication that something went wrong, e.g. something mild like a url changed (301/302), or something more serious like an authenticated user trying to access a page they have no permission for, or an unauthenticated user trying to access anything guarded (401/403).
You wouldn't want to pick up where you left off from a lot of scenarios that trigger a redirect (and it wouldn't be practical at all) so it's common to not attempt to do anything with form or file upload data and let the user re-do the action.

How to authenticate Rails application using token from 3rd party API?

I have a Rails application that make several user-specific calls to a third-party API. They interact with a lot of data in the course of filling out a survey, and their progress is stored in HTML5 localStorage until they reach the end of the survey and the data is saved in a local database & localStorage cleared.
The API calls require a token tacked onto the end as an "auth=" parameter. Right now, I have the user log into my app with their username and password to that service, POST those credentials to the "sessions" call of that API, and get a token back in JSON. I store that token in a variable in the controller, and use it to make the successive API calls and present the user's data in my app, etc. etc.
I've learned quite a bit about Rails, but next to nothing about sessions or authentication. Generally speaking, is there anything more I need to do for this to be a secure scenario? I feel like I'm missing something.
Assuming the user's username / password combination for the 3rd party service doesn't hit your servers, seems OK to me.
If your servers see the user's credentials, that's not particularly cool. Instead use OAuth to get 3rd party sign in, and use the token to make requests on behalf of the user. You can usually keep the whole session on the client if you want to avoid saving users to the database.
Storing progress in localstorage sounds fine btw. To preserve values you can have the pages of the form be tabs (so hide the previous form, not a new page) and use:
autocomplete="on"
to signify that the values should be restored to what they were. Try that before writing code to save things to localstorage.

How do I prevent double-clicking in ASP.NET MVC without using JavaScript?

Yes others have asked similar questions, however, the end solution was using JavaScript. I have that working, my question becomes what happens when the user has JavaScript turned off? I would hope only advanced users would be turning off JavaScript and thus know to know click once on a button and can tell that the server is working. On the off chance they don't, how do I make sure that button is only clicked once?
I should note that this is on a payment form.
I'm afraid without JavaScript there is no way to prevent this. If the click results in a POST request, then you can try to make it idempotent on the server side.
You cannot make sure the button is only clicked once, as you have no control over user's browser. What you can do, though, is to add a hidden field, a token to your forms so that if you see a token you've already seen, you'll be able to return an already-calculated answer.
Update: In case of payment processing, it's not even a technique for preventing double submission—it's a technique protecting your clients from fraud. Check out OWASP's A5: Cross-Site Request Forgery (CSRF):
Preventing CSRF requires the inclusion of a unpredictable token in the body or URL of each HTTP request. Such tokens should at a minimum be unique per user session, but can also be unique per request.
The preferred option is to include the unique token in a hidden field. This causes the value to be sent in the body of the HTTP request, avoiding its inclusion in the URL, which is subject to exposure.
The unique token can also be included in the URL itself, or a URL parameter. However, such placement runs the risk that the URL will be exposed to an attacker, thus compromising the secret token.
Basically, each time you receive a payment form, you want to make sure it's a legitimate response to the form you've shown. Handling double submission comes free with security—a rare case indeed! ;)
what happens when the user has JavaScript turned off?
The server is hit twice and there is not much you could do about it.
Now depending on what you are doing on the server there are different ways to react. For example in a RESTful application if you are using a POST verb which modifies some state on the server and is neither safe nor idempotent it is eventually the underlying data source that will detect the anomaly and simply throw an exception which will be gracefully reported to the user telling him that his request was already submitted.
For a simple and small ASP.NET MVC app, I find using the HttpRuntime.Cache is enough:
Function SomeAction() As ActionResult
Dim cachekey = "uniquecode"
If HttpRuntime.Cache(cachekey) IsNot Nothing Then
' wait until the other request is finished
Do
Threading.Thread.Sleep(1000)
Loop Until HttpRuntime.Cache(cachekey) Is Nothing
End If
HttpRuntime.Cache.Add(
cachekey, "", Nothing,
DateTime.Now.AddMinutes(5),
Cache.NoSlidingExpiration, CacheItemPriority.Low, Nothing)
Try
' do stuff
Finally
HttpRuntime.Cache.Remove(cachekey)
End Try
End Function
The cachekey must be the same for requests that you consider double, and must be different from all the other requests. If you check that the cachekey is already in the cache, tell the thread that is processing the request to wait (or throw error).

HTTP POST Request, HTML Form input (login: user/password) browser simulation

I'm trying to login to a website (http://www.meo.pt/ver/Pages/login.aspx) from within my application so that I can access the program listing, etc, I searched in the page source code for the html for of the username textbox and password textbox input.
<input name="ctl00$SPWebPartManager1$g_cb264700_1517_426f_926d_3ca40934a6fd$ctl00$EditModePanel1$txtUserName"
type="text"
id="ctl00_SPWebPartManager1_g_cb264700_1517_426f_926d_3ca40934a6fd_ctl00_EditModePanel1_txtUserName"
class="forms_login" />
I used the value in name and set the content of that key with the username and the same form the password. Then made a POST request to http://www.meo.pt/ver/Pages/login.aspx from which I got a response containing the HTML source of the same page, so login wasn't successful. I don't think the server even considered it a login try.
My question is how should I set the POST request values to make this work?
I'm using ASIHTTPRequest for iPhone.
My guess is that it's cookie-related: the page sends a cookie when it appears and requires that cookie along with the username and password. Odds are good that every POST and GET returns a cookie along with the page content, a cookie you'll need to send back.
If you use ASIHTTPRequest to perform the requests and use the same instance of the object to make subsequent requests, it will take care of sending those revised cookies each time. I love this library and recommend it.
http://allseeing-i.com/ASIHTTPRequest/
If instead you're using an NSURLConnection and prefer to manage the cookies yourself, the NSHTTPCookie object will help.

Resources