Im doing claims based user role authentication. For this authentication i tested the following:
var identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, name),
new Claim(ClaimTypes.Email, email),
new Claim(ClaimTypes.StreetAddress, Address),
new Claim(ClaimTypes.Role, "Admin")
},
My authentication works just fine, but the i realized that i should implement some kind of security in order to avoid that the user can tamper the set role.
Therefore i stumbled across this, that is supposed to be added in the Global.asax:
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
I can't seem to exactly understand what this code above does? Am i right, if i say that it gives the cookie, that the user holds, a unique token made from the email, that then is used to validate the legitimacy of the user by the system?
Im new to this, by the way, so go easy on me :-)
I'm not quite sure what you're meaning by your question, but let me try to clear out a few things.
First, let's talk about your AntiForgeryConfig line of code. What it does is configure the AntiForgeryToken to use the Email claim to identify the request (creates a token based on the email). The AntiForgeryToken allows you to trust a request and prevent Cross-Site Request Forgery (CSRF).
It is implemented in 2 parts. First you need to add the AntiForgeryToken to the form (#Html.AntiForgeryToken). Second, you need to validate the token in your controllers' actions (ValidateAntiForgeryTokenAttribute).
Here is a link to explain what CSRF
Here is a link with up to date code how to implement it
As a side note, you said ... to avoid that the user can tamper the set role. AntiForgeryToken doesn't do anything about tampering roles. Tampering roles would more related to your authentication process.
Related
So at work I was given the task of designing a database API, now security assessment has stated that the system must use Authentication and Authorization.
On top of that Authentication Happens through their NetScalar that forces the user to login with company credentials and in turn gives the user a token. This token will then be sent to my API in the header of each request.
Now here comes the issue. The token only contains a username, I however want to do a
[Authorize(Roles = "Admin")]
Check on my controllers. Now as the user has already been authenticated with his password and username I know that he has is a valid user however I would like to assign a role to him.
Now I'm open for suggestions on how to do this but the simplest way of fixing this that I could think of was to at each request query my DB for the users role and add it to the token claims.
However I don't know how to do this and also I have no idea if this is a good solution.
I would appreciate any help with adding the claims (in code) or other solution (also code would be much appreciated).
Thank you!
To add ADFS 3.0 authentication in our SPA we use the javascript sample and one (wsfed) external identityprovider, and we also add a local api for the SPA client
We also added a custom view to the login process, where the user could "Select WorkingContext" and we could set an additional claim.
Problem: How to add and retrive that additional claim?
Since we simply need the a few of the claim from ws federation, we've made a super simple callback where we just do the following (I'm answering the questions from the docs)
Handling the callback and signing in the user
inspect the identity returned by the external provider.
Yes, we get correct claims from wsfed
make a decision how you want to deal with that user. This might be different based on the fact if this is a new user or a returning user. New users might need additional steps and UI before they are allowed
in.
No additional steps required
probably create a new internal user account that is linked to the external provider.
No, we don't need the user, we just need the a few of the claims from wsfed, so we just return a TestUser based on the wsfed sub in FindUserFromExternalProvider
store the external claims that you want to keep.
Do we need to store the claims, will the claims not be embedded in the jwt token, and the token simply validated?
delete the temporary cookie
ok
sign-in the user
Here we would like to show a custom ui where the user should select a "workingcontext", and we could add the "workingcontext" as an additional claim.
Assuming the above is valid, how can we in step 6 add the extra claim?
await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username, true, context?.ClientId));
doesn't seem to give any ways to add claims.
This is how we try to pass the additional claims through the login process:
var isuser = new IdentityServerUser(user.SubjectId)
{
DisplayName = user.Username,
IdentityProvider = provider,
AdditionalClaims = additionalLocalClaims
};
await HttpContext.SignInAsync(isuser, localSignInProps);
We just need to implement the IProfileService, that's all.
I'm building a custom ASP.NET Identity 2.0 implementation that uses our own data model, another ORM, other business logic, etc. By default, a user is logged in by setting the ApplicationCookie, after which the AuthorizeAttribute recognizes the cookie and logs the user in. For our own implementation, I want to add more ways to log in. For example:
Impersonation
Password reset token
Google Authenticator (two-factor)
SMS (two-factor)
In all these scenarios the user must be logged in, but what actions the user is allowed to perform depends on the way he logged in. For example: when the user logged in using a 'password reset token', he may change his password but not do anything else. When the user logged in with 'username + password', he may do basically everything, except for the actions that need a higher permission level (where the two-factor methods come in play). In order to do this, I want to build a custom AuthorizeAttribute that checks what login method was used, and then decides whether the user may perform the action or not.
The problem I'm facing is that I can set other cookies than ApplicationCookie (e.g. the TwoFactorCookie that is being set by going through the SMS process), but those cookies are not recognized as authentication cookies. Thus, when I have a TwoFactorCookie, I can't use that cookie to log in. Only having an ApplicationCookie results in a log in.
The issues I'm struggling with:
Do I always need to use ApplicationCookie to log in or can I use custom cookies to log in as well (so for example I can log in using ApplicationCookie, TwoFactorCookie and XYZCookie?
Should I have different cookies for each authentication method or should I have only 1 cookie and store the authentication method/type in a different way (for example in a Claim)?
If I should use different cookies, should I also write custom authentication middleware for each authentication method/type or can I use the default CookieAuthenticationMiddleware? As far as I know, the only thing that has to be done is set a cookie, and flag it with the correct authentication method so I can see how the user was logged in.
Edit:
As per Hao Kung's suggestion I made a couple of extension methods that look like this:
public static void UseSmsSignInCookie(this IAppBuilder app, TimeSpan expires)
{
if (app == null)
throw new ArgumentNullException("app");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = ApplicationAuthenticationTypes.Sms,
AuthenticationMode = AuthenticationMode.Passive,
CookieName = CookiePrefix + ApplicationAuthenticationTypes.Sms,
ExpireTimeSpan = expires,
});
}
I try to log someone in by calling AuthenticationManager.SignIn with a custom ClaimsIdentity that has my custom AuthenticationType (SMS). This doesn't work though: after calling SignIn, the result of HttpContext.Current.User.Identity.AuthenticationType still equals ApplicationCookie. The cookie has been set as expected though.
Does anyone have an idea what I'm missing?
So each instance of a CookieMiddleware basically represents one auth cookie, if you want multiple cookies, you can add more than one CookieMiddleware and to retrieve the ClaimsIdentity mapping to your cookie, you just need to call Authenticate on the AuthenticationManager passing in the AuthenticationType for the cookie you want.
Is there a way to pass a value back to a relying party after login? e.g. on the querystring?
Background:
What we want to do is inform the relying party what action the user took, e.g. sign in or register, so that the relying party can display the appropriate confirmation message to the user. Because the relying party might link to a Sign Up page, but then instead of signing up the user signs in, so the relying party shouldn't display a "thanks for joining us" notification panel.
I tried adding &lastaction=signup to the returnUrl but that gets lost when the form is posted through Azure ACS.
Next attempt was to try to add lastaction to the wreply, like so:
WSFederationMessage message;
WSFederationMessage.TryCreateFromUri(uri, out message);
var signinMessage = wsFederationMessage as SignInRequestMessage;
if (signinMessage != null)
{
signinMessage.Reply += "?lastaction=hello";
...
In Fiddler I can see that the next POST to ACS posts to https://xxxxx.accesscontrol.windows.net/v2/wsfederation?lastaction=hello
But the lastaction is not passed on to my relying party.
We had a related problem: we wanted to let the RP know which authentication methods the user used when signing in. We solved this by creating a new "system" claim with our namespace, and put the information in there.
In our TokenService implementation, in the AddSecurityClaims method:
claimsIdentity.AddClaim(
new Claim(
String.Format("{0}/{1}", WellKnownConfiguration.TokenService.ClaimsNamespace,
ClaimsAuthenticationMethods), ((int) userAuthenticationMethods)));
Update
You mentioned you thought about using cookies. In that case, I would do the following. I would implement setting a cookie (e.g. when registration page) and then create one more "action" that would return the value of that cookie. When the app gets the POST request with the credentials, you'd perform a redirect (immediately) to that relaying action with a return url. That action would then append the value of the cookie and call the original RP, but a custom action, that would then properly display the view.
Think of it as a cookie proxy. To summarize, the process is as follows:
User hits the RP, action requires authentication
The RP redirects the user to the STS as per WS-Federation
STS issues a token, and also adds a cookie to its own domain
RP gets the authenticated user, redirects to STS Cookie Reader
STS redirects to RP's second screen that can handle the login properly
All in all, one more hop, but like I said, it's probably fast enough for the user to not notice and/or care.
Am trying to design login page for my website and I am looking for methods other than forms authentication. The way in which I am trying is to have a table in the database that stores user information and check for the user validity.
The point where I get struck is how do i set cookies and session variables and how will I carry it through out the system. Can anyone tell/suggest me where I can relevant material so as to move forward. And also is my idea of negating traditional forms authentication and going for a model I described, is it good also does any other better method exist?
You can do this even with forms authentication itself...
For Forms Authentication to work, you need not have to use the Complete Database Setup that MS uses to Authenticate. You can simply have your own Database and Validate a user yourself, and just set the cookie.
String UserName = "CoolGuy";
String PassWord = "Pwd"
Boolean isValidUser = YourClass.YourMethod(UserName, PassWord);
if (isValidUser)
{ FormsAuthentication.setAuthCookie(UserName, false); }
This will authenticate the user "CoolGuy" for the session, provided YourMethod returns true. And you need to put this code only in Login Page... and the user will automatically be authenticated for the entire session or whatever...
Please see my response to another similar question here... ASP.NET access controls