I have a Grails application using Spring Security.
This application is basically a content management system, so it is a CRUD.
My URL's access are basically formatted as follows:
/$controller/$action/$id
This is where encounters problems. That occurs in a controller, for example, to change a user I have the following URL:
/user/update/1
And into the controller I have the following code:
def update(Long id) {
def user = User.get(id);
[user: user]
}
That's the problem. If the user change the (id) directly without checking if the user id in request is correct, anyone can surf the users of my system. Now i have a big problem.
The solution that I thought would be to create a unique hash for each registration system, which would hinder the user to understand that, for example, the ID 1 has the hash 123aabbCCDD, for example.
But i have a lot of registers and many domains in the system, and i don't know if this is the best solution.
I need help to know, for example, using the spring security, I can do this kind of thing.
I tried to find solutions to the issue but I'm not sure by what words to search, so if there is already a question like mine, put the link in comments please.
Thanks.
As Joshua points out, if this is a general problem where you need to limit which users (or which roles) can perform particular actions, the spring-security-acl plugin will help. But that can be tedious to work with because you typically need to model things in a fine-grained way, and you end up with a lot of ACL data in the db.
But if you only want to restrict users to being able to edit themselves, just don't pass the user id. You already know who the user is if the action requires authentication. If that's the case, change the action to something like
def springSecurityService
def update() {
[user: springSecurityService.currentUser]
}
A related workflow that can often avoid using ACLs is allowing a user to edit something that they own, e.g. a CreditCard. Assuming you have static hasMany = [creditCards: CreditCard] in the User class and static belongsTo = [user: User] (or just User user), then you can allow the form to send the credit card id, but you just need to use a modified query, e.g.
def springSecurityService
def update(Long id) {
def user = springSecurityService.currentUser
def card = CreditCard.findByIdAndUser(id, user)
[creditCard: card]
}
The final SQL query will look something like select ... from credit_card where id=? and user_id=?, which has a big security advantage over the SQL for a get() call which would be select ... from credit_card where id=?. A malicious user can still try to send any id they want, but since the where clause checks both the id and the user foreign key, if they're not logged in as the card owner, the finder will return null and you can treat that as a mistake or a hack and not allow access.
Note that the hash approach you described isn't very secure - it's just "security by obscurity". If each user's hash is constant, it's not difficult to find out what a user's hash is and forge a request (e.g. a coworker can just look at another's monitor and see the url in their browser).
Related
How can I set up default roles in jhipster ? (using angularjs and spring).
I explain myself
in the registration page I want to specify the role for the registred user. let's say by a checkbox or a list. (for exemple human and animal )
How can I do that in the angular controller and in spring ?
What I can do now ?
I added the roles I need in the database and in angular and I can specify the roles for the new registred users , only through the Admin's users management page.
There is some work to do, to achieve that, so I will paste just the right parts with some small samples..
In general you must extend the API to become aware of a role selection, so this information can be provided explicitly. Then you change your angularJS frontend as you need.
for the backend
a registration happens by POSTing a ManagedUserVM to /api/account/register, so the first thing is to tell AccountResource.registerAccount(...) to pass a set of of strings (your roles) as additional parameter to userService.createUser
#Timed
public ResponseEntity registerAccount(#Valid #RequestBody ManagedUserVM managedUserVM) {
HttpHeaders textPlainHeaders = new HttpHeaders();
///...
User user = userService
.createUser(managedUserVM.getLogin(),
managedUserVM.getPassword(),
managedUserVM.getFirstName(),
managedUserVM.getLastName(),
managedUserVM.getEmail().toLowerCase(),
managedUserVM.getImageUrl(),
managedUserVM.getLangKey(),
//add authorities here
managedUserVM.getAuthorities()
);
mailService.sendActivationEmail(user);
//...
}
Then in UserService.createUser, you apply the set and add them to the user before saving it, by adding the Set<String> authorities to its parameters and
if (authorities != null) {
Set<Authority> authorities = new HashSet<>();
authorities.forEach(
authority -> authorities.add(authorityRepository.findOne(authority))
);
user.setAuthorities(authorities);
}
and this should be sufficient to pass authorities to /api/register/ and save them. You should be aware of users forbid to register themselves with ADMIN roles, but the security consideration is up to you and not part my answer.
apply to frontend
Knowing your API now can process also authorities, you could just pass them.
You just add some checkbox or selectbox with ng-model="vm.registerAccount.authorities" to src/main/webapp/app/account/register/register.html (if angularJS1) or
[(ngModel)]="registerAccount.authorities" tosrc/main/webapp/app/account/register/register.component.html` (if angular2).
AFAIK this should lead automatically to the angular services passing these authorities/roles to the API.
I hope my brief answer helps you to find the proper places! Feel free to ask in comments if you stuck
In asp.net mvc when creating, updating, deleting data how does one know that the data beeing manipulated does really belong to the user making the call?
[Authorize]
[HttpPost]
public ActionResult Edit(Model model)
{
// edit data in database
}
If a user is only to manipulate his own data but can see and easily find out information of other users witch is public to manipulate.
How can i be sure that the user is really who he says when for example Edit is called?
The Authorize only makes sure that a user has logged in.
I'm thinking about using controller.User.Identity.Name in the update to make sure the user how created the data is the one that changes it.
But then comes the question could it be possible for a user to go around this by manipulating controller.User.Identity.Name ?
How can one know that a user is who he says he is with regard to this?
There are two kinds of authorization.
One, which is very "vertical", has helpers provided by the framework (such as the Authorize attribute). This "vertical authorization" determines if a user is allowed to make a request or perform an action. It knows nothing of the data of the request or the action being performed, just the request/action itself.
The second, which is more "horizontal", doesn't have built-in helpers in the framework because it's subjective based on the business logic of your application. This one is up to you. This "horizontal authorization" determines if a user is permitted to manipulate specific data elements (specific records in the data) under specific conditions.
To put it simply... If a user submits a request to your application (invoking an edit action on a record for example) then while the framework can tell you if that user is permitted to invoke that action you need to manually determine if that user is permitted to edit that specific data.
For example, let's say two users create records in a table. In that table there should be a column indicating the user which created that record. (Username, some identifier, however you want to link it to a user.) This value isn't provided by the user when inserting the data, it's provided by your code when you build the record. You'd probably pull this value from the logged-in identity of the user (however you track username/id in the application).
Later, when a user attempts to edit a record in that table, you would need to validate that the user performing the action (again, based on their logged-in identity) is the user who originally wrote that record (based on the data that's in the table). Or an admin, or in some other way authorized to manage that data based on your business logic. None of this is based on values being sent from the client, it's all entirely server-side.
So while the client-side code may store an identifier for the record being edited, that value can be changed by any savvy user. That value isn't to be trusted. If a user requests a page, edits values, and submits that page then your server-side code would use the page-provided identifier to know which record the user is attempting to edit, but would use the logged-in user identity to determine if the user is allowed to edit that record. In the event that the user has manipulated the form values to edit somebody else's record, the server-side code should just respond with an error or friendly message denying that action.
This is a loaded question. You could do this with roles (if only Admins can edit). You can do this via user IDs (if you only want them to edit their own personal data).
It seems your question on more based on personal user data so lets go that route.
[Authorize]
[HttpPost]
public ActionResult Edit(Model model)
{
var userId = WebSecurity.CurrentUserId;
var previousRecdord = //Logic or service call to get previous record
if (previousRecord.AUthorId != userId)
{
//Do Something
}
else
{
//Edit something
}
}
You could even throw all of this into a service method and have a validate method that is called before the actions on the service are run. something like
[Authorize]
[HttpPost]
public ActionResult Edit(Model model)
{
var userId = WebSecurity.CurrentUserId;
var profileEntity = //some mapper that maps profile to entity
_UserService.EditUserProfile(userId, profileEntity)
}
and then in some service method:
public void EditUserProfile(int userId, profileEntity profile)
{
validateProfile(userId, profile);
saveProfile(profile);
}
private void validateProfile(int userId, profileEntity profile)
{
var previousRecdord = //Logic or service call to get previous record
if (previousRecord.AUthorId != userId)
{
//throw exp of some sort
}
}
Using MVC when registering a new user a record gets created in webpages_Membership and UserProfile
The UserId by default gets created as sequential number 1, 2, 3...
my model
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
}
When I go to edit the record in the URL it shows /profile/1
I want to change the id's value to something random e.g. profile/f8934hre987f8987f9f8 for security reasons.
Same thing I want to generate random number when details gets viewed by members so instead
/details/1 want it to be /details/783787483743874873
The ViewModel for displaying the details contains Id field as a primary key which is also gets generated sequentially.
I read using [GUID] is not great for performance.
Advice how to change it without affecting the performance? Suggestions. Thank you.
EDIT
Have similar like groupon site, when user attempts to edit his/her profile instead of showing /edit/1 have something like:
So user doesnt know how many records in the database or what record number the user is.
I am not 100% sure what you mean by something random. I am assuming that you mean encryption. Please take a look at this MSDN link for the details on encryption.
After that ,you can have your action method like /detail/{encrypteduserId}
Then you can have action method like below
public class Detail(string id)
{
var decryptedUserId = GetDecryptedId(id);
// GetDecryptedId gives the decrypted information.
// You can implement it based on the MSDN link
// You can use decryptedUserId to run queries on the database.
}
This way you can achieve your goals without making schema changes. This seems like a minimum possible friction approach.
There is no security benefit to having a random user id, so long as your site implements proper controlled access. That is, nobody should be able to access /profile/1 except the user with a user id of 1 (or another user who is authorized to do so, such as an administrator). All other users should get an error.
An even better approach is to not use an id at all. Simply get the current users ID and show the profile of the currently logged in user. Then user with userid 1 just goes to /profile and they see their profile, and user with an id of 2 goes to /profile and they see their profile and there is no way for one user to see the others.
That's not always possible however, for instance in maintenance screens where an admin is viewing other users profiles, but in that case only the authorized admin should be able to do that.
Obscuring the userid is a false sense of security, since the id will be visible anyways. You are simply fooling yourself if you think this adds any security value, unless you haven't implement proper security in the first place, in which case it's just hiding your real problem.
It also adds needless complexity, and confusion. It's equivalent to saying "I want to change the address of my house to a random number for security reasons". Think of all the problems that would cause, for dubious results.
Having the User ID displayed in the URL is a genuine security concern, be it a simple integer user id or some GUID (if that GUID can be used to identify a user). This is especially true in cases of Transport layer security (HTTPS) where the URL is not encrypted like the content is.
Here are a couple of ways I can think of going around this:-
1.) As suggested by Erik above, use User.Identity.Name to identify the currently logged in user. This wouldn't however work for the administrator accessing another member's profile. It would also not work for unauthenticated scenarios.
2.) Instead of creating a direct hyperlink, create a form which posts the user id as part of a custom type (model). Then use model binding to access the User ID as a property of the custom model object in the Action method. In this case, the user ID is submitted as part of the form and hence is transported over the wire encrypted (if HTTPS) and not visible in the URL. This would work in both cases where a member is trying to access his/her own profile, or when an administrator chooses a profile to access on screen.
An example of scenario 2::
public ActionResult EditProfile(UserProfile userProfile)
{
bool success = false;
if (User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
if (WebSecurity.UserExists(userProfile.UserName))
{
// your code to update profile here.
}
}
}
if (success)
{
ViewBag.Message = "Profile updated successfully.";
}
else
{
ViewBag.Message = "Profile not updated:";
}
return View();
}
Hello guys I having been keeping searching for answers for a few days and read couple of posts already but still quite confused.
I am using a user table with fields including First Name, Last Name, Email, Password, RoleID and other stuff like phone numbers etc.
Also I have a "role table" which has a Field standing for "Role Name" in string and few other fields stands for different Accesses of Boolean type such as "AccessToAlterItemInformation" which if a user with such roles who having (AccessToAlterItemInformation == True) will be granted with access to Item Editing page.
There are a few questions I want to ask about this topic:
codes like:
[Authorize(Roles="admin")]
were used to authorizing on several posts I saw but I want to do something more like
[Authorize(user.role.AccessToAlterItemInformation == true)] //I know this is not right but something similar
OR:
if (User.Roles.AccessToAlterItemInformation == True)
{
//Do something as Access granted
}
How could I achieve this? (or some other approaches which at least achieve something similar to that so I can make a website Authorizing according to different accesses)
-2. with the requirements as first question described above, I have to implement the member/user system with a MVC 4 Web Application with Razor using already created User Table and Role Table. How could I achieve that? I want to use as much as possible of whatever is already there (asp.net, simplemembership etc.) and make as little changes as possible because I really only have little time left for this project. Please help me! Thanks in advance!
And sorry for my poor English
You will have to define a custom Authorize attribute to do this.
[Authorize(user.role.AccessToAlterItemInformation == true)]
It should be changed to something like this.
[Authorize(Permissions = Access.EditItemInformation)]
where Access is a Flag enum and Permissions is a member variable (of type Access) in the custom Authorize attribute class you define.
you will also have to define the enum flag itself
[Flags]
public enum Access: ulong
{
CreateItemInformation = 0x00000002,
EditItemInformation = 0x00000004,
DeleteItemInformation = 0x00000008,
}
By using flags you will be able to give more than one flag as permissions
[Authorize(Permissions = Access.EditItemInformation || Access.CreateItemInformation)]
within the overridden AuthorizeCore method, you'll check if the permission member variable has different types of Access flags and return true if authorized and false if not. This is how you check if a given Access flag is in the Permission variable
Permissions.HasFlag(Access.EditItemInformation);
This is how you'd implement a custom authorize attribute
ASP.NET MVC 4 Custom Authorize Attribute with Permission Codes (without roles)
values of Enum Flags should be in power of 2. Please take a look at these articles to understand flags.
http://www.codeproject.com/Articles/13740/The-Beginner-s-Guide-to-Using-Enum-Flags
http://forums.asp.net/t/1917822.aspx/1?+use+of+Enum+with+flags+in+practicle+
Hope that helps
In my application I have a top level entity called Organization. The relationship between User and Organization is many-to-many.
Because of this I could have the following scenario:
UserA has role ROLE_ADMIN for OrganizationA
UserA has role ROLE_USER for OrganizationB
I need to ensure that when UserA accesses resources for OrganizationB he is not doing it as an ADMIN. So I need an additional check that the user has the correct roles at the organization level. Is there anything built into Spring Security that allows for this? If not, does anyone know what the best way would be to about solving this?
UPDATE: A bit more information...
A User logs in and chooses which org they want to work with. That is stored in the session. Beyond that, URLs are locked down with the Secured annotation. What that means is that if UserA were to log in and select OrgA, they should be able to access /admin/user/create however, if they log in and choose OrgB they should not have access to that URL.
The long way is to add additional checks in every method where this matters. So call some service method that says "ok, you're an admin for OrgA but not for OrgB and you're logged in using OrgB, so deny this request".
I'm hoping for a more grails / spring-security way of handling this.
You can probably do this by using a custom AccessDecisionVoter. The vote method will supply you with the "configuration attributes" for the resource (method or URL), which will typically be the required roles, and you can obtain the current user's roles/authorities either directly from the Authentication object, or by reading the current org and selecting the appropriate roles for the user.
I'm assuming that you have some way of differentiating the user's roles, based on the org they've selected.
Essentially, you'd be writing an extended version of the standard RoleVoter, which takes the organization into account.
I think I'm little late here but this is what worked for me:
When an organization is selected, you can set a new Authentication object with new roles in your session(The previous Authentication object gets invalidated). Something like this:
#RequestMapping(value = "/org-a")
String orgA(HttpServletRequest request) {
request.getSession().setAttribute("org", "org-a")
Organization org = new Organization("org-a")
reloadRolesForAuthenticatedUser(org)
....
}
private void reloadRolesForAuthenticatedUser(Organization org) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication()
List<String> newRoles = getRoles(auth.getPrincipal().getUsername(), org)
List<GrantedAuthority> authorities = getAuthorities(newRoles)
Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(),auth.getCredentials(),authorities)
SecurityContextHolder.getContext().setAuthentication(newAuth)
}
private List<GrantedAuthority> getAuthorities(List<String> roles) {
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>()
if (!roles.isEmpty()) {
for (String r : roles) {
auths.add(new SimpleGrantedAuthority(r))
}
}
return auths
}