How do/Should I persist a ClaimsPrincipal? - asp.net

I've just watched the Introduction to Identity and Access Control in .NET 4.5 video on Pluralsight. I am trying to convert an old webforms app (not MVC and not OWIN) from this...
Dim authTicket As New FormsAuthenticationTicket(1, "Bob", DateTime.UtcNow.ToLocalTime(), DateTime.UtcNow.ToLocalTime.AddMinutes(60), False, "Master")
Dim authCookie As New HttpCookie("MyApp", FormsAuthentication.Encrypt(authTicket))
...to a ClaimsIdentity and claims-based approach. Although ClaimsIdentity and its Claims are covered in the video, there is little mention of how to plug it all together and persist a user across pages (the stuff that's been done automatically before now).
For example, is this a valid alternative to the above for setting up the user's claims?
Dim fd As New FormsIdentity(New FormsAuthenticationTicket("MyApp", True, 60))
fd.AddClaims(New List(Of Claim) From {
New Claim(ClaimTypes.Name, "Bob"),
New Claim(ClaimTypes.Role, "Master")
})
Dim p As New ClaimsPrincipal(fd)
If so, how is ClaimsPrincipal then stored/persisted/retrieved on subsequent pages?
Currently I'm not using OWIN, but can introduce it if it will benefit this scenario.

AFAIK A ClaimsPrincipal is always converted to some kind of SecurityToken when "serialized". If it is sent by an STS this is a SAML or JWT security token. If is is remembered during a session then it is a SessionSecurityToken. Each of these tokens has a corresponding SecurityTokenHandler class.
In classical ASP.NET/MVC, You have two http modules : WSFederationAuthenticationModule and SessionAuthenticationModule. The latter makes sure the ClaimsPrincipal is stored across a session. By default, WIF uses a SessionSecurityTokenHandler and stores the ClaimsPrincipal in a bunch of cookies.
So your question becomes easier once you know that the road to serializaing a ClaimsPrincipal goes over a SecurityToken. You first convert it to a SecurityToken and then use a handler to "convert it to a string".
For you it boils down to instantiating the correct SecurityTokenHandler derivate. To deserialize it, you just call ValidateToken (which is a great method name to deserialize a token). This gives you a list of claims, which can easily be converted in a ClaimsIdentity and a ClaimsPrincipal.
To serialize it, you might have to pass over a SecurityTokenDescriptor (where you put your claims in) to convert your ClaimsPrincipal into a SecurityToken, then the SecurityTokenHandler can convert this into a "string".

Related

How do IIdentity, IPrincipal, OWIN, IdentityUser and IUser<string> fit together?

I am struggling to work out which .Net authentication concepts are still relevant in the world of OWIN, and which are now obsolete. From the pre-OWIN ASP.Net days, I am used to dealing with the .Net constructs: FormsAuthentication, FormsAuthCookie, IPrincipal, IIdentity and also custom implementations of IPrincipal (inheriting from GenericPrincipal). With the latest version of MVC (5) much of the authentication seems to have been changed be to OWIN based. Two things I am trying to understand in particular:
1)Where does IPrincipal and IIdentity and GenericPrincipal fit in?
With FormsAuthentication, custom data could be stored in the FormsAuth cookie. This could then used in the ASP.Net PostAuthenticate event to create a CustomPrincipal object, and override the default IPrincipal on the HTTPContext (per code example below). How (or does) OWIN change this?:
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
//Decrypt forms authentication cookie and retrieve some userdata
...
//Create CustomPrincipal (which inherits from GenericPrincipal)
var principal = new CustomPrincipal(userId, roles, someAdditionalUserDataFromCookie);
//Replace standard IPrincipal object on HTTPContext with custom principal
HttpContext.Current.User = newUser
}
2) Where can custom auth data be stored? In the pre-OWIN days I used the UserData value of the AuthCookie to store custom identification information (in addition to the username) - such as OrgID. Can this now be stored as a Claim in the ClaimsIdentity object? Is this a good idea? Can it still be stored in the AuthenticationTicket? Am I looking at this all wrong?!
Thanks for any help.
You will use CookieAuthenticationMiddleware instead of FormsAuthenticationModule. CookieAuthenticationMiddleware still creates a cookie with an authentication ticket but the format is different. With CookieAuthenticationMiddleware, things are designed for claims from the ground up. So, by default, you get ClaimsPrincipal with ClaimsIdentity although these classes implement IPrincipal and IIdentity.
Regarding custom authentication data, store them as claims part of the identity. One good thing about the new world is that you no longer need to use PostAuthenticate to restore your principal based on the custom data in the ticket. If you create your identity with all the required claims before calling SignIn, CookieAuthenticationMiddleware takes care of serializing claims part of identity into the ticket in the cookie and back into the identity in its entirety. Also, you will not use HttpContext.Current.User to read the principal. You will read from the OWIN context using the extension method available on the request object like so.
Request.GetOwinContext().Authentication.User returns ClaimsPrincipal
Request.GetOwinContext().Request.User returns same as above but as IPrincipal
From the controller, you can use User which is IPrincipal, which again returns the one from the context.

