I use ASP.NET SimpleMembership..
My scenario;
The user login and then I change IsConfirmed column to false on webpages_Membership table..
And the user try to change page, the login page seems to the user..
Your most sensible options are to use any of the authentication related steps in Global.asax.cs, or to derive from AuthorizeAttribute. Given that non-confirmed users are going to have to get to somewhere (for example in order to confirm their account) then you probably don't want the former. With either approach their next request will get denied.
Therefore, I would just extend your [Authorize] attribute to do something like the following, and just use that in the appropriate Controllers and Actions instead of [Authorize] (I'm assuming C# as you didn't specify language in your tags):
public class AuthorizeIfConfirmedAttribute : AuthorizeAttribute {
protected override bool AuthorizeCore(HttpContextBase httpContext) {
if (!base.AuthorizeCore(httpContext)) return false;
System.Security.Principal.IIdentity user = httpContext.User.Identity;
return WebMatrix.WebData.WebSecurity.IsConfirmed(user.Name);
}
}
[AuthorizeIfConfirmed]
public class MyController { ... }
(If you want to use a custom property on your UserProfile class instead of IsConfirmed then you can simply adjust this code accordingly).
The advantage of this approach is that it keeps all your authorization logic in the usual place, and you can also combine it with role enforcement, e.g.:
[AuthorizeIfConfirmed(Roles = "admin")]
public class MyController { ... }
Note that if you use WebApi or SignalR you may have to include these checks in however you are performing request authorization for the apis as well.
I user Application_AuthenticateRequest in Global.asax.. Because my application needs authenticate on all pages..
protected void Application_AuthenticateRequest()
{
if (WebSecurity.IsAuthenticated)
{
bool isConfirmed = (..your codes here..)
if (isConfirmed == false)
{
WebSecurity.Logout();
}
}
}
Related
I am trying to do something seemingly very simple. All I want to do is get the current Identity User's email address for my Blazor view. I have a UserEmailController in my Server project, with a GetCurrent() method that returns a Task<string>.
public class UserEmailsController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public UserEmailsController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
[Route("api/currentUser")]
public async Task<string> GetCurrent()
{
var user = await _userManager.GetUserAsync(User);
return await _userManager.GetEmailAsync(user);
}
}
From the spelunking I've done, it seems that the User property on the Controller base class should have the information loaded into it when a user is logged in, and I should be able to do something like await _userManager.GetUserAsync(User). However, when I break on this line, the Name property of User is null, along with many of the other values. But IsAuthenticated is true. Huh?
So, the result of the _userManager.GetUserAsync(User) call is null.
I've seen a few posts about this, and there are two common themes.
#1 - people try to use the User property in the constructor of a controller and it doesn't work. The suggested solution is to use it in an Action instead, which is of course what I'm doing.
#2 - another common suggestion is to use HttpContext.User, or to inject an IHttpContextAccessor (added via services.AddSingleton... or services.AddHttpContextAccessor()). I've tried all of these approaches and I get the same result.
I found a solution here. Specifically using HttpContext.User.FindFirst(ClaimTypes.NameIdentifier) and then passing that into _userManager.FindByIdAsync(nameId). Hell of a roundabout way of doing it, but it works.
I have a legacy Application that we're converting to use the MVC 5 Application template. We have a custom API method, to keep the example simple let's just say it's signature is:
bool Login(username, password);
How can I set the User as logged in, so that I can use things like the [Authorize] attribute? For the moment we want the simplest method possible just to get us started developing the site.
I tried implementing this to set User.Identity manually. But this is then reset on every subsequent request.
In the end I extracted out the logic to the Account controller. This handles the Login and stores the result in the Session. Then I just needed to override the System.Web.Mvc.AuthorizeAttribute class and AuthoriseCore method as follows:
using System.Web;
using System.Web.Mvc;
namespace HomeHealth.Web.Infrastructure
{
public class HomeHealthAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return WebSession.SdkContext.IsAuthenticated;
}
}
}
It has some helper code to clean up accessing the Context from the session, but that's irrelevant. The point is that this is the Attribute/Method you probably want. You can then mark Controllers/Methods with the following:
[HomeHealthAuthorize]
public class PatientController : BaseController
Then all the checking/redirecting is done for you.
I have a base controller which is globally marked as [Authorize]. Is there a way to prevent Controllers which inherit it from overriding the authorization requirement by simply adding the [AllowAnonymous] attribute?
Here is my exact scenario: I have three base controllers: one is for anonymous users, and two are for logged in users, both of which are globally decorated with [Authorize]. Each new controller that is created inherits from one of the base three, depending on which functionality is needed. One of the [Authorize] controllers contains "highly secure" functionality which absolutely should not be run by anonymous users. A developer inheriting from this "secure" base controller accidentally decorated some methods with [AllowAnonymous] which enabled anonymous users to potentially access the "secure" functionality in the base controller. It was caught in testing but I thought it would be a good idea to prevent that type of mistake, and I'm wondering if there is a simple way to do that. For now, I have taken all of the code inside of the secure base controller and wrapped it in blocks of:
if (Request.IsAuthenticated)
{
// do stuff
}
else
{
// redirect to login page, basically simulating what [Authorize] does
}
The above accomplishes what I want, however it kind of defeats the purpose of the global [Authorize] decoration in the first place. I'm envisioning something along the lines of:
[Authorize(AllowAnonymousOverride=false)] // this doesn't exist, but might be helpful
Is there a better way to accomplish this functionality?
The correct way to do this is to derive your own AuthorizeAttribute. The default AuthorizeAttribute looks like:
namespace System.Web.Mvc
{
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
{
throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
}
// This is the Important part..
bool flag = filterContext.ActionDescriptor
.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor
.IsDefined(typeof(AllowAnonymousAttribute), true);
if (flag)
{
return;
}
if (this.AuthorizeCore(filterContext.HttpContext))
{
HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
cache.SetProxyMaxAge(new TimeSpan(0L));
cache.AddValidationCallback(
new HttpCacheValidateHandler(this.CacheValidateHandler), null);
return;
}
this.HandleUnauthorizedRequest(filterContext);
}
}
}
Derive your own:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public bool IsAllowAnonymousEnabled { get; set; }
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
{
throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
}
// This is the Important part..
bool flag = IsAllowAnonymousEnabled
&& (filterContext.ActionDescriptor
.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor
.IsDefined(typeof(AllowAnonymousAttribute), true));
if (flag)
{
return;
}
if (this.AuthorizeCore(filterContext.HttpContext))
{
HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
cache.SetProxyMaxAge(new TimeSpan(0L));
cache.AddValidationCallback(
new HttpCacheValidateHandler(this.CacheValidateHandler), null);
return;
}
this.HandleUnauthorizedRequest(filterContext);
}
}
Usage:
[CustomAuthorizeAttribute(IsAllowAnonymousEnabled = false)]
public class MyController : Controller
{
[AllowAnonymous]
public ActionResult Index()
{
// This will still execute Authorization regardless of [AllowAnonymous]
return View();
}
}
You can't call base.OnAuthorization() because it will Allow AllowAnonymous.
First, you seem to have a controller with some methods and then your approach is to inherit it so that the same methods are exposed. I wonder what's the point of having two or more controllers that expose the same data. Was is the mistake of that developer or rather it is a custom routine in your approach?
Then, you expect to have an attribute that prevents other attributes but this is clearly not possible in the language nor in the mvc framework.
Third, someone wrote a controller without unit tests or maybe with tests but no one verified these tests so that the issue was caught during manual testing phase. This indicates that the issue is wider and not only restricted to inheritance - suppose your developer wrote a controller that doesn't inherit anything and still exposes some critical data because of allow anonymous mark. Then what? Even if you have a remedy for your original issue, it wouldn't be able to catch the new possible issue.
My advice would be to have a custom analyzer attached to the post build event that scans all possible controllers and makes a list of all anonymous and restricted actions and compares it to a previously generated list. If there is a change, then an alert is created and someone has to resolve the issue manually, either by approving newly created actions or rejecting changes because a bug has been introduced.
Our old software architecture used role based validation. We now want to use claims based authorization. As a matter of fact, I think we always used something modelling claims, even if we used role base technology.
The lowest level are Privileges. A privilege may be "invoke the user service adding a user" or short "UserService.Add". Privileges can be assigned to groups. Users can be members of groups. In the end, through group membership, a user can have a list of privileges.
The old system used a combination of UserNamePasswordValidator, IAuthorizationPolicy and CodeAccessSecurityAttribute to have attributes that were written above the service method and on call of the service method, the validity would be checked. If the user didn't have the required privilege, access would be denied. Worked great.
[CompanyRoleRequired(SecurityAction.Demand, Role = "Common.Connect")]
[CompanyRoleRequired(SecurityAction.Demand, Role = "SomeServiceName.Save")]
public void Save(IEnumerable<Data> data)
{
// code
}
Now I'd like to use claims based authorization. Keeping the model above, I would create either a claim for each former privilege, or maybe a claim for each service with valid values of it's operations. For example, instead of "UserService.Add" I could add a claim "UserService" and people with the former privilege would get the claim with the value "Add". I would like to offer the service developers the same ease of access checking, so I'd like the required claims to be annotated above the service method. Microsoft already provides a ClaimsPrincipalPermissionAttribute for this.
Instead of implementing IAuthorizationPolicy, I implemented ClaimsAuthorizationManager.
Question 1) The authorization manager gets called twice. Once with the soap url and once with my attribute. I've googled a lot and it seems to be by design. I don't have a problem differentiating between the calls and checking only my calls, but maybe I didn't see something. Is there an option or an easy way to not get called on soap calls with the urls and only getting called for the attributes?
Question 2) The access check offers the ability to check if the pricipal has a claim. Obviously, a claim has a type/name and a value. I would have expected the attribute to offer such an interface. However, the attribute wants to know about the resource and operation. The access check function I need to overwrite also needs to check resources and operations. Why is that? Do I need to map resource/operation to claims in my AuthorizationManager? And if I don't see any need for it, would it be ok to just put the expected type and value of the claim in the attribute as resource and operation and map them 1:1 in the authorization manager? Or do I miss out on some important security feature if I do this?
Q1) That's unfortunately the case - and since both the "automatic" calls and the attribute/.CheckAccess use the same claim types you cannot easily distinguish between the two. I wrote about that here: http://leastprivilege.com/2011/04/30/what-i-dont-like-about-wifs-claims-based-authorization/
Q2) You are missing the concept here. The idea is to NOT check for specific claims - but to rather annotate the code with "what you are doing". The person that writes the business code typically does not know exactly who is allowed to call it (or which claims are exactly needed). You only tell the authZ poliy that you are about to add a customer (as an example). The authorization manager's job is to figure out if the principal is authorized to do that (by whatever means). Separation of concerns. See here: http://leastprivilege.com/2011/04/30/what-i-like-about-wifs-claims-based-authorization/
Not sure if this is going to be helpful to you but ClaimsAuthorizationManager has method that can be overridden (LoadCustomConfiguration) that you can use to load your policy from XML file. That policy might be designed in a way to allow mapping between resources and actions and roles. I've built in-code access control list instead that looks like this:
public interface IAccessControlList
{
List<CustomAccessRule> Rules { get; }
}
public class CustomAccessRule
{
public string Operation { get; set; }
public List<string> Roles { get; set; }
public CustomAccessRule(string operation, params string[] roles)
{
Operation = operation;
Roles = roles.ToList();
}
}
My claims authorization manager looks like this:
public class CustomClaimsAuthorizationManager : ClaimsAuthorizationManager
{
private IAccessControlList _accessControlList;
public CustomClaimsAuthorizationManager(IAccessControlList accessControlList)
{
_accessControlList = accessControlList;
}
public override bool CheckAccess(AuthorizationContext context)
{
string operation = context.Action.First().Value.Split('/').Last();
CustomAccessRule rule = _accessControlList.Rules.FirstOrDefault(x => x.Operation == operation);
if (rule == null) return true;
if (context.Principal.Identities.First().IsInRoles(rule.Roles)) return true;
throw new MessageSecurityException(string.Format("Username {0} does not have access to operation {1}.", context.Principal.Identities.First().Name, operation));
}
}
And here is an example of one access control list implementation for one service:
public class SampleServiceACL : IAccessControlList
{
public List<CustomAccessRule> Rules { get; private set; }
public SampleServiceACL()
{
Rules = new List<CustomAccessRule>();
Rules.Add(new CustomAccessRule("OpenAccount", "Manager", "Owner"));
Rules.Add(new CustomAccessRule("CloseAccount", "Manager", "Owner"));
Rules.Add(new CustomAccessRule("SendEmail", "User", "Manager", "Owner"));
}
}
And I'm applying this at service host base level by using:
protected override void OnOpening()
{
base.OnOpening();
IdentityConfiguration identityConfiguration = new IdentityConfiguration();
identityConfiguration.SecurityTokenHandlers.Clear();
identityConfiguration.ClaimsAuthorizationManager = new CustomClaimsAuthorizationManager(new SampleServiceACL());
this.Credentials.IdentityConfiguration = identityConfiguration;
...
}
As a result, I'm not using attributes at all, all authorization logic is centralized in claims authorization manager over ACL.
Now if you don't like this approach, and you're still in pursuit of attribute that will check for specific claims, you can then derive from CodeAccessSecurityAttribute and actually implement that logic. What is given by MS out of the box is good, but it does not mean you should stick to it by any means. Also logic for checking the claims can be implemented as an extension to identity, i.e.:
public static class IdentityExtensions
{
public static bool IsInRoles(this ClaimsIdentity id, List<string> roles)
{
foreach (string role in roles)
if (id.HasClaim(ClaimTypes.Role, role)) return true;
return false;
}
}
So you might build extensions, custom attribute, and then use extensions in the attribute to perform your validation logic.
Again, this is just something that I've already done. Might not be what you're looking for but it's one type of custom solution.
I'm trying to use the new MVC4 DbDataController to expose a restful data api.
My problem is trying to secure this. I have created custom authorization attributes that derive from Authorize Attribute
public class AdminOnlyAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!IsAllowed()) {
filterContext.Result = new HttpUnauthorizedResult("Not logged in");
}
...
}
And that works fine when applied to my normal controller actions. I'm trying to use the same thing in my data service like this:
[AdminOnlyAttribute]
public class DataServiceController : DbDataController<AppBuilderDataContext>
{
[AdminOnlyAttribute]
public IQueryable<Thing> GetThings()
{
return DbContext.AllMyThings();
}
}
You can see I've tried my attribute on both the controller and the action, but it's not firing for either one. I've set a breakpoint inside my authorize attribute function, and it's not getting called.
I'm pretty sure Scott Guthrie said this was going to work. Am I doing it wrong, or do I need a completely different method to secure these?
To work with an DataController or any other type derived from ApiController your attribute must derive from System.Web.Http.AuthorizeAttribute