To check multiple roles has the method level access
I have used #PreAuthorize annotation to check the role
#PreAuthorize("hasRole(\"" + AuthoritiesConstants.USER + "\",)" )
How to check multiple roles using #PreAuthorize annotaion?
You can create a custom annotation to validate many roles and conditions. P.e.:
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasRole(T(com.bs.dmsbox.api.constants.RoleConstants).ROLE_AGENT) " +
"|| hasRole(T(com.bs.dmsbox.api.constants.RoleConstants).ROLE_ADMIN)" +
"|| (hasRole(T(com.bs.dmsbox.api.constants.RoleConstants).ROLE_CUSTOMER) && #userId == principal.username)")
public #interface IsAuthenticatedAsAgentOrCustomerIsUserId {
}
Then, you can use this annotation as below:
#IsAuthenticatedAsAgentOrCustomerIsUserId
Folder findByUserIdAndType(#Param("userId") String userId, #Param("typeId") FolderType id);
This annotation validate that user logged as role AGENT or ADMIN. If user has role CUSTOMER validate if userId parameter is equals to user logged
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')")
hasAnyRole()
When you need to support multiple roles, you can use the hasAnyRole() expression.
#PreAuthorize("hasAnyRole('ADMIN','DB-ADMIN')")
https://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
https://www.appsdeveloperblog.com/spring-security-preauthorize-annotation-example/
Simply combine roles by using && or || in SpEL expressions
#PreAuthorize("hasRole('" + AuthoritiesConstants.USER + "')" +
" && hasRole('" + AuthoritiesConstants.ADMIN + "')" )
SecurityExpressionOperations interface in package org.springframework.security.access.expression; contains all the authorization-related methods.
Below are the most useful methods for authentication.
boolean hasRole(String role);
boolean hasAnyRole(String... roles)
boolean isAuthenticated();
boolean hasPermission(Object target, Object permission);
boolean hasPermission(Object targetId, String targetType, Object permission);
I believe the best option is to use #PreAuthorize("hasAnyRole()")
In this case I suppose #PreAuthorize("hasAnyRole(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN)")
Related
I have "mydomain\myusername" in the database with the role Administrator. I have ran a couple of test with different configurations. The comment with the "+" is given access, whereas, the "-" is required to log on. It seems as though a user is given access if it's authorized by itself. But when a role is added in, the role takes priority and it doesn't even look at the single user.
How do I get it to work where it takes the single user or multiple users into account when a role is specified? I am using a custom [DefaultAuthorize]:Asp.net MVC4: Authorize on both controller and action and OverrideAuthorize so that the controller and the action permission don't AND together, but it doesn't cause the behavior where the Users is ignored over the Role. That behavior seems to be the default behavior of the authentication.
Edited: I just tested it some more, and the solution from the SO above doesn't really work to create the OR in controller/actions, it still requires a logon if both are specified but user is only in the controller group. It works if user is in the action group.
Edited: The only thing I see for sure is defining Roles in the Actions works as expected. Adding Roles or users in the controller create a nonsensical behavior.
So there are two issues that boggles the mind. 1. Can't seem to get rid of the AND condition when roles are specified in the controller and actions. 2. the user is ignored over role.
I am using MVC5 with windows authentication and roles.
//-[Authorize(Roles = "Publisher,Editor", Users = "mydomain\\myusername")] //this should have worked since myusername is running the test
//-[Authorize(Users = "mydomain\\myusername",Roles = "Publisher,Editor")] //this should have worked also
//+[Authorize(Users = "mydomain\\myusername", Roles = "Administrator,Publisher,Editor")] //this works because of Administrator
//+[Authorize(Users="mydomain\\myusername")]
//+[Authorize(Roles = "Administrator")]
//+[Authorize(Roles = "Administrator", Users = "mydomain\\myusername")]
//+[Authorize(Roles = "Administrator,Editor", Users = "mydomain\\myusername")]
//+[Authorize(Roles = "Publisher,Administrator,Editor", Users = "mydomain\\myusername")]
[DefaultAuthorize(Roles = "Publisher,Editor")]
public class PersonEntitiesController : Controller
{
//default role and override role works as long as it is in a group
//-[Authorize(Roles = "Administrator")] doesn't work as it's AND with controller
//when a user is grouped with a Role, the role takes priority
//doesn't work as myusername is ignored and only looks at Publisher but user is not in gorup
//-[OverrideAuthorize(Users = "mydomain\\myusername",Roles="Publisher")]
//+[OverrideAuthorize(Roles="Administrator")]
//+[OverrideAuthorize(Users = "mydomain\\myusername")] //works as long as myusername is listed by itself
//+[OverrideAuthorize(Users = "mydomain\\myusername",Roles="Administrator")] //the group works as long as myusername is in that group
public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
This is the default behavior of the Authorize attribute. The attribute verify that all the following rules pass:
The user is not null, it has an identity and it's authenticated.
If user's names were included, that the identity name is included on those.
If roles were included, that any of the roles included is present on the identity roles.
Doing an inspection of the ASP.NET MVC's AuthorizeAttribute.IsAuthorized code confirms it:
protected virtual bool IsAuthorized(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw Error.ArgumentNull("actionContext");
}
IPrincipal user = actionContext.ControllerContext.RequestContext.Principal;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
{
return false;
}
return true;
}
So as you suspected this behavior works as an AND, not an OR. If you want to have a different behavior, I recommend that you create a custom Authorization attribute and put your own logic on it. Just inherit from AuthorizeAttribute and override the IsAuthorized method with your custom logic.
I am working on grails application, where I have a Profile domain for every User. There are two ways to view and edit profile of a user -
The user clicks on the header link called Profile, so he can view his profile and edit it if needed.
The admin can view profile of any user by clicking a user link from the list of all users.
So in the first case if a user himself is checking his profile then on the controller side I am checking the user using spring security method "springSecurityService.currentUser".
While in second case, if the admin is checking the profile of a user then userInstance is passed to the controller action.
Problem arises when I am using it for the first case, i.e. User himself is checking his profile. Here when I check for null of userInstance parameter using if/else condition, the userInstance passes null check even though it is null. And when I print it on console it gives me a null pointer exception.
Code is-
def show(User userInstance){
println("Inside show action of profileController")
println("userInstance: " + userInstance) //Output- userInstance: null
if(userInstance != null){
println("userInstance: " + userInstance) //Output- userInstance: null
}else{
println("userInstance is null") //It never prints even though userInstance is null
userInstance = springSecurityService.currentUser
}
//More functionality to come
}
So basically its very basic thing but I am not able to figure it out, why is it not checking for null but sill printing as null.
when I check for null of userInstance parameter using if/else condition, the userInstance passes null check even though it is null.
This implies a pretty fundamental bug in the Groovy compiler, which I doubt. Try this instead:
def show(User userInstance){
userInstance = userInstance ?: springSecurityService.currentUser
}
Presumably when an admin is viewing a user's profile, the ID of the user is passed as a request parameter? If so, what's to stop a malicious user who knows (or guesses) the ID of another user, from accessing their profile?
Use this approach : Forget about isNull function but , and also forget about userIntance == null statement and try this !userInstance ,it works as follow!!!
Example
var user = User.get(10);
According to you :
def show(User userInstance){
println("Inside show action of profileController")
println("userInstance: " + userInstance) //Output- userInstance: null
if(!userInstance){
println("userInstance: " + userInstance) //Output- userInstance: null
}else{
println("userInstance is null") //It never prints even though userInstance is null
userInstance = springSecurityService.currentUser
}
//More functionality to come
}
Check this groovy script example on groovy Console Here
Controller
public partial class HomeController
{
private static String[] userPermissions;
public HomeController()
{
var MyPermission = Convert.ToString(TempData["MyPermission"]);
userPermissions = (MyPermission).Split(',');
}
[Microsoft.AspNet.Mvc.Facebook.FacebookAuthorize(userPermissions)]
public virtual ActionResult MyActionMethod()
{
return View();
}
}
Overload
Compilation Error
In the above block, we have following code
[Microsoft.AspNet.Mvc.Facebook.FacebookAuthorize(userPermissions)]
It is giving below compilation error...
Not sure if it helps but this is how I let users add additional permissions.
/// <summary>
/// Use this method when an action fails due to lack of priviligies. It will redirect user to facebook with provided permission request.
/// Refactor to handle list of request.
/// </summary>
/// <param name="permission"></param>
private static void AddAdditionalPermissions(string permission)
{
System.Diagnostics.Trace.TraceInformation(permission + " not authorized for user.");
string facebook_urlAuthorize_base = "https://graph.facebook.com/oauth/authorize";
string scope = permission; //see: https://developers.facebook.com/docs/authentication/permissions/ for extended permissions
string urlAuthorize = facebook_urlAuthorize_base;
urlAuthorize += "?client_id=" + AppId;
urlAuthorize += "&redirect_uri=" + "https://mydomainnamehere.nu/";
urlAuthorize += "&scope=" + scope;
//redirect the users browser to Facebook to ask the user to authorize our Facebook application
HttpContext.Current.Response.Redirect(urlAuthorize, true); //this cannot be done using WebRequest since facebook may need to show dialogs in the users browser
}
It is my understanding that you cannot dynamically assign anything to an attribute argument (as the error message backups up).
I do something with my Custom Membership Provider that I think you could adapt to meet your goal. I wanted a roles/rights setup defining user access to various parts of the system without needing to assign a bunch of individual rights to the users but still have very granular control of what each role can do. I followed the approach here (with some changes) to accomplish this.
The approach I would take if there is a need to do this on the fly in your scenario is define a constant Role to use in the FacebookAuthorize attribute for an ActionMethod and then in whatever is handling your permission checking pass (or have it look up) the array of permissions for each "role". This way the "role" you assign to the AuthorizeAttribute is a constant.
I am able to authenticate the user using ADFS and succeded in getting the user alias using the below statement. Since some time, i am looking for a way in getting the other claims of the authenticated user, like email, name, roles, username etc.
Any help on this would be appreciated.
string alias = ((MicrosoftAdfsProxyRP.MicrosoftPrincipal)HttpContext.Current.User).Alias;
Response.Write (alias);
The Claims way of getting the other claims is as follows.
IClaimsPrincipal claimsPr = (IClaimsPrincipal)(HttpContext.Current.User)
From the claims principle you can get the ClaimsIdentityCollection through the IClaimsIdentity.
Get the IClaimsIdentity from the claimsPr.Identifies.
Then inspect all the claims present in the IClaimsIdentity using the Claims property.
You're asking the world a question about an internal Microsoft service and interface. Try emailing the msftadfsproxydisc alias with your question.
Have a look at How to: Access Claims in an ASP.NET Page.
Just in case the link disappears, the key is:
void Page_Load(object sender, EventArgs e)
{
// Cast the Thread.CurrentPrincipal
IClaimsPrincipal icp = Thread.CurrentPrincipal as IClaimsPrincipal;
// Access IClaimsIdentity which contains claims
IClaimsIdentity claimsIdentity = (IClaimsIdentity)icp.Identity;
// Access claims
foreach(Claim claim in claimsIdentity.Claims)
{
Response.Write(claim.ClaimType) + "<BR>";
Response.Write(claim.Value) + "<BR>";
Response.Write(claim.ValueType) + "<BR>";
}
}
I'm using ASP.NET MVC and Forms Authentication on my application. Basically I use FormsAuthentication.SetAuthCookie to login and FormsAuthentication.SignOut to logout.
In the HttpContext.Current.User.Identity I have stored the user name but I need more info about the logged user. I don't want to store my entire User obj in the Session because it might be big and with much more infomation than I need.
Do you think it's a good idea to create like a class called LoggedUserInfo with only the attributes I need and then add it to the Session variable? Is this a good approach?
Or do you have better ideas?
I use this solution:
ASP.NET 2.0 Forms authentication - Keeping it customized yet simple
To summarize: I created my own IPrincipal implementation. It is stored in HttpContext.Current.Cache. If it is somehow lost, I have username from client side authorization cookie and can rebuild it. This solution doesn't rely on Session, which can be easily lost.
EDIT
If you want to use your principal in your controller and make it testable, you can do this:
private MyPrincipal _myPrincipal;
MyPrincipal MyPrincipal
{
get
{
if (_myPrincipal == null)
return (MyPrincipal)User;
return _myPrincipal;
}
set
{
_myPrincipal = value;
}
}
In your test, you will set object prepared for testing. Otherwise it will be taken from HttpContext. And now I started thinking, why do I use Ninject to do it?
Store it server side in the session.
Eg.
// Make this as light as possible and store only what you need
public class UserCedentials
{
public string Username { get; set; }
public string SomeOtherInfo { get; set; }
// etc...
}
Then when they sign in just do the following to save the users info:
// Should make typesafe accessors for your session objects but you will
// get the point from this example
Session["UserCredentials"] = new UserCredentials()
{ Username = "SomeUserName", SomeOtherInfo = "SomeMoreData" };
Then whenever you need it fetch it:
UserCredentials user = (UserCredentials)(Session["UserCredentials"]);
I have written a couple of question/answers regarding doing custom authorization in MVC:
How to implement authorization checks in ASP.NET MVC based on Session data?
How does the Authorize tag work? - Asp.net Mvc
I actually like to use a CustomPrincipal and CustomIdentity which I set in the logon action method like
if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password) && _authService.IsValidLogin(username, password))
{
User objUser = _userService.GetUserByName(username);
if (objUser != null)
{
//** Construct the userdata string
string userData = objUser.RoleName + "|" + objUser.DistrictID + "|" + objUser.DistrictName + "|" + objUser.ID + "|" + objUser.DisplayName;
HttpCookie authCookie = FormsAuthentication.GetAuthCookie(username, rememberMe.GetValueOrDefault());
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData);
authCookie.Value = FormsAuthentication.Encrypt(newTicket);
Response.Cookies.Add(authCookie);
return RedirectToAction("Index", "Absence");
}
else
{
return RedirectToAction("LogOn", "Account");
}
}
else
{
return RedirectToAction("LogOn", "Account");
}
Then in the custom principal you can have methods that access specific information you passed in to the constructor like
((CustomIdentity)((CustomPrincipal)HttpContext.Current.User).Identity).DisplayName;
where the DisplayName property is declared in the CustomIdentity class.
Well you will have to store these somewhere. Two main possible places though:
The server
You can either put them into Session. I suggest you do create a separate class that will hold only data that you actually need to avoid of wasting too much memory. Or you can also store into Cache that can end up in having many DB calls when there are huge amounts of concurrent users.
The client
In this case if you can limit the amount of data with a separate class, to that and use whatever way to serialize it and send it to the client. Either in a cookie or in URI (if length permits and cookies are disabled)...
Outcome of these thoughts:
the main thing here would be to create a separate class if you gain much memory resources this way. So that's the first thing you should do.