Implementing Security in ASP.NET Web App as afterthought - asp.net

As with many real world applications out there, the security (login/password) was just there to grant/deny access to the complete application. Now the client has asked for fine grained security like some web pages should only be viewable, some users can delete other cannot etc.
basically the client is requesting the following.
Effective Permission:: Users--> Web page --> Type of Access (View,Create/Edit,Delete)
Details of Application
ASP.NET/C#
MSSQL Server 2008 for Biz data
SQLCE for users/passwords/profiles/logs
Ext.NET for main UI
We discussed that it is better to enhance the security.sdf file and have a table for screens (webpages) and a join table of user + screens + a number that denotes type of access i.e.
1: Read
2: Write
4: Delete
These can be checked using bitwise operator. The application uses ASP.NET impersonation to gain access to MSSQL2008
The problem is how to implement it in the web application?
If anyone has better ideas please share!!!

You can use the IsInRole function and categorize your users into roles. Each role can have some action that can be done only. So by asking in witch role is the user you can let him do or not thinks.
HttpContext.Current.User.IsInRole("Role")
Or you can do it reversely, ask if this action is available for this role, here is a simple object, with permissions and checks.
public enum csPermissions
{
pActionDelete = 1,
pActionEdit = 2 ,
// more names...
}
private int[] AdminPermission = {
(int)csPermissions.pActionEdit,
(int)csPermissions.pActionDelete,
// more permissions...
};
private int[] BackOfficePermission = {
(int)csPermissions.pActionEdit,
// more permissions...
};
public static bool IsThisAllowed(csPermissions AskPermitForThisAction)
{
// questions here for all users roles...
// here is only an example
if (HttpContext.Current.User.IsInRole("Administator")))
{
for (int i = 0; i < AdminPermission.Length; i++)
if (AdminPermission[i] == (int)AskPermitForThisAction)
return true;
}
// no permission found
return false;
}

Related

About authorization in ASP.NET Core

I am trying to build a permission based Authorization for Asp.net Core while I am moving to core from .net framework. I built an Authorization system based on my needs(using Identity). Basically I am adding Claims to Roles and Users have roles. I built checkboxes for assigning roles to user and assigning claims to roles. Everything works well but here is my question:
While the system is working, let's say user1 has "Admin Role". user1 can access the pages based on the policies which are using his roles->claims. The problem starts here. While user1 is logged in, if I change the claims of "Admin" role, user1 won't be effected until he/she log off and login again.
Anyone has an idea to solve this problem?
The solution seems to work... but let me raise up a caution a bit...
Performance issue
Since you have to check the permission on database for every client request (which will have a real burden to the system). I know it seems like you're building classic mono app. But the server will still suffer from coming back and forth database hard.
The user doesn't know what's happening.
Imagine you display a report section that user usually access it frequently, but on some nice day... the browser blank out, or pop-up some dialog that she doesn't have permission to using this anymore. That's could cause real issue cause user only use what they need at the very moment. What'll happen if it's 10 minutes to the meeting and an assistance needed to print out some report and that pop-up ? (from my experienced lesson (XD)).
So I highly suggest that, on app deployemnt and user login, take all their role and claims from database once and cache them somewhere (like IMemoryCache, since we are targeting classic mono app), then check the claim on caches afterward.
Everytime user permission changed, update the cache, and log the user out right at that moment. If something bad happen. User would yelling at the person who setting the permission, not us as developers.
Seems like you have spend a few continuously hours to complete your own decent solution since last time.
Good work mate
Okay. I came up with a solution.
internal class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
UserManager<User> _userManager;
RoleManager<IdentityRole> _roleManager;
public PermissionAuthorizationHandler(UserManager<User> userManager, RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
if (context.User.Identity.Name == null)
{
return;
}
// Get all the roles the user belongs to and check if any of the roles has the permission required
// for the authorization to succeed.
var user = await _userManager.GetUserAsync(context.User);
var userRoleNames = await _userManager.GetRolesAsync(user);
var userRoles = _roleManager.Roles.Where(x => userRoleNames.Contains(x.Name));
foreach (var role in userRoles)
{
var roleClaims = await _roleManager.GetClaimsAsync(role);
var permissions = roleClaims.Where(x => x.Type == CustomClaimTypes.Permission &&
x.Value == requirement.Permission)
.Select(x => x.Value);
if (permissions.Any())
{
context.Succeed(requirement);
return;
}
}
}
}
and then we call this in startup.cs
services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
For more detailed answer please check: https://www.zehntec.com/blog/permission-based-authorization-in-asp-net-core/

Session variable are set to null between page

