Code is ignoring PrincipalPermission attribute? - c#

I have a Delete method on all my business objects that has the PrincipalPermission attribute on it.
Example:
[PrincipalPermission(SecurityAction.Demand, Role = "Vendor Manager")]
public static bool Delete(Vendor myVendor)
{
//do work here
}
The problem is that it appears to be completely ignoring my PrincipalPermission. It lets anyone through, no matter what role they may be part of.
Is there something else I've forgotten to do? I have added the following to my Application's global.asax in the Application Startup section:
AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);
But that doesn't make any difference either.
I also just tried the following:
public static bool Delete(Vendor myVendor)
{
PrincipalPermission iPerm = new PrincipalPermission(null, "Vendor Manager");
iPerm.Demand();
//do work here
}
and wouldn't ya know, this works just fine!.... any ideas on why it works one way but not the other?

Did you get an answer for this? I just tested this in my own application and it works pretty well. I'm specifically NOT adding
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
And, I'm using Forms Authentication (ASP.NET Membership), MVC 2, .NET 3.5.
I did however discover if I decorate my class with the following my method decorations do not work.
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]

Only one observation for any people that says that sample does not work. Check the name for the role according with your local culture. For example, if you resides in Mexico, you must to use: #"BUILTIN\Administradores" instead of #"BUILTIN\Administrators".

Have you validated that the Windows principal doesn't happen to have the permission you're requiring? Something like this (modified from here) -- I would think -- should mimic that behavior and allow you to step through. It should indicate whether or not the permission is granted.
If this passes, then I would expect the attribute to pass on through as well. If this fails, but the attribute passes through, then I'm as stumped as you are.
static void Main(string[] args)
{
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
PrincipalPermission principalPerm = new PrincipalPermission(null, "Vendor Manager");
try
{
principalPerm.Demand();
Console.WriteLine("Demand succeeded.");
}
catch (Exception secEx)
{
Console.WriteLine("Demand failed.");
}
Console.ReadLine();
}

Related

Controlling access to methods

Is there a way to control access to methods to certain roles in .net. Like
class A
{
//should only be called by Admins**
public void Method1() { }
//should only be called by Admins and PM's**
public void Method2() { }
}
I'm using windows authentication only for retrieving user names and nothing more.User roles are maintained in a different application. I think it's possible through attributes but I'm not really sure how
It it possible, I have used it on an web project that used asp.net and AzMan as the authentication.
Take a look at Code Access Security
From memory all of our methods looked something like
[Permission(SecurityAction.Demand, "Permission")]
public void Method1
It's been a while though so that might not be actually 100% correct.
I'd also highly suggest if you are going to put protection down to this level to look at a task orientated permission approach as this is much more flexible than role based permissions
You can do this as follows:
class A
{
//should only be called by Admins**
[PrincipalPermission(SecurityAction.Demand, Role="Admin")]
public void Method1()
{
}
//should only be called by Admins and PM's**
[PrincipalPermission(SecurityAction.Demand, Role="Admin")]
[PrincipalPermission(SecurityAction.Demand, Role="PM")]
public void Method2()
{
}
}
To do this Thread.CurrentPrincipal must be set to a principal that has the required roles. For example, if you enable roleManager in an ASP.NET application, Thread.CurrentPrincipal will be set to a RolePrincipal with roles from your configured RoleProvider. See this MSDN article for more info.
You can do it using custom validation.
1- Make a method in another public class which take login id as parameter and return roles in form of bits.
2- Call this method on the page_Load event of the required class and save returned bits in the view state.
3- Now validate required method on the basis of roles bits.

PhluffyFotos does not work on Azure SDK 1.3