MVC 5 and use of claims default authentication

I have a question regarding the claims in MVC 5.
So basically imagine I have a registered user in DB, now the user is going to log in, like so:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Add more custom claims here if you want. Eg HomeTown can be a claim for the User
var homeclaim = new Claim(ClaimTypes.Country, user.HomeTown);
identity.AddClaim(homeclaim);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
So in this case i add a new claim to the identity and then i sign in this identity.
Now my questions are:
What is the use of setting this claim? (because i can also get this from the db if i need it, what is the point in this case of claim)
And how do i use it later on in the code?
Setting the Claim against the identity makes your application security more efficient and saves hitting your database each time.
The method above can be known as a Claims Transformation which often involves reading in data that is transformed into claims after authentication succeeds.
In order to read it later you can do this:
//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
//Get the country from the claims
var country = identity.Claims.Where(c => c.Type == ClaimTypes.Country).Select(c => c.Value);
Update
Just to provide some further information to the answer as discussed in the comments below.
With a Claims based approach you also benefit from being able to use a claims authorization manager which can provide a centralized/finely grained access control to resources and actions. 
If you've not used claims before it's best to think of actions against resources rather than role based permissions. That way you can drill right down and control access to each resource/action individually rather than having a multitude of roles for each one. 
I personally like to use a mixture but store the roles as claims too. 
That way I can use the standard authorization tags in mvc with roles, which read the claims and use thinktecture's attributes/ClaimsAuthorization to make the claims authorization manager pickup the more complicated rules.
A good link on implementing claims based authentication in MVC 4 is available here:
http://dotnetcodr.com/2013/02/25/claims-based-authentication-in-mvc4-with-net4-5-c-part-1-claims-transformation/

Session maintenance in cloud application ASP.Net MVC

I am developing a web application on ASP.Net MVC 4 with razor syntax. I have to deploy it on cloud, probably on Azure.
I am quiet confused about the login scheme of MVC. We have to work on multiple schemas so thats why we aren't using the membership provided by ASP.Net.
I know session maintenance and i used it in web forms but session have some serious issues with cloud.
What would be the best method to save usernames and session data?
I would avoid using the Session State to store user information or even session data, because this makes your application less scalable.
If you want to store a username, displayname, email address, ... I would suggest Claims Based authentication. Brock Allen wrote a great introduction article to get you started: Replacing forms authentication with WIF’s session authentication module (SAM) to enable claims aware identity.
The main idea is that you hand out a cookie (just like with Forms Authentication):
Claim[] claims = LoadClaimsForUser(username);
var id = new ClaimsIdentity(claims, "Forms");
var cp = new ClaimsPrincipal(id);
var token = new SessionSecurityToken(cp);
var sam = FederatedAuthentication.SessionAuthenticationModule;
sam.WriteSessionTokenToCookie(token);
And this cookie represents a ClaimIdentity which can contain one or more claims like email address etc...
private Claim[] LoadClaimsForUser(string username) {
var claims = new Claim[]
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Email, "username#company.com"),
new Claim(ClaimTypes.Role, "RoleA"),
new Claim(ClaimTypes.Role, "RoleB"),
new Claim(OfficeLocationClaimType, "5W-A1"),
};
return claims; }
In terms of session data you might want to consider Windows Azure In-Role Caching or the Windows Azure Caching Service. There's even a Session State Provider which can store the session state in cache: http://msdn.microsoft.com/en-us/library/windowsazure/gg185668.aspx.
But you can easily do this yourself without using the session state by playing with the cache keys, like this:
myCache.Put(user.Id + "_Friends", friendsList);

UI to Web Services communication with custom authorization using .NET technologies