I have a solution with 2 projects : Core and Web. In the Core, I manage session I do something and I call this method :
public void SetLog()
{
HttpContext.Current.Session["Logged"] = true;
}
That's work.
When I change page (I use the ASP.NET 4.0 default template for testing), I click on the "About" link and I call this method :
public bool IsLogged()
{
if (HttpContext.Current.Session["Logged"] == null)
return false;
return true;
}
On the About page, Session are null, normal ? how solve this ?
Thanks,
I suspect that you have 2 web applications: Core and Web hosted on 2 different domains: http://localhost:1234 and http://localhost:5678. You seem to be setting the session variable inside the first web application but this session is only about the first application. As soon as you leave this application the other has a completely distinct session. Remember that sessions cannot be shared between ASP.NET applications. There are workarounds for this but out of the box it doesn't work.

Using ASP.net membership to get aspnet_Users in silverlight

Hope somebody can help.
Have looked around on the net but cannot seem to solve (or understand) this.
I have tried the code posted at
http://blogs.msdn.com/b/kylemc/archive/2010/05/10/using-asp-net-membership-in-silverlight.aspx
(not going to repeat the class MembershipServiceUser here as it is quite long and can be seen on the mentioned page)
I have set up the domain service with the class and the code to return the users:
//[RequiresRole("Managers")]
public IEnumerable<MembershipServiceUser> GetAllUsers()
{
return Membership.GetAllUsers().Cast<MembershipUser>().Select(u => new MembershipServiceUser(u));
}
I took out the RequiresRole for testing.
What I seem to be a bit blonde about is the calling of the GetAllUsers() method.
In my code behind I am using:
MembershipDataContext context = new MembershipDataContext();
EntityQuery<MembershipServiceUser> users = context.GetAllUsersQuery();
I am not 100% sure if this is the correct way to use the method or if something else is wrong because
context.GetAllUsersQuery(); returns "Enumeration yielded no results"
One question is also in the code kylmc uses //RequiresRole("Admin")]. Is this a custom role created in the ASP.NET Configuration editor?
Looking at another tutorial regarding using the ASP.NET authentication service in Silverlight, I create a role called "Managers" and added the login user to that role.
Logging in using a user with role Managers doesn't help and results are still not yielded.
Any ideas I could possible look at?
Many thanks
Neill
There are two steps involved with querying.
Get a query object from the Domain Service context (synchronous).
Load the query from the Domain Service context (asynchronous).
Example:
public void Load()
{
// define the query
var query = context.GetAllUsersQuery();
// start running the query, and when the results return call
// OnGetAllUsersLoaded
context.Load(query, OnGetAllUsersLoaded, null);
}
public void OnGetAllUsersLoaded(LoadOperation op)
{
var results = op.Entities;
}

ASP.NET MVC3 Role and Permission Management -> With Runtime Permission Assignment