I have tried PhluffyFotos example on Azure SDK 1.2 and it works perfect. Today I have installed on another (clen) computer Azure SDK 1.3 and I have also want to try PhluffyFotos on it but it does not work. I have problem with this part:
if (!Roles.GetAllRoles().Contains("Administrator"))
{
Roles.CreateRole("Administrator");
}
It seems it somehow does not load the custom RoleProvider (TableStorageRoleProvider). Do you have any idea what it could be?
I get the following error: "The Role Manager feature has not been enabled.", because of the following exception "'System.Web.Security.Roles.ApplicationName' threw an exception of type 'System.Configuration.Provider.ProviderException'".
Can someone test this example and see what is the problem? http://phluffyfotos.codeplex.com/
Firsty I have the "SetConfigurationSettingPublisher" problem with this example, but I have successfully resole it.
EDIT:
I have look deeper into it and I am sure there are a problem with Role provider. Somehow the Roles class do not read config file. Have anyone any idea why?
I have the exact same problem with my own project. I verified with Fusion logs that the assembly which contains the custom providers dont even load. so it seems the problem is somehow related to the web.config settings being ignored.
To run PhluffyFotos example on Azure SKD 1.3 you have to the following:
Change reference Microsoft.WindowsAzure.StorageClient from 1.0 to 1.1
Move "GetConfigurationSettingValue" to the Global.asax "Application_Start" event.
Move Role related initialization to the Global.asax "Application_BeginRequest" event, but you have to ensure that it executes only once. Example:
private static object gate = new object();
private static bool initialized = false;
protected void Application_BeginRequest()
{
if (initialized)
{
return;
}
lock (gate)
{
if (!initialized)
{
// We need to check if this is the first launch of the app and pre-create
// the admin role and the first user to be admin (still needs to register).
if (!Roles.GetAllRoles().Contains("Administrator"))
{
Roles.CreateRole("Administrator");
}
if (!Roles.GetUsersInRole("Administrator").Any())
{
Roles.AddUserToRole(RoleEnvironment.GetConfigurationSettingValue("DefaultAdminRoleUser"), "Administrator");
}
initialized = true;
}
}
}
I posted a version of the code with the fixes suggested by Peter to rapidshare here:
http://rapidshare.com/files/434649379/PhluffyFotos.zip
For those who don't want to fuss around fixing the dependencies etc.
Cheers,
Daniel

Authorising Web App users against User Information as well as Role

I was wondering if anyone would be able to help me with the following?
I need some more complicated rules for authorisation in a webapp than just role, which I have working fine. Something along the lines of "Allow all Admins. Allow Buyers, provided they have the correct department ID and are allowed to see this customer's credentials".
I am using a custom identity and custom principal to store information such as whether a user is allowed to see all clients or which individual clients they may see. This information is retrieved from a database and added upon creation of the identity/principal.
I have created a custom permission that extends IPermission, ISecurityEncodable. Within this, I have modified the Demand() function to the following:
public void Demand()
{
this._identity = (UserIdentity)Thread.CurrentPrincipal.Identity;
if (Thread.CurrentPrincipal.IsInRole("Admin")) { }
else if ((Thread.CurrentPrincipal.IsInRole("Buyer")) &&
(this._identity.CanViewAllClients) &&
(this._identity.IsInDept(this._departmentID)) ) { }
else if ((Thread.CurrentPrincipal.IsInRole("Buyer")) &&
(this._identity.CanViewClient(this._requestedClient)) &&
(this._identity.IsInDept(this._departmentID)) ) { }
else { throw new SecurityException("Custom Permission Denied"); }
}
I then call this when I wish to authorise by using
CustomPermission custperm = new CustomPermission(requestedClient, reqClientDept);
custperm.Demand();
This works fine, but seems a messy, hacky way to do things. Especially since it would be nice to use my security roles as an attribute e.g.
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public class...
Perhaps there is a way to call [CustomPrincipalPermission(SecurityAction.Demand, Authorised = true)] with a custom IsAuthorised check? Is this possible? What would need to be implemented?
I apologise if there is a simple solution that I've missed online, but rest assured I have been checking for days now.
It seems like what you want is a declarative rather than a programmatic demand. In order to do so, you'll need to create a CustomPermissionAttribute based on your CustomPermission.
There's an example of a declarative demand of a custom permission here and details of creating a custom permission attribute here.

Winforms role based security limitations

