How do I populate a controller field from user claims ? We use claims based authentication and I'm intrested in one of claim values say "Internal Id" which is send along with the user claims.
I'll need to extract this claim value and make it available for all my web api's. I know I can extract the value from the user claims using a loop within each of the action methods.
Is there is better way to do this ? Somthing like a attribute / value provider
you can use an extention method on IIdentity to extract claims, this is how i do it:
public static int GetInternalId(this IIdentity identity)
{
var storedClaim = ((ClaimsIdentity)identity).FindFirstValue("InternalId");
if (string.IsNullOrEmpty(storedClaim)) return 0;
var value = Convert.ToInt32(storedClaim);
return value;
}
and you can call it everywhere you have access to Context object like Controller or ApiController
User.Identity.GetInternalId();
You can create a custom value provider that read the claims from the current user identity, then have a class that represent the list of key/value pair which is the claim/value in your action method.
This will make cause the value provider to fill the key/value pair and you won't have to write any additional code to have the user claims in any action method
Related
Hello guys I have a MVC actions that have Authorize attribute set on them. For each one of these actions there is a password/ security pin which is only valid for that Action.
public ActionResult Action_1()// generic pin 1
{
Return RedirectToAction("PinCheck", new { returnUrl = "Action_1" });
...
}
[Authorize]
public ActionResult Action_2()// generic pin 2
{
...
}
[Authorize]
public ActionResult PinCheck(string returnUrl)// generic pin 1
{
// request three characters of the pin in random.
...
}
[Authorize]
[HttpPost]
public ActionResult PinCheck(string a, string b, string c, string returnUrl)// generic pin 1
{
// check the three chars.
...
// How do I store pin check for the controller was a success and don't ask the user unless he closes browser or logout
}
My plan of action is checking pins stored by the Admin for the particular User for that particular Action in the Database. So far I have achieved checking PinCheck() routine but the problem I face is that the User has to enter the pin every time he requests that particular action. I made a way around this by saving an encrypted cookie on PinCheck success. But is there a way to modify the Authorize attribute and the Authentication cookie itself to achieve What I am doing?
You can also represent each Pin verified as a claim stored as part of the ClaimsIdentity in the cookie so that you can just query against the user's claims looking for the appropriate PinClaim in each Action. If you are using the ASP.NET Identity, you can do something like so when you verify the pin:
await manager.AddClaimAsync(User.Identity.GetUserId(), new Claim("<mypinclaim>", "<value>"))
await SignInAsync() // And then resign the user in to regenerate the cookie with the claim
One ways of doing this is by creating a custom role provider. You could create one by inheriting from RoleProvider. Then override IsUserInRole and optionally FindUsersInRole, GetAllRoles, GetUsersInRole to reflect your pin management logic.
Once done, register the custom role provide via the web.config.
A good article on custom role providers (http://bojanskr.blogspot.com.au/2011/12/custom-role-provider.html)
I write a controller like below:
public class AccountController : Controller
{
public ActionResult Login(/*---*/)
{
GenericIdentity identity = new GenericIdentity("userName");
GenericPrincipal principal = new GenericPrincipal(identity, new string[] { "role1", "role2" });
this.HttpContext.User = principal;
/*---*/;
}
}
After login, I can get user name by User.Identity.Name in other controller.
But User.IsInRole("role1") always return false.
How can I assign a value to User, I don't want to use Membership...
You need to persist the user data somewhere so that all subsequent page requests have access to it. Usually you would create an authentication ticket and store it in a cookie. Then for each request you extract the data and create your IPrincipal. This can be done in the Application_AuthenticateRequest method of Global.ascx,
MVC - How to store/assign roles of authenticated users has more information on a simple way to do what you want.
Hm.
Using membership?
At least the lower level API. You need to assign it a principal in some event (which basically turns into a cookie and is deserialized with every call).
Details are in http://support.microsoft.com/kb/306590
Or also in http://msdn.microsoft.com/en-us/library/aa302399.aspx
Let's suppose I don't want to use Membership and want to restrict user's access with ActionFilter.
I know I can create a filter/attribute and override the OnActionExecuting method and further I can put this attribute in a ActionResult.
And let's assume that I have a table named 'tbUsers', it has also an int field named 'certificate' and depending on this 'certificate' value, an user can access an ActionResult or not.
But, how can I, in a OnActionExecuting mehod, check this user's 'certificate' value and grant his access or redirect to a 'NotAllowed.aspx' page?
Thanks!!!
I would not do it this way. I would implement an IAuthorizationFilter. Authorization filters run before all action filters.
For example, suppose you later put an OutputCache attribute on the action method and it happens to run before your authentication filter. That would be bad! If the content is cached, the authentication filter would never run and people would see cached sensitive data.
The ActionExecutingContext has the HttpContext which would include the current User object. You can use this to get the User. You can also use it to access the Session if you wanted to store the information in the Session. You could also put it in an encrypted cookie and access those through the Request.Cookies on the context. You'd want to think about the security implications of that, though I don't see it as being more problematic than the auth cookie.
Checking it against the database and maintaining testability on your filter is a little more tricky. What I've done is to provide two constructors for each filter class. One provides a database factory that will create my data context. I use this in testing and supply a mock database factory that produces a mock or fake database. The normal, parameterless constructor calls the previous constructor with a null factory. When this happens the other constructor creates a new instance of the default factory.
private IDatabaseFactory Factory { get; set; }
public MyFilter( IDatabaseFactory factory )
{
this.Factory = factory ?? new DefaultDatabaseFactory();
}
public MyFilter() : this(null) { }
Basically, I log into my website using OpenId, very similar to what I am assuming SO does. When I get the information back, I throw it into a database and create my "Registered User". I set my AuthCookie:
FormsAuthentication.SetAuthCookie(user.Profile.MyProfile.DisplayName, false);
Then I can use this for the User Name. However, I would like to pass in the entire object instead of just the string for display name. So my question is:
How does SO do it?
Do they extend/override the SetAuthCookie(string, bool) method to accept the User object, i.e. SetAuthCookie(User(object), bool).
What is the best way to persist a User object so that it is available to my UserControl on every single page of my Web Application?
Thanks in advance!
You can achieve this behavior by implementing your custom Membership Provider, or extending an existing one. The provider stores user information based on a key (or just by user name) and provides access to the MembershipUser class, which you can extend however you wish. So when you call FormsAuthentication.SetAuthCookie(...), you basically set the user key, which can be accessed be the provider.
When you call Membership.GetUser(), the membership infrastructure will invoke the underlying provider and call its GetUser(...) method providing it with a key of the current user. Thus you will receive the current user object.
Jeff,
As I said in a comment to your question above, you must use the ClaimedIdentifier for the username -- that is, the first parameter to SetAuthCookie. There is a huge security reason for this. Feel free to start a thread on dotnetopenid#googlegroups.com if you'd like to understand more about the reasons.
Now regarding your question about an entire user object... if you wanted to send that down as a cookie, you'd have to serialize your user object as a string, then you'd HAVE TO sign it in some way to protect against user tampering. You might also want to encrypt it. Blah blah, it's a lot of work, and you'd end up with a large cookie going back and forth with every web request which you don't want.
What I do on my apps to solve the problem you state is add a static property to my Global.asax.cs file called CurrentUser. Like this:
public static User CurrentUser {
get {
User user = HttpContext.Current.Items["CurrentUser"] as User;
if (user == null && HttpContext.Current.User.Identity.IsAuthenticated) {
user = Database.LookupUserByClaimedIdentifier(HttpContext.Current.User.Identity.Name);
HttpContext.Current.Items["CurrentUser"] = user;
}
return user;
}
}
Notice I cache the result in the HttpContext.Current.Items dictionary, which is specific to a single HTTP request, and keeps the user fetch down to a single hit -- and only fetches it the first time if a page actually wants the CurrentUser information.
So a page can easily get current logged in user information like this:
User user = Global.CurrentUser;
if (user != null) { // unnecessary check if this is a page that users must be authenticated to access
int age = user.Age; // whatever you need here
}
One way is to inject into your controller a class that is responsible for retrieving information for the current logged in user. Here is how I did it. I created a class called WebUserSession which implements an interface called IUserSession. Then I just use dependency injection to inject it into the controller when the controller instance is created. I implemented a method on my interface called, GetCurrentUser which will return a User object that I can then use in my actions if needed, by passing it to the view.
using System.Security.Principal;
using System.Web;
public interface IUserSession
{
User GetCurrentUser();
}
public class WebUserSession : IUserSession
{
public User GetCurrentUser()
{
IIdentity identity = HttpContext.Current.User.Identity;
if (!identity.IsAuthenticated)
{
return null;
}
User currentUser = // logic to grab user by identity.Name;
return currentUser;
}
}
public class SomeController : Controller
{
private readonly IUserSession _userSession;
public SomeController(IUserSession userSession)
{
_userSession = userSession;
}
public ActionResult Index()
{
User user = _userSession.GetCurrentUser();
return View(user);
}
}
As you can see, you will now have access to retrieve the user if needed. Of course you can change the GetCurrentUser method to first look into the session or some other means if you want to, so you're not going to the database all the time.
Where do I get information about the currently connected user? That is, how does shibboleth pass the information?
Can I set some restrictions on actions using [Authorize] attribute based on data acquired from shibboleth?
Shibboleth publishes user attributes associated with
sessions into HTTP request headers, based on header names defined
in Attribute Acceptance Policy (1.3.x) or Attribute Mapping (2.x)
files. These headers are transformed into CGI variables based
on mapping rules defined by the CGI specification.
You should be aware of this security advisory:
http://shibboleth.net/community/advisories/secadv_20090615.txt
I have never user shibboleth, but you can get information about the user from Controller.User property. It will return a generic principal of current thread. Using this principal you can check whether the user is authenticated and get a login name of the user. This is due to the reason that after logon an authentication cookie is set and this cookie contains limited amount of information. And on each request after logon only this cookie is checked (if it exists and valid - user is authenticated).
So if you need in some specific information you can manually load a user (it's better to use cache here) and check whatever you want.
Also you can create and attach your own principal with necessary information to the thread on start of a request (e.g. on start of a request load the user from db/cache using user name from base principal, create and set your own principal to thread). After this you can check all properties of the user you need.
Where would you attach your own principal? You say on the start of the request but what if you don't want every request authorizing?
You'll want to create a method in Global.asax.cs that has the following signature
protected void Application_PostAuthenticateRequest()
{
//Your code here.
}
This will be called automatically before almost anything else is done (MVC will call this method if it exists, you don't have to "turn it on" anywhere), and this is where you need to set the Principal. For instance, let's assume you have a header called RolesHeader that has a comma separated value of roles and another header called UserId that has (duh) the user ID.
Your code, without any error handling, might look something like:
protected void Application_PostAuthenticateRequest()
{
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
}
It's the Principal/Identity that the [Authorize] attribute uses, so setting it here at the beginning of the request lifecycle means the [Authorize] attribute will work correctly.
The rest of this is optional, but I recommend it:
I like to create my own custom classes that implement IPrincipal and IIdentity instead of using the GenericPrincipal and GenericIdentity, so I can stuff more user information in it. My custom Principal and Identity objects then have much more rich information, such as branch numbers or email addresses or whatever.
Then, I create a Controller called BaseController that has the following
protected new CustomPrincipal User
{
get
{
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
}
}
This allows me to access all my rich, custom Principal data instead of just what's defined in IPrincipal. All of my real controllers then inherit from BaseController instead of directly from Controller.
Obviously, when using a custom Principal like this, in the Application_PostAuthenticateRequest() method, you'd set the Context.User to be your CustomPrincipal instead of a GenericPrincipal.