ASP.NET MVC allows users the ability to assign permissions to functionality (i.e. Actions) at Design Time like so.
[Authorize(Roles = "Administrator,ContentEditor")]
public ActionResult Foo()
{
return View();
}
To actually check the permission, one might use the following statement in a (Razor) view:
#if (User.IsInRole("ContentEditor"))
{
<div>This will be visible only to users in the ContentEditor role.</div>
}
The problem with this approach is that all permissions must be set up and assigned as attributes at design time. (Attributes are compiled in with the DLL so I am presently aware of no mechanism to apply attributes (to allow additional permissions) such as [Authorize(Roles = "Administrator,ContentEditor")] at runtime.
In our use case, the client needs to be able to change what users have what permissions after deployment.
For example, the client may wish to allow a user in the ContentEditor role to edit some content of a particular type. Perhaps a user was not allowed to edit lookup table values, but now the client wants to allow this without granting the user all the permissions in the next higher role. Instead, the client simply wants to modify the permissions available to the user's current role.
What options are strategies are available to allow permissions on MVC Controllers/Views/Actions to be defined outside of attributes (as in a database) and evaluated and applied at runtime?
If possible, we would very much like to stick as closely as we can to the ASP.NET Membership and Role Provider functionality so that we can continue to leverage the other benefits it provides.
Thank you in advance for any ideas or insights.
What options are strategies are available to allow permissions on MVC
Controllers/Views/Actions to be defined outside of attributes (as in a
database) and evaluated and applied at runtime?
A custom Authorize attribute is one possibility to achieve this:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
Roles = ... go ahead and fetch those roles dynamically from wherever they are stored
return base.AuthorizeCore(httpContext);
}
}
and then:
[MyAuthorize]
public ActionResult Foo()
{
return View();
}
As I'm lazy I couldn't be bothered rolling my own attribute and used FluentSecurity for this. In addition to the ability to apply rules at run time it allows a custom way to check role membership. In my case I have a configuration file setting for each role, and then I implement something like the following;
// Map application roles to configuration settings
private static readonly Dictionary<ApplicationRole, string>
RoleToConfigurationMapper = new Dictionary<ApplicationRole, string>
{
{ ApplicationRole.ExceptionLogViewer, "ExceptionLogViewerGroups" }
};
the application roles are then applied like so
SecurityConfigurator.Configure(
configuration =>
{
configuration.GetAuthenticationStatusFrom(() =>
HttpContext.Current.User.Identity.IsAuthenticated);
configuration.GetRolesFrom(() =>
GetApplicationRolesForPrincipal(HttpContext.Current.User));
configuration.ForAllControllers().DenyAnonymousAccess();
configuration.For<Areas.Administration.Controllers.LogViewerController>()
.RequireRole(ApplicationRole.ExceptionLogViewer);
});
filters.Add(new HandleSecurityAttribute());
and then the check is performed by
public static object[] GetApplicationRolesForPrincipal(IPrincipal principal)
{
if (principal == null)
{
return new object[0];
}
List<object> roles = new List<object>();
foreach (KeyValuePair<ApplicationRole, string> configurationMap in
RoleToConfigurationMapper)
{
string mappedRoles = (string)Properties.Settings.Default[configurationMap.Value];
if (string.IsNullOrEmpty(mappedRoles))
{
continue;
}
string[] individualRoles = mappedRoles.Split(',');
foreach (string indvidualRole in individualRoles)
{
if (!roles.Contains(configurationMap.Key) && principal.IsInRole(indvidualRole))
{
roles.Add(configurationMap.Key);
if (!roles.Contains(ApplicationRole.AnyAdministrationFunction))
{
roles.Add(ApplicationRole.AnyAdministrationFunction);
}
}
}
}
return roles.ToArray();
}
You could of course pull roles from a database. The nice thing about this is that I can apply different rules during development, plus someone has already done the hard work for me!
You could also consider doing task/activity based security and dynamically assign permission to perform those tasks to different groups
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/
You would need to mangle the provider a little bit to work with this but it is possible to stay inline with the .net authorisation
http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx
If you need to do Method or Controller based authorization (deny access to the whole method or controller) then you can override OnAuthorization in the controller base and do your ouwn authorization. You can then build a table to lookup what permissions are assigned to that controller/method and go from there.
You can also do a custom global filter, which is very similar.
Another option, using your second approach, is to say something like this:
#if (User.IsInRole(Model.MethodRoles))
{
<div>This will be visible only to users in the ContentEditor role.</div>
}
And then in your controller populate MethodRoles with the roles assigned to that method.

How to get HealthVault to work with multiple ApplicationID in same application

We may never know why Microsoft decided to limit developers by making HealthVault applications constrained to a single web/app.config entry for a HealthVault application. However I need to be able to make 2 (or more) HealthVault ApplicationID’s work with one ASP.NET website? I’m looking for an effective and reliable way to do this.
I won’t go into the details of the reasoning behind 2 different HealthVault applications, but other than to say we need it to work. I still cannot login correctly with MSDN Forums (think infinite redirection sign in loop) so I am hoping for a post here that will help me.
I did contact a HealthVault developer on how to achieve this however the developer gave a suggestion that I don’t believe would be reliable (if I’m wrong let me know).
The developer’s suggestion was to do the following in code when you needed to connect to HealthVault, but prior to connecting:
ConfigurationSettings.AppSettings[“ApplicationId”] = “[YOUR APP ID]”;
The problem is that this is a static property and I do see this as an issue as our web application will have different users accessing both HealthVault applications at the same time.
Does anyone have any suggestions to make 2 (or more) HealthVault ApplicationID’s work with one ASP.NET website? I’m looking for an effective and reliable way to do this.
There is a way to dynamically switch app ids on runtime. Both applications must be created, both certificates must be installed. Few things to keep in mind. For every authenticated connection, user will be granted a token (aka wctoken). This token is consumed when user is redirect back from Live ID (in case live id is used...) by your redirect.aspx page (assuming your redirect page inherits from HealthServiceActionPage.This means that everytime you switch applications, you must redirect user back to Live ID with new app id to receive new token.
Here is code sample that can be user to dynamically change settings:
public class ConfigurationManager : HealthWebApplicationConfiguration
{
private string appid;
public ConfigurationManager(string appid)
{
this.appid = appid;
}
public override Guid ApplicationId
{
get
{
return AppManager.Current.GetCurrentAppId(this.appid);
}
}
}
public class AppManager
{
private static readonly Object lck = new Object();
public Guid? App;
public static AppManager Current
{
get
{
AppManager mgr = null;
if (_current == null)
{
lock (lck)
{
mgr = new AppManager();
}
}
return mgr;
}
}
private static AppManager _current;
public Guid GetCurrentAppId(string id)
{
return new Guid(id);
}
}
Usage:
ConfigurationManager cm = new ConfigurationManager(your-app-id-here);
HealthWebApplicationConfiguration.Current = cm;

Resources