If I want to protect an action for being accessed by everyone except one user, how do I do that?
So let's say a user has a product. When they go to the EditProduct action, how can I prevent anyone else from accessing it? In the past I always used User.Idenity.Name and compare dthat to their username. But if someone logs in as username instead of UserName then the case breaks even though it's the same user.
Using .ToUpper() or something like this on every check seems very flimsy and inefficient.
You can put an Authorize attribute above the action like this:
[Authorize(Users = "username")]
I'm not completely sure if it is case sensitive, but this is the best method for protecting actions and controllers. In addition, you can do the same with Roles:
[Authorize(Roles = "Administrator")]
String has a property for Equals:
User.Identity.Name.Equals("OtherName",StringComparison.CurrentCultureIgnoreCase)
Related
Assume I have a site with a unique URL for users, e.g. abc.com/user1.
I want users to be able to create their own user urls like abc.com/user1 to abc.com/foo
The problem here is that my site has static pages such as: about, help, contact, download.
On the profile page, when users change their url, i apply this validator to their new profile url:
'username' => 'required|alpha_dash|max:20|min:3|unique:users'
In this situation, if the user chooses their new profile url to the same as a Route of my app (help, about, download...), their URL looks like: abc.com/about, this is troublesome.
Of course, the Validator will return true because that name is valid: min=3, max=20 and unique in "users" table ( "users" table not contains any control, of course).
To solve this, I add name of some Route to "users" table (about,contact,download...), so they cannot make their profile URL like abc.com/about,
But this is not good idea, because I might add more Routes in future.
PS: I dont like URL like abc.com/profile/user1, must be abc.com/user1.
Please help me to solve this.
You can use Route::getRoutes() to get all registered routes in your application
$routes = Route::getRoutes();
foreach($routes as $route){
echo $route->getUri(); // getUri will return the url pattern it matches
}
Now you can use this to check if the username doesn't appear in your routes.
But be careful! If you want to add routes in when the application is running you will have to check everytime that there's no user that has taken the name you want to chose.
Here are some possibilities
1. Call static page routes first
You can either call the static routes first and then at the end you do a catchall like lukasgeiter suggested, or you might even do a check in the controller and go through your static pages first. The problem here is that the user can create the user (e.g. "about") but then when they call that page, they would see the about page, even though they've correctly created the username, this might create a confusion.
2. Blacklist
Another way would be to create a blacklist for these usernames, so that people can't even register these types of usernames (this would be similar to your solution of pre-creating those usernames, but this way would be a bit cleaner and more easily expandable). Using this you will always have the trouble that someone will have used the username, once you want to use it as a static page. E.g. when you want to expand into another country.
3. Static pages on one level lower
E.g. you can create the static pages one level lower, such as abc.com/static/about, so there would be no clash.
4. Prepend character before username
This is the way I went, because the other ways were technically a bit too risky for me. So I chose the '#' sign for my users. So abc.com/#ThisIsMe is my current solution. It works in different languages (as opposed to abc.com/profile/thisisme would only work in languages, where profile is the correct term)
I think Flickr went from flickr.com/username to flickr.com/photos/username. Google+ doesn't really let you decide, but makes suggestions (AND adds the +). Twitter and Facebook let users choose their own, I would assume they have a blacklist. LinkedIn uses /in/.
I'm trying to figure out how to view a profile-page in codeigniter. I know how to create templates and so on in CodeIgniter, but I don't know which way to go to handle "translation from username to userid" in a secure manner. This is a profile that should be viewed when the user isn't logged in (public profile).
Code snippet from my profile-controller:
$username = uri_segment(3); //Here's the actual username is stored in the url
$profile = new Profile();
$this->user_id = $profile->getUserByUserName($username);
Above seems ok, right? But when a username contains spaces, the "username-link" gets from "Gustav Wiberg" to "gustav-wiberg" (space replaced by hyphens, and the username is lowercase).
The actual link could look something like this: http://www.domain.com/profile/gustav-wiberg
But if I check this link with uri_segment I get username "gustav-wiberg" and not "Gustav Wiberg" which is the REAL username I want to compare with (by getting the return value of $profile->getUserByUserName($username);.
Am I taking the wrong approach to this? Or is it ok approach based on each username must be unique.
I could just do a replacement from uri_segment "gustav-wiberg" by capitalizing each word and replacing hypens with space and then do my query to check id for that username?
Please give me any pointers...
Either you can put a check while creating the username that there should not be spaces i.e. User can create a URL friendly username.
Or as you mentioned, you can do a replacement from uri_segment. But thinking of different scenarios, this approach can create issues so it seems its better to create a url friendly username.
One more option is you can add one more field in DB along with the username, say "slug". Wherein you can convert the username to URL friendly name and store. And check for that name while retrieving.
I am trying to create a suitable authentication check for a CakePHP service. Currently it appears that the user session is created initially during login, but never checked beyond this during a single session.
eg. Renamed the username, changing the password or ID in the user's database entry has no effect on the session.
Is there a preferred method for this type of, constantly checked, authentication? Essentially the user should be confirmed access at every request.
My current solution would involve extending the AuthComponent and storing a hash of the user data (including the encrypted password) and checking this at every request. I also considered storing the session ID in this same token, but noticed that CakePHP does not even use the session_start() function.
This functionality appears necessary for me, and I would have thought others would also require such a solution. I have yet to find Cake documentation or community solutions similar to what I need.
Well, you can use isAuthorized() function from AuthComponent. It's being called with every request.
public function isAuthorized($user){
return true; //allow the user to see the page
}
You can debug($user) to see the actual data and if you want "new" information from your database, you can always get them like this:
public function isAuthorized($user){
$current_user_from_database = $this->User->findById($user['id']);
if($current_user_from_database['User']['username'] != $user['username']){
$this->Session->setFlash('You\'ve changed the username. Please, login again.');
$this->redirect($this->Auth->logout);
return false;
}
return true;
}
Look at the API for more info and from the PDF book. You can look at this video about AuthComponent too. It's great.
If you need any more information or help, feel free to ask.
Btw. you have to configure AuthComponent in your Controller if you want isAuthorized() function to get called with every request.
If Session.timeout will work correctly with a setting of zero minutes, you're set. http://book.cakephp.org/2.0/en/development/sessions.html
I am developing an ASP.Net MVC 3 Web Application. Within some of my Views I display tabular data to the user, and beside each record in the table there is an Edit link. When the user clicks this link it takes them to an edit page where they can edit and update the record.
My issue is that once the user clicks the edit link, the URL becomes something like this
http://www.mytestsite.com/myData/edit/3
The '3' is the ID of the record to be updated, however, there is nothing stopping the user from changing the '3' to another digit, and this then means they can edit potentially a record which does not belong to them.
Does anyone have a solution on how I can prevent this from happening?
Thanks for you help.
You need to introduce Authentication and Authorisation into your application. Here is one article of many out there on how to get started with this. You will additionally need to work out how to store logged on user identity and then how to attach this to the record when it was created in the first place. You must then validate, on the server, that the subsequent edit request is being made by the user who created the record in the first place (or by a user who has a role on your system which allows them to do this, such as an Administrator).
Even if the ID wasn't being displayed on the URL a malicious user could still manipulate the HTTP Request to pass an ID of their choice. In any secure system you should always, always, always validate that the currently logged on user genuinely has permission to carry out the requested action. You should never rely on what comes back from the browser to determine this (aside from the authentication context which is managed securely by the MVC framework. Usually).
I believe you should have the information about who have the edit permission on this purticular resource, in your tables. Ex : in your table you might have the "CreatedById" column where you store the ID of the user who created this record. Now in your edit action method, you check the "CreatedById" of the current Item is same as of the "UserId" of the Current user (you maye get this from the session, if you stored it there). Something like this.
public ActionResult Edit(int id)
{
int currentUserID=1; // TO DO : get this value from session or somewhere
ProductVieWModel product=myRepo.GetProduct(id);
if(product!=null)
{
if(product.CreatedById==currentUserID)
{
return View(product);
}
else
{
return View("NotAutherized");
}
}
return View("ProdcutNotFound");
}
You should try using the GUID data type as it helps in these kind of situations, and the user cannot easily guess the next value
I have two tables, users and tokens.
Each user have a activated field and each token have the {id, token, user_id, created} fields.
The way the app should work is:
On the creation, the app will -
make sure that the activated field is empty (to avoid manipulations to the submitted data).
a token will be created in the tokens table.
On update, the app will -
NOT create a new token.
NOT allow an update of any kind to the activated field.
check if a new email has been submitted, and if so: will create a new token and set the activated field to false.
I know how to activate the account through the controller and how to setup the router for that.
What I need is mainly the model configuration.
For example:
I think that the token creation should be done in the afterSave method, so - how do I determine if the method is called by an update or by a create operation?
Thanks for any help
yossi you can also specify the fields that should be saved from the form though - a whitelist of fields it is ok to save in you $this->save() call. That way you can stop a hacker passing an ID in the request, and you should just set it in the controller yourself then with $this->Token->id = whatever you have, I would personally use saveField ('activated) in conjunction with this (just saves a single field!). Fat models is best if you can but get it working first then refactor it if you have got stuck. Better than wasting lots of time writing perfect first time.
You question is unclear. If you have a default value for a field, then why not set it in the database rather than doing something in aftersave? If you need to do something that should be done only in certain circumstances, then write a custom method in your model to perform the tasks you want either on creation or update.
Edit
So, if your record has an id, then you know it exists in the database. So, the simple thing to do is (in any method) check to see if the model has an id field and that it is not empty. If it's empty, then you know that you are creating a record and you can do x task. If it isn't, then do y task.
if(isset($modelData['ModelName']['id']) && !empty($modelData['ModelName']['id'])){
//This is an update
} else {
//This is a new record
}