I'm trying to design a web application that would user WCF services to access data and provide business logic. So in general the whole system would look like that:
UI (ASP.NET MVC)
BusinessLayer (WCF Services)
DataLayer (Entity Framework)
Date (SQL Server Database)
All parts of the system will resist on the same, closed environment, so I'm going to use Certificates to secure ASP.NET <-> WCF connection. Database connection would use standard EF securities, Connection String and Windows Authentication.
The application has to provide authentication and authorization functionality. I'm going to move most of that into ASP.NET, so there will be ValidateUserAuth() service method, which will be used to validate credentials, but the result (with UserRole that user belongs to) will be then used by ASP to create user session.
After that, every Service Method call needs to know the UserRole of current user, to return proper results (or say 'Access denied' if it's necessary). Problem is I don't want to pass that UserRole as a parameter for every Service Method! I'd like to make it happen automatically. Is it even possible with WCF?
All I need is:
Every service call made from ASP.NET app will be extended with User data taken from current ASP Session.
Service Method invoked by that call will be able to recieve that User data and use it to provide results according to user permissions.
All this would happen somekind on background, so there will be no additional UserDetails method parameter added to every Service Method exposed from Service.
I read a lot about WCF itself, but found anything that could met my requirements. I hope I just missed it and it's still possible.
Passing user roles from the client to the server in a plain form would be a design mistake. Clients could easily misuse your services by calling them freely, outisde of the application scope.
Why don't you rely on a role provider? This way all you pass from the client is the identity (could even be a forms cookie) and then at the server side you read all roles. You could probably even use a built in mechanism to cache roles in a role cookie.
Some time ago I wrote two tutorials on wcf securing with forms authentication so that integration between web pages and active clients is easy
http://netpl.blogspot.com/2008/02/clickonce-webservice-and-shared-forms.html
http://netpl.blogspot.com/2010/04/aspnet-forms-authentication-sharing-for.html
I decided to use MessageInspector for that:
On Client-side:
Public Function BeforeSendRequest(ByRef request As System.ServiceModel.Channels.Message, channel As System.ServiceModel.IClientChannel) As Object Implements System.ServiceModel.Dispatcher.IClientMessageInspector.BeforeSendRequest
Dim requestMessageProperty = New HttpRequestMessageProperty()
Dim currentUser = Authentication.AuthenticatedStaffcareUser
If currentUser Is Nothing Then Throw New ApplicationException()
requestMessageProperty.Headers("UserName") = currentUser.UserName
requestMessageProperty.Headers("UserId") = currentUser.UserID
requestMessageProperty.Headers("UserRole") = currentUser.UserRole
requestMessageProperty.Headers("EffectiveDate") = currentUser.EffectiveDate
request.Properties(HttpRequestMessageProperty.Name) = requestMessageProperty
Return Nothing
End Function
And Server-side:
Public Function AfterReceiveRequest(ByRef request As Message, channel As IClientChannel, instanceContext As InstanceContext) As Object Implements IDispatchMessageInspector.AfterReceiveRequest
Dim messageProperty = CType(OperationContext.Current.IncomingMessageProperties(HttpRequestMessageProperty.Name), HttpRequestMessageProperty)
Dim userName = messageProperty.Headers("UserName")
Dim userId = Integer.Parse(messageProperty.Headers("UserId"))
Dim userRole = messageProperty.Headers("UserRole")
Dim effectiveDate = DateTime.Parse(messageProperty.Headers("EffectiveDate"))
Dim identity = New AppServerUserIdentity(userName, userId, userRole, effectiveDate)
Dim principal = New AppServerUserPrincipal(identity)
Threading.Thread.CurrentPrincipal = principal
Return Nothing
End Function
I also had to set custom AuthorizationPolicy to prevent standard one from overwriting Thread.CurrentPrincipal:
Public Function Evaluate(evaluationContext As EvaluationContext, ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate
Dim principal = TryCast(Threading.Thread.CurrentPrincipal, AppServerUserPrincipal)
If principal Is Nothing Then
Return False
Else
evaluationContext.Properties("Principal") = principal
Return True
End If
End Function

How do I get current logged in user's UserID when using ASP.NET Forms Authentication?

I am currently having trouble in ASP.NET (with Silverlight 4). I need to get the UserID of the currently logged in user, (I am using Forms Authentication). How can I get this value?
You can create a custom Forms Authentication ticket and write additional data into the ticket. Once authenticated you can then read that extra value out of the ticket.
In a lot of my apps I tend to store the user's ID and display name in there to avoid having to hit the database for every request and that works well.
To manually create a ticket looks like this:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userState.UserId,
DateTime.Now, DateTime.Now.AddDays(10),
rememberMe, userState.ToString());
string ticketString = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticketString);
if (rememberMe)
cookie.Expires = DateTime.Now.AddDays(10);
HttpContext.Response.Cookies.Add(cookie);
You can basically pass two value - the name parameter (second) and the user data. If you want data beyond the username you can use the userdata parameter.
Then when you need to read the data make sure you're authenticated first, then you can read the user data:
if (this.User.Identity != null && this.User.Identity is FormsIdentity)
userData = ((FormsIdentity)this.User.Identity).Ticket.UserData;
What you store in userData is up to you really. It can be a simple value (like your user id) or something more complex like an object that you can serialize to and from a string.
If i am correct you want to pass UserID from web application to silverlight application.
1st step:Add a web service(.asmx/.svc) in web application create a operation contract for the same.
2nd step:In web service get userId and return the same.
3 step:Add service reference in silverlight app of web service created in web
4 th step call the method using async method.
here is the link which should help you http://www.codeproject.com/Articles/37522/7-Simple-Steps-to-Connect-SQL-Server-using-WCF-fro

Resources