I've managed to successfully implement a custom MembershipProvider for my MVC2 application. I have my own User table as well as Role table.
My problem right now is that when I put in the [Authorize(Roles="blah")] attribute, it doesn't work. I've searched a bit but haven't found a definitive answer I'm looking for, which is -- how does this Role authorization work? My web.config uses the standard AspNet role provider.
My understanding is that I have to have my User.cs class implement the IPrincipal interface, which means, adding the code to check for IsInRole.
My question(s) -- is this correct? How does the framework know to and know how to get my custom User object? My understanding is that the Asp.Net authentication & authorization pieces work with MembershipUser.
Any tips, thoughts, or links would be greatly appreciated,
Thx
Is your roles table / code an implementation of a RoleProvider? I believe the IPrincipal works against the default RoleProvider as configured in the web.config.
This forum post talks about what you would need to do in order to implement your own IPrincipal, if need be.
Ok, I think I figured it out, I'm just a little blind.
Since I created my own custom MembershipProvider (with its own custom User table AND Role table), it only stands to reason that I had to implement a custom RoleProvider. So, once I did that, it all makes sense, because the RoleProvider has the IsUserInRole method, i.e.
public override bool IsUserInRole(string username, string roleName)
{
IUserRepository userRepository = GetUserRepository();
User user = userRepository.Retrieve(username);
// and here, my User class implements IPrincipal
if (user != null && user.IsInRole(roleName))
return true;
else
return false;
}
Related
I have been implementing Jhipster at my work and loving it. I was asked to implement a security validation that one user should not be allowed to edit the entity created by other user. For this I need two things:
First, in all entities, add a ManytoOne relation with User entity.
In Backend put a validation in controller while updating the entity to check if current logged in user is same as what is stored in DB. In front end also same logic to show/hide edit button.
I have done a POC for this and it works but is little ugly, check the code:
public ResponseEntity<Entry> updateEntry(#RequestBody Entry entry) throws URISyntaxException {
log.debug("REST request to update Entry : {}", entry);
if (entry.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}
//here is my logic
Optional<Entry> entry_db = entryRepository.findOneWithEagerRelationships(entry.getId());
if(!entry_db.get().getUser().getId().equals(userService.getUserWithAuthorities().get().getId())) {
//throw someexception
}
//
Entry result = entryRepository.save(entry);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, entry.getId().toString()))
.body(result);
}
Is there any better or OOTB way of doing this??? may be something in spring security i am not aware of??
Thanks for help!!
This is a job for Spring Security Expression-Based Access Control, in particular you could annotate your method with #PreFilter and a custom PermissionEvaluator you would implement with similar logic as in your POC. The PermissionEvaluator could be generic and applied to several entity types if you define an Owned interface that models the ownership with a method like User getOwner() and that all your entity classes would implement.
See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-access
The annotated method should be in a service rather than in a resource controller.
Also, UserService alone will not help you in finding the current authenticated user, you should use JHipster's SecurityUtils first and then ÙserService if you need more data about it.
I've got an architecture issue that I'm hoping someone can be of assistance to guide me in a more ideal strategy. The way I've been forced to do this reeks of "code smell".
I've got two different kinds of "Roles". I've got the built in Identity Roles, and I've got a custom set of roles (User Group Roles). I store these User Group Roles in a database, essentially a relationship between a user id, a usergroup role id, and a usergroup id. I'm using Ninject for dependency injection of my UserGroupService that handles all the CRUD operations of assigning users with certain usergroup roles to usergroups.
My first plan of attack was to create a custom authorization attribute that I could place on actions, similar to the Identity [Authorize(Role="")] attribute. I did not have any luck with this because I cannot inject a service into an attribute class (needs a parameterless constructor).
After that didn't work, my second plan of attack was to write an extension method for IPrincipal, essentially mimicking User.IsInRole("") with User.IsInUserGroupRole(""). This didn't work because I cannot inject a service into a static class.
Currently I am stuck including some booleans in the model of every view that has role based logic involved. So for instance:
public ActionResult Navigation()
{
var isSystemAdmin = User.IsInRole("Administrator");
var isUserGroupAdmin = _userGroupService.IsUserGroupAdmin(User.Identity.GetUserId()) && !isSystemAdmin;
var isGeneralUser = !isSystemAdmin && !isUserGroupAdmin;
var model = new NavigationViewModel
{
IsSystemAdmin = isSystemAdmin,
IsUserGroupAdmin = isUserGroupAdmin,
IsGeneralUser = isGeneralUser
};
return PartialView("_Navigation", model);
}
The issue here is that I have to do this any time I want to determine what kind of roles the user is currently in. It works, but it smells.
Am I missing something here? I think the most ideal option would be the extension method strategy of being able to call it right off of User, but cannot seem to make that work.
Constructor DI is not the only way to get access to a dependency.
Each IOC has a way of resolving a dependency, all you need is a reference to the IOC container. So, even if your attribute requires a parameterless constructor you could still resolve the dependency manually.
Something like this should help :
http://www.c-sharpcorner.com/UploadFile/47fc0a/resolving-dependency-using-ninject/
Is it a great way to use your IOC this way? Probably not but it sure beats what you're doing now.
I got a problem as i am writing a custom SSO solution for my company. To mkae it simple, i've made a custom authentication httpmodule that intercepts all requests so as to check user authentication state. If not authenticated, user is redirected to my custom sso login page.
The thing is, when user is not authenticated, i'd like to check if he can access the requested page/resource... With Webforms, no problem, i add an authorization block in web.config, and i use UrlAuthorizationModule.CheckUrlAccessForPrincipal with an anonymous user. Everything works fine...
But when i apply my module to an MVC (3) web site, this does not work anymore (for obvious reasons, like the possibility to access the same controller and/or action from differents urls when using routing, and because authorizations are made through controller attributes).
How can I achieve this ?? I've been searching all day long, didn't find anything about that :/
ASP.NET MVC 3 Internet Application template includes a basic AccountController which implements the following actions (along with the associated models and views):
LogOn
Register
ChangePassword / ChangePasswordSuccess
You simply need the [Authorize] attribute on the Actions or classes you wish to secure. But if you need something really custom you can do something like I've done.
I created a custom class to override security in my application.
public class AuthorizeActivityAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
HttpContext currentContext = HttpContext.Current;
//Do your custom authentication stuff here and return true or false depending on results
Return true;
}
}
And now in my Controller I have the following:
[AuthorizeActivity]
public ActionResult Index()
{
ViewBag.Message = "Welcome";
return View();
}
I had the same problem.
See solution here: MVC equivalent of Webforms "UrlAuthorizationModule.CheckUrlAccessForPrincipal"
You would have to read the information from the other controller. This
can be done by instantiating its context and the Descriptor, then
instantiating the AuthorizationContext for that controller and read
the filter info.
How does the Authorize Tag determine if the user is authorized or not?
Like say, if a user logs in and they try to go to a view that has an Authorize tag. How does it determine if a user is authorized or not? Does it do a query to database and check?
How about if they go to a view with a role authorization? Does it query the membership role table?
I am just wondering since I have what the ASP.NET membership tables considers duplicate userNames. I use a serious of fields to determine which user is what, allowing users to have the same duplicate userName, but still be unique in my database.
This caused me to have to write custom methods for lots of .NET membership stuff since it all used "userName" to do searching instead of using the UserId.
So I am now wondering if this could be the case with the Authorize tag. Since I have no clue how it works and like if I was not using .NET membership I would not have a clue how it would determine it.
The Authorize tag uses all the built in membership checks from ASP.NET. It's VERY easy to roll your own tag. For example:
public class MyAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (httpContext.User.Identity.IsAuthenticated == false) return false;
// Do you own custom stuff here
bool allow = CheckIfAllowedToAccessStuff();
return allow;
}
}
You then can use the [MyAuthorize] tag which will use your custom checks.
ControllerActionInvoker parses the attribute and calls OnAuthorization() on it when it's time to check the credentials.
The AuthorizationAttribute.OnAuthorization() method basically checks to see if User.Identity.IsAuthenticated is true or not. This just draws on the functionality of FormsAuthentication or whatever other authentication scheme you may be using.
This seems like a pretty stupid question, but I'm trying to figure out the best way to do this. Would you simply redirect to a /Logout page and have the controller call the FormsAuthentication.SignOut function?
That was my first thought, but then I wondered if it could be abused by third party websites. Let's say someone just decides to post a link to your /Logout page. The user would get signed out of your application. Is there a good way to prevent that?
If you are concerned about a user getting accidentally logged out of you application through the use of a malicious link, you can check the Referrer to make sure that the logout is coming from your site (or is NULL in the case where the user simply types the URL in).
I actually don't worry about this since logging someone out is annoying but not necessarily a security risk.
Such a malicious link would be an example of a class of security vulnerabilities known as cross site request forgery, CSRF. A logout link is relatively harmless, but a remote site could set up a number of hidden forms and post them to your site to perform any action possible through POST.
The most common counter-measure is to include a challenge, a random hidden value in each form, and then check for that value. Checking the referer header could work, but note that some browsers don't send referer at all.
Read more: http://en.wikipedia.org/wiki/Cross-site_request_forgery
This is an old question, but here is a modern example with MVC:
[Authorize]
public RedirectResult Logout()
{
FormsAuthentication.SignOut();
return this.Redirect("/");
}
You can ensure that the Logout action is only able to be called by somebody who is logged in by applying the Authorize attribute to it.
This is what I use.
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
Seems to work fine.
Third party websites are only going to log themselves out. So they wouldn't be achieving anything different from actually clicking Logout.
The new ASP.net MVC Beta contains an AccountController, which may be worth looking at, as it essentially implements everything from Registration to Login/Logout to Forgot Password functionality. Not sure how good it is, but a good starting Point for sure.
Derive from ActionResult
public class LogoutResult : ActionResult
{
private readonly IAuthenticationService _authenticationService;
private readonly IWebContext _context;
public LogoutResult(IAuthenticationService authenticationService, IWebContext context)
{
_authenticationService = authenticationService;
_context = context;
}
public override void ExecuteResult(ControllerContext context)
{
_authenticationService.Logout();
_context.Abandon();
_context.Redirect("~/");
}
}
You should look for a cookie or something that identifies the client as the true user.