Using the ASP.Net Identity 2 provider model in conjunction with plain Authorize attributes.
Anonymous access is true, Windows authentication is disabled.
HttpRequestBase.IsAuthenticated will return true, how-ever, the HttpRequestBase.LogonUserIdentity will not return the actual ClaimsIdentity but instead an impersonated user (me as I'm running IIS Express locally).
The actual authenticated and returned ClaimsIdentity from the provider is accessible via e.g.
HttpContext.Current.User... and/or System.Threading.Thread.CurrentPrincipal...
Q: Why not via HttpRequestBase.LogonUserIdentity?
First time I see this property used. The documentation says this property should return WindowsIdentity of the current user. MVC app does not know about WindowsIdentity of the logged in user, because there is no such thing.
Also in source code for this property eventually asks for server variables.
I usually access currently logged-in user via ClaimsPrincipal.Current and never seen user retrieved from HttpRequestBase.LogonUserIdentity.
Also HttpRequestBase.IsAuthenticated is identical to calling HttpContext.Current.User.IsAuthenticated with few null-checks.
Related
I have set up a Blazor application in .NET Core 3.1 and I'm implementing authentication/authorization, but it is clear I just don't have a great understanding of how default authentication works.
I set up an "AuthorizeView" tag as follows, fully expecting it to fail:
<AuthorizeView Context="auth" Roles="Admin">
<Authorized>
Content
</Authorized>
<NotAuthorized>
You do not have access to this page.
</NotAuthorized>
</AuthorizeView>
but instead it works fine. I am able to see the "Content" section, despite the fact I have not set up ANY authorization. I'm assuming this defaults back to something like Windows Authentication (which is what I'm using in my Blazor app) but I'm not specifying to use AD Authorization anywhere.
Can anyone point me to where I would go, or help me understand, how this is working by default and where it is pulling this "Admin" role from?
You can control and limit access to your resources using authorization. You can control access depending on the roles of the user, claims and authorization policy.
Using the AuthorizeView above and setting the Roles attribute to "Admin", you tell Blazor that if the user belongs to the Admin role, he is authorized to access the content within Authorized element.
I guess that you've set your Blazor app to authenticate users accessing your app by selecting Windows Authentication, when creating your app, right ?
When you try to access your app, you are asked to provide your credentials which are passed from IIS (express) to your app...
Roughly speaking a Claims Principle( or Windows Principle) object is created by Blazor and passed to an object named ServerAuthenticationStateProvider as an AuthenticationState object. This object, meaning the AuthenticationState object is also provided to the AuthorizeView whose base class AuthorizeViewCore contains the logic to call the IAuthorizationService, passing it the claims principle. Now the authorization service inspect the Claims Principle object, what claims it has, what roles it has, and of course it looks for a role claim with the value "Admin", if found, true is returned, and at the end of the pipe line it is decided that you are allowed to access the restricted content.
where it is pulling this "Admin" role from
From your Windows AD if you've one or from windows user accounts, etc. Remember, you told the wizard that you want to use Windows authentication (this is my supposition, otherwise everything I've said may be wrong).
You had better go to the docs and acquaint yourself with services like AuthenticationStateProvider, ServiceAuthenticationStateProvider ,etc.
Did ADFS change recently with respect to how the upn gets mapped to User.Identity.Name in ASP.NET?
What I know:
ASP.NET web app that authenticates externally via ADFS
test environment worked OK with no outgoing Name claim defined in ADFS a few months ago
test environment was fired up recently and ADFS login failed. ADFS server did not have any configuration changes
issue is that User.Identity.Name is null even though Request.IsAuthenticated is true
root cause is that there is no Name claim and there appears to be no explicit mapping in web.config to use upn for this
From Microsoft:
https://msdn.microsoft.com/en-us/library/mt740689(v=vs.85).aspx
When you pass a valid security token to the AD FS Web Agent, it
creates an session cookie and processes the token's claims into the
session's User object. This object is derived from IPrincipal, and
exposes one method, IsInRole(), with which you can query the User and
determine whether that user asserts the specified role claim (using a
string to specify the role).
IPrincipal also exposes one property, Identity, which returns the
user's identity, represented as an IIdentity object. This object can
be used by the default.aspx page to determine whether the User is
authenticated (by calling IsAuthenticated(). It also allows you to
determine whether the user is asserting a name claim by accessing the
Name property, which returns a string representing the User's name.
The snippet here illustrates the use of both of these techniques.
I have questions about this that I can't find in Microsoft docs:
What specifically is meant (as in: which xml attribute or specific ADFS claim string) by "the user is asserting a name claim" ? (it is ambiguous: is it "name" claim? because it reads more like "name claim" where "name" could be loosely defined as user name, and often upn is used for this, and was working in the past)
What is the exact logic used by .NET for setting User.Identity.Name when using configuration-based identity with ADFS (defined in web.config)?
AFAIK, this "Name" logic did not change in the latest versions of the framework.
As explained here for instance, by default the claim type used to populate the Identity.Name property has always been:
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
So if your SAML token contains such claim, it will be used as the "name" of the user (it is up to you to decide which AD attribute you want to put in this claim: userPrincipalName, displayName, mail, ...).
This default attribute can be overriden in code, or in your web.config. This page mentions a "<nameClaimType />" element, honestly I don't remember if it has changed in the meantime.
a
Note: your link is really old. The "ADFS Web Agent" was something from the first version of ADFS, but it was rapidely superseded by WIF.
I am developing an ASP.NET website. I am planning to use Forms authentication in order to guarantee authentication/authorization, but I am facing two problems regarding the authorization:
I know how to set in the web config that the authenticated users are allowed to visit a webpage (say myPage.aspx). But I do not know how to define that UserA is able to access myPage to retrieve his information, not UserB's information.
I was thinking about generating a token when the user authenticates, so I am able to check to whom this token belongs to and verify if this information is available to him.
What do you think about this approach? Does the Form Authentication generates a token like that? (I couldn't find any mention about it in my research). If not, could I adapt the Form authentication mechanisms in order to generate or would I need to write everything on my own?
I would like to access webservices, and these should only return information if the user is logged. For this reason, I would like to use the same token explained above. What do you think about it? Is it a good approach?
I am asking this because I have no experience on designing authentication/authorization mechanisms, any help/hint would be appreciated.
Regarding question one, after forms authentication occurs in an ASP.Net web forms app, the user's identity is exposed as a FormsIdentity object in the Page.User.Identity property. This object has a Name property which contains the username that a user use to log into your site. You can use this value to restrict what a user can access. For example, let's say you have a table in your database with user information containing the following fields:
userId int
userName varchar(25)
...more fields containing user information...
You can restrict a user to only access information from the row in this table in which the userName equals the Page.User.Identity.Name property, either directly if you are using direct ADO.Net or via your query to your ORM-mapped (i.e. nHibernate or EF) domain object.
Regarding question two, the FormsIdentity object exposed by Page.User.Identity has a boolean "IsAuthenticated" property. You can use this to restrict access to your web service as follows:
if(Page.User.Identity.IsAuthenticated)
{
//Call your web service in a secure manner
}
I am reading on form authentication in ASP.NET and cannot understand some moment:
James enters a username-password, they are saved in the db. A cookie from username is created, encrypted and attached to a response. As I understand then, when we get a request we need to recognise that cookie received are from James and so we can show his customised page.
What I would like to understand is how system will retrieve username form cookie and then load his info from db?
Forms Auth is storage agnostic. It doesn't have to use a database, indeed you can use it with usernames and passwords in web.config.
So what happens is
A user logs in.
The user is authenticated against the membership provider (which can use SQL, Active DIrectory, web.config, Oracle, MySQL, whatever)
A forms authentication token is created for the user, and is placed on the user machine via a cookie.
Each subsequent request reads the forms authentication token, and queries the provider to get the user details.
The user details are used to populate the user identity in the HttpContext and current thread for the request which is then available to your code to use.
In your code you can check the User property in the Page class (WebForms) or the User property in the controller class (MVC).
While you can get at it via the current thread, or the current context it's not advised, especially once you start using background tasks, where the identity may not propagate to the thread, or the context may change.
You'll note that nothing is stored in a database when the user logs in. It's all in the forms authentication token, and the work of retrieving the user from it's store on each request is done for you.
Afaik Forms Authentication does not store or load anything in any database. You can use a database to store the username and password, or you can put them in the web.config. How you store user credentials and validate them is up to you, and can happen separately from Forms Authentication.
Once you have validated a user (against database or some other logical storage), you use FormsAuthentication to write the authentication cookie. You do not need to worry about decrypting the cookie.
You can get the username from System.Threading.Thread.CurrentPrincipal.Identity.Name. To retrieve user's info from the database, you would query the database using the value if the principal identity name.
Response to comments
Right, you can use forms authentication with the membership provider, active directory, or your own custom user database. FormsAuth doesn't care about the password at all, unless it is stored in web.config (as noted in blowdart's more complete answer). It just writes the cookie, which is decrypted and used to create the thread identity automatically.
Additional Info
Even though this was marked as the answer, blowdart's response is much more complete. You really should not get the identity from the thread if you need it in an ASPX page or MVC controller, use the properties he referenced.
You get the username in your web form by calling User.Identity.Name, e.g. like this:
protected void Page_Load(object sender, EventArgs e)
{
string userName = User.Identity.Name;
}
ASP.NET interprets the cookie for you, you don't have to read it yourself. Or is your question how to store the user and password in the DB?
We have an ASP.NET application that manages it's own User, Roles and Permission database and we have recently added a field to the User table to hold the Windows domain account.
I would like to make it so that the user doesn't have to physically log in to our application, but rather would be automatically logged in based on the currently logged in Windows domain account DOMAIN\username. We want to authenticate the Windows domain account against our own User table.
This is a piece of cake to do in Windows Forms, is it possible to do this in Web Forms?
I don't want the user to be prompted with a Windows challenge screen, I want our system to handle the log in.
Clarification: We are using our own custom Principal object.
Clarification: Not sure if it makes a difference or not, but we are using IIS7.
Integration of this sort is at the server level, it's IIS that decides that the user is not logged in; and it's IIS that sends back the authentication prompt to the user, to which the browser reacts.
As you want to use the domain login there is only one way to do this; integrated windows authentication. This will only work if the IIS server is also part of the domain and the users are accessing the machine directly, not through a proxy, and from machines which are also part of the domain (with the users suitably logged in).
However your custom principal object may create fun and games; authentication of this type will be a WindowsPrincipal and a WindowsIdentity; which you can access via the User object (see How To: Use Windows Authentication in ASP.NET 2.0)
I assume you want a custom principal because of your custom roles? I doubt you can get the two to play nicely; you could create a custom role provider which looks at your data store or look at you could look at ADAM, an extension to AD which provides roles on a per program basis and comes with nice management tools.
I did pretty much exactly what you want to do a few years ago. Im trying to find some code for it, though it was at a previous job so that code is at home.
I do remember though i used this article as my starting point. You set up the LDAP provider so you can actually run a check of the user vs the LDAP. One thing to make sure of if you try the LDAP approach. In the setting file where you set up the LDAP make sure LDAP is all caps, if it is not it will not resolve.
using System.Security.Principal;
...
WindowsPrincipal wp = (WindowsPrincipal)HttpContext.Current.User;
to get the current domain user. Of course you have to make sure that the IIS is set up to handle Windows Authentication.
This might be helpful:
WindowsIdentity myIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal myPrincipal = new WindowsPrincipal(myIdentity);
string name = myPrincipal.Identity.Name;
string authType = myPrincipal.Identity.AuthenticationType;
string isAuth = myPrincipal.Identity.IsAuthenticated.ToString();
string identName = myIdentity.Name;
string identType = myIdentity.AuthenticationType;
string identIsAuth = myIdentity.IsAuthenticated.ToString();
string iSAnon = myIdentity.IsAnonymous.ToString();
string isG = myIdentity.IsGuest.ToString();
string isSys = myIdentity.IsSystem.ToString();
string token = myIdentity.Token.ToString();
Disclaimer: I got this from a technet article, but I can't find the link.
You can use System.Threading.Thread.CurrentPrincipal.
Request.ServerVariables["REMOTE_USER"]
This is unverified for your setup, but I recall using this awhile back.
Try Request.ServerVariables("LOGON_USER").
If the directory security options are set so that this directory does not allow anonymous users, when the surfer hits this page they will be prompted with the standard modal dialog asking for username and password. Request.ServerVariables("LOGON_USER") will return that user.
However, this will probably not work for you because you are using your own custom security objects. If you can figure out how to get around that logon box, or pass in NT credentials to the site before it askes for them, then you would be all set.
Have you thought about impersonation? You could store the user's NT logon credentials in your custom security object, and then just impseronate the user via code when appropriate.
http://msdn.microsoft.com/en-us/library/aa292118(VS.71).aspx