I’m building a small application that will have multiple users using ASP.NET MVC, but I’m not sure how to handle user authorisation in the scenario below. I may be missing something obvious as I’m still learning, so any advice is appreciated.
Basically, to illustrate my problem, consider that I’m building a very small email like messaging system. Here is the action to read a message:
/Message/ReadMessage/1
Where Message is the controller, ReadMessage the action and 1 is the MessageId.
Now this message was for “Bob” and in the db his UserId is stored with the message. Another user called “Fred” has also received a message and the MessageId for this is 2.
In my application, there would be no way for Bob to see Fred’s messages on the page directly or through links (messages should be private to each user), so what is the best way for me to protect from Bob simply changing the MessageId in the URL manually from 1 to 2 and viewing Fred's message?
As a current solution to this, I have a very simple check at the beginning of my controller action which compares the UserId stored with the message to the current UserId and if they don’t match, the user is redirected (to say, their inbox).
Is this a suitable solution for such a scenario? I get the feeling that while this works now, it isn’t the best approach to this problem. Thanks for the help.
your controller needs to check that the current user is allowed to access the resource ( message in this case )
Related
What is the best-supported approach for tracking logged-in Usernames/Ids in App Insights telemetry?
A User with Username "JonTester1" said some Pages he visited 4 hours ago were really slow. How can I see everything JonTester1 did in App Insights to trouble shoot/know which pages he's referring to?
Seems like User Id in App Insights is some Azure-generated anonymized thing like u7gbh that Azure ties to its own idea of the same user (thru cookie?). It doesn't know about our app's usernames at all.
I've also seen a separate field in App Insights called Auth Id (or user_AuthenticatedId in some spots), which looks to sometimes have the actual username e.g. "JonTester1" filled in - but not always... And while I don't see any mention of this field in the docs, it seems promising. How is our app's code/config supposed to be setting that Auth Id to make sure every App Insights log/telemetry has it set?
Relevant MS docs:
https://learn.microsoft.com/en-us/azure/azure-monitor/app/usage-send-user-context
This looks to just copy one library Telemetry object's User Id into another... no mention of our custom, helpful Username/Id anyway... and most in-the-wild examples I see don't actually look like this, including MS docs own examples in the 3rd link below; they instead hardcode get a new TelemetryClient()
https://learn.microsoft.com/en-us/azure/azure-monitor/app/website-monitoring No mention of consistently tracking a custom Username/Id
https://learn.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics#authenticated-users Shows some different helpful pieces, but still no full example. E.g. it says with only the setAuth... JS function call (still no full example of working client-side JS that tracks User) on the page, you don't need any server-side code for it to track custom User Id across both client-side and server-side telemetry sent to Azure... yet then it also shows explicit code to new up a TelemetryClient() server-side to track User Id (in the Global.asax.cs or where?)... so you do need both?
Similar SO questions, but don't connect the dots/show a full solution:
Azure Insights telemetry not showing Auth ID on all transactions
Application Insights - Tracking user and session across schemas
How is Application insight tracking the User_Id?
Display user ID in the metrics of application Insight
I'm hoping this question and answers can get this more ironed out; hopefully do a better job of documentation than the relevant MS docs...
The first link in your question lists the answer. What it does show you is how to write a custom telemetry initializer. Such an initializer lets you add or overwrite properties that will be send along any telemetry that is being send to App Insights.
Once you add it to the configuration, either in code or the config file (see the docs mentioned earlier in the answer) it will do its work without you needing to create special instances of TelemetryClient. That is why this text of you does not make sense to me:
[…] and most in-the-wild examples I see don't actually look like this, including MS docs own examples in the 3rd link below; they instead hardcode get a new TelemetryClient()
You can either overwrite the value of UserId or overwrite AuthenticatedUserId in your initializer. You can modify the code given in the docs like this:
if (requestTelemetry != null && !string.IsNullOrEmpty(requestTelemetry.Context.User.Id) &&
(string.IsNullOrEmpty(telemetry.Context.User.Id) || string.IsNullOrEmpty(telemetry.Context.Session.Id)))
{
// Set the user id on the Application Insights telemetry item.
telemetry.Context.User.AuthenticatedUserId = HttpContext.Current.User.Identity.Name;
}
You can then see the Auth Id and User Id by going to your AI resource -> Search and click an item. Make sure to press "Show All" first, otherwise the field is not displayed.
Auth Id in the screenshot below is set to the user id from the database in our example:
We access the server from azure functions as well so we set the user id server side as well since there is no client involved in such scenarios.
There is no harm in settting it in both places, javascript and server side via an initializer. That way you cover all scenario's.
You can also manually add user id to app insights by
appInsights.setAuthenticatedUserContext(userId);
See App Insights Authenticated users
I am trying to figure out what the basic steps are for getting data passed between users. For example, say I, a user of the app, want to send another user of my app a message or a geopoint or some other form of data. I know the first step would be posting the data to Parse, which I don't have a problem with. But then, how would the other user know there is data to retrieve and also how would they go about retrieving it. Are push notifications the proper and only way of letting the recipient's app know its being sent something? When the recipient app knows there is data posted intended for it to retrieve, how does it go about locating it with a PFQuery? Does the posting app need to supply the receiving app with a UID of some form that the receiving app can then use in its query to locate the data? This is kind of the last puzzle piece for my app and unfortunately it's the only thing Parse didn't make clear to me. It is more than likely user error on my part not finding the correct documentation but, app to app communication is key in most apps and so I need to figure out the defacto way that Parse accomplishes this. Thanks in advance for any help!
You can have a relational table lets say "Messages" table in Parse,
with properties, sender (Pointer to a User), recipient (Pointer to a User) and message (String). and maybe a 'read' Boolean.
You could then query the messages table, With something like:
PSEUDO:
get all messages where recipient is equal to logged in user.
and display these messages on the UI.
Its pretty straightforward, I have done simple messaging service with Parse before
Thanks guys! In the end, I think it is best for a device to not have to be querying for changes but rather to be notified when it has new data to retrieve. Thus, for my uses, I think a combination of your answers, especially with the "onSave" hook function mentioned by Bruno, is the best solution.
I am working w/ the Event Brite API and I have a need that I am trying to figure out the best approach for. Right now, I have an event that people will be registering for. At the final step of the registration process, I need to ask them some questions that are specific to my event. Sadly, these questions are data-driven from my website, so I am unable to use the packaged surveys w/ Event Bright.
In a perfect world, I would use the basic flow detailed in the Website Workflow of the EB documentation, ending upon the "3rd Party Next Steps" step (redirect method).
http://developer.eventbrite.com/doc/workflows/
Upon landing on that page, I would like to be able to access the order data that we just created in order to update my database and to send emails to each person who purchased a seat. This email would contain the information needed to kick off the survey portion of my registration process.
Is this possible in the current API? Does the redirect post any data back to the 3rd party site? I saw a few SO posts that gave a few keywords that could be included in the redirect URL (is there a comprehensive list?). If so, is there a way to use that data to look up order information for that order only?
Right now, my only other alternative is to set up a polling service that would pull EB API data, check for new values, and then kick off the process on intervals. This would be pretty noisy for all parties involved, create delay for my attendees, and I would like to avoid it if possible. Thoughts?
Thanks!
Here are the full set of parameters which we support after an attendee places an order:
http://yoursite.com/?eid=$event_id&attid=$attendee_id&oid=$order_id
It's possible that order_id and attendee_id would not be a numeric value, in which case it would return a value of "unknown." You'll always have the event_id though.
If you want to get order-specific data after redirecting an attendee to your site, you can using the event_list_attendees method, along with the modified_after parameter. You'll still have to look through the result set for the new order_id, but the result set will be much smaller and easier to navigate. You can get more information here: http://developer.eventbrite.com/doc/events/event_list_attendees/
You can pass the order_id in your redirect URL in order to solve this.
When you define a redirect URL, Evenbrite will automatically swap in the order_id value in place of the string "$order_id".
http://your3rdpartywebsite.com/welcome_back/?order_id=$order_id
or:
http://your3rdpartywebsite.com/welcome_back/$order_id/
When the user completes their transaction, they will be redirected to your external site, as shown here: /http://developer.eventbrite.com/doc/workflows/
When your post-transaction landing page is loaded, grab the order_id from the request URL, and call the event_list_attendees API method to find the order information in the response.
I'm stuck figuring out the best practice...
I want to create a "following" system in a way that a user can follow a car (getting email updates when car price changes, etc). The part of implementation that's giving me headaches is when I want to introduce lazy registration by only using email.
Everything needs to work as AJAX requests.
In the interface, there will be a button to trigger the follow action, which will check if the user is registered or not. If a user is logged in, create a new CarSubscription item, otherwise display a form where he could type his email address. Once submitted, the form should create a user with no password (if email exists, ask for the password and log in) and then it should create the relationship item.
The challenge here is to use redirection after submission of the form to the CREATE action of the CarSubscriptionController. Since I can't redirect using POST I can't simulate the CREATE or DESTROY action.
The non-RESTful solution would be to create 2 actions under cars_controller: follow and unfollow and let them do the logic of creating entries and deleting them. That would enable me to just store the request path and use it after the user enters their email and logs in.
How can I achieve what I want using RESTful resources?
After trying to describe my problem here, it seems it's way too complicated and I am indeed very stuck... There are 3 different controllers and possibly 4 requests in this scenario.
Any help would be tremendously appreciated!
Please see my flow chart below:
Not an expert here, I don't know if it's the best solution, but what I have done in similar situation is :
In your controller, respond with javascript instead of redirecting the user
In your javascript file, use $.post(...) to issue a POST to your controller action
Et voilà!
You can also use ActiveResource to achieve this, but I actually never tried that solution : http://api.rubyonrails.org/classes/ActiveResource/Base.html#label-Custom+REST+methods
Person.new(:name => 'Ryan').post(:register)
Hope this helps
I had a very similar need and had trouble pulling the various bits of info on how to do this with Devise and Rails together into a working example. Here's a fully working example based on Rails 4, Ruby 2, and Devise 3.0:
https://github.com/mwlang/lazy_registration_demos
I'm designing (and developing) web software that will allow the general public to sign up for a service, become a customer, and exchange fairly sensitive data.
I'm working through the documentation and the tutorials, and of course the RESTful pattern adopted by the default routing in ASP.NET MVC is to do URL's like this: /customer/edit/3487.
I guess I am a little squeamish about displaying such technical details as customer ID in the URL bar.
What do the smart kids do these days? Does RESTful have to mean "put your record ID's on display"?
Edit: In an ASP.NET WebForm I would have stored this in the session, I think. But I'm finding that this is discouraged in ASP.NET MVC.
Edit:
I do not intend to rely on security through obscurity.
That still doesn't mean its a good idea to give the users any ideas, or any information about the underlying data. Let's say I have an app that's publishing information about the different business in a Chamber of Commerce, to be arbitrary. Once you are logged in, you have an administrative right to click on every business in the directory and see them all - but the application is supposed to spoon feed them to you as search results or the like. Just because the user technically is allowed to access all records, this doesn't mean it should be trivial for you to write a screen scraper that downloads all of my content in a few minutes. As well, the user can just look at customer ID's and make a guess about how many customers I might have. There's lots of good reasons not to display this.
As long is there is proper authentication and authorization being done on server side then displaying ids is not an issue.
Otherwise just try to encrypt the particular id or username in the URL, this way it will be difficult for the attacks.
You don't have to put the Id in the Url, you just need to use a unique value or unique combination of values to find the data you want to display.
I'd think that the actual bussinesses name would be good and also look good in the Url. So you would have something like this:
/Business/View/theouteredge/
Or if the business name is not unique you could use a combination of business name and zip/postal code.
/Business/View/theouteredge/78665/
You would have to write a new route to handle this.
routes.MapRoute(
"Bussiness",
"Business/{Action}/{name}/{zip}/",
new { controller = "Business", action = "Index", Name = "", PostalCode = "" }
);
All this action would need to be secured with the [authorize] attribute, or the controller its self.
If you also decorate your actions with [authorise] then if another user does use the id from another user, they will automatically be challenged for a login.
It's 6 of one and 1/2 dozen of the other as to whether you use an ID or a Name. Eventually they both resolve to a record.
The important thing is to only allow authorised persons to view the data by allowing them to log in.
I've got a site which has sensitive data but only if you are the holder of that info can you see it and I do that by decorating my actions and checking rights etc.
I think that putting an ID in a url is fine -- as long as it is a Surrogate Key. The key has no value, except to identify a record. Just make sure that the requester is authorized before you send sensitive data back to the client.
Update:
I can see how having a number as part of your URL is undesirable. After all, a URL for a web app is part of the user interface, and exposing such internal details can take away from the UI's elegance. However, you are faced with limited options.
Somehow, you have to identify the resource that you want to get. The crux of REST (IMO) is that a request to a server for a particular resource must be described entirely by the request. The key for the item you want has to be encoded into the HTTP GET somehow. Your options are: put it into the URL somehow, or add it to a cookie. However, adding a key to a cookie is frowned upon.
If you look at this site you will see the question id in the url. If you view your profile you will see your username. So you would probably want to use usernames intead of an id.
If you're really concerned about it you can use a Guid, which isn't very user friendly but would be very hard to guess. :)
If you use some other way than customer id simply because you're concerned about security, then that means you're using security through obscurity, which is a bad idea. Proper authorization would require something like you either 1) have to be logged in with that customer id, or 2) be logged in as an admin, to have that request succeed.