I'm implementing role based security using Microsoft's membership and role provider.
The theoretical problem I'm having is that you implement a specific role on a method such as:
[PrincipalPermissionAttribute(SecurityAction.Demand, Role="Supervisor")]
private void someMethod() {}
What if at some point down the road, I don't want Supervisors to access someMethod() anymore?
Wouldn't I have to change the source code to make that change? Am I missing something?
It seems there has to be some way to abstract the relationship between the supervisors role and the method so I can create a way in the application to change this coupling of role permission to method.
Any insight or direction would be appreciated. Thank you.
If you use the declarative approach, then yes - if you suddenly don't want members of the Supervisor to be able to call your method, you need to change your source code for that.
You can, however, also do all of this in code, programmatically:
private void someMethod()
{
WindowsPrincipal currentUser = (Thread.CurrentPrincipal as WindowsPrincipal);
if (currentUser != null)
{
if (currentUser.IsInRole("Supervisor"))
{
// do something here
}
}
}
You can always get the current Windows principal your Winforms app is running under, and then you can call the IsInRole method to check whether or not a given user is in a given role. Of course, you can also make all of this configurable, e.g. read the required role from a config file, and if you want to allow everyone in, you just simply change the role to be Users or something
PrincipalPermissionAttribute does not tend to be used in many applications I've worked on for the reason you've touched upon; the attribute applies a policy which can only be altered by a code change.
The alternative is to use the PrincipalPermission class directly. All security attributes resolve to similarly named classes and method calls at run time. In the case of your attribute, the following code is executed:
PrincipalPermission permission = new PrincipalPermission(null, "Supervisor");
permission.Demand(); // Throws SecurityException if user is not in the role.
If you use the permission classes directly, you gain more control over how your permissions are formed. You could have a database which you query to get a list of roles and perform a demand for them like this:
private void someMethod()
{
IEnumerable<string> roles = GetRolesForMethod("someMethod");
PrincipalPermission permission = null;
foreach(string role in roles)
{
if(permission == null)
{
permission = new PrincipalPermission(null, role);
}
else
{
permission = permission.Union(
new PrincipalPermission(null, role);
);
}
}
if(permission != null)
{
permission.Demand();
}
}

How to set a multilanguage PrincipalPermission role name?

I'm trying to secure a WCF service using windows accounts. The service should run on many systems with different languages. How can i set a PrincipalPermission that has language independent role names?
I found ugly workarounds like this one.
[PrincipalPermission(SecurityAction.Demand, Role = "Builtin\\Administrators")] // English
[PrincipalPermission(SecurityAction.Demand, Role = "Vordefiniert\\Administratoren")] // German
public string HelloWorld()
{
return "Hello";
}
I don't think this is a good solution, is there any way to make this language independent? Is there a way to use the account SID instead of a string?
You could roll your own permission attribute which handles the translation:
[Serializable, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false), ComVisible(true)]
public sealed class AdministratorPrincipalPermissionAttribute : CodeAccessSecurityAttribute
{
public AdministratorPrincipalPermissionAttribute(SecurityAction action) : base(action)
{ }
public override IPermission CreatePermission()
{
var identifier = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
var role = identifier.Translate(typeof(NTAccount)).Value;
return new PrincipalPermission(null, role);
}
}
Please note that this would require some extra deployment effort (gac, caspol etc.).
One more try: Have a look at http://msdn.microsoft.com/en-us/library/system.security.principal.windowsbuiltinrole.aspx .... and go to the sample . There you can use the BuiltIn enumeration members to get the correctly spelled group name (via the API)... then it should be language neutral.
HTH,
Thomas
You may use the imperative version and dynamically convert a language neutral form (e.g. SID) to the localized form (may be through SecurityIdentifier.Translate).
Well known SIDs are listed in KB 243330.
Hmmmm, I would not use a group name directly in my code (hard coded). Try to abstract it to a role like "HelloWorldAdmin" and have a role configured in the app.config. This one should be mapped to a user group. This would allow your users / admins to select a group and map it to the role (e.g. in case that the application admins are not you AD admins).
Have a look at http://msdn.microsoft.com/en-us/library/ms998314.aspx. HTH.
Are you absolutely sure that on a German-language system, the "BUILTIN\Administrators" will not work? I would have imagined even then, these basic group names should be valid. Yes, in your admin tools, it will show "Vordefiniert\ADministratoren" - but I would be surprised if the PrincipalPermission attribute would be language-dependant.
MArc

Categories