I'm moving from an integrated/windows authenticated system (whereby I used windows groups in the web.config's authorization section, and the web.sitemap as well as using user.identity.name for various per-user features) to an SSO solution which offers authenticated details through the http headers.
I created a very simple custom RoleProvider (overriding IsUserInRole and GetRolesForUser) which worked great for the 'allow roles' sections of the web.config, and roles section of web.sitemap.
I want to do the same for the 'users' part of authorization.. how would I go about doing this? Is it through overriding a different provider? Would it also affect what's returned by user.identity.name?
Thanks for pointing me in the right direction :)
Edit - for Jay.
Note this is likely a bit of a hacky and inexperienced fix, but it suited my purpose.. Following http://msdn.microsoft.com/en-us/library/8fw7xh74(v=vs.100).aspx you can create a class with all the required function definitions, returning false/empty string arrays as necessary.
The only functions I implemented were IsUserInRole and GetRolesForUser. The latter simply hooked into Request.ServerVariables to check the appropriate HTTP header, and format those into a String array as required. The IsUserInRole simply matches a supplied string against the string array returned by GetRolesForUser.
After that, I just referenced the above in the web.config
<roleManager defaultProvider="myroleprov" enabled="true">
<providers>
<clear/>
<add name="myroleprov" type="myApp.CustomProviders.myroleprov" applicationName="myApp"/>
</providers>
</roleManager>
I think that's about it? Hope it helps.
I think you're looking for the Membership provider: http://msdn.microsoft.com/en-us/library/system.web.security.membershipprovider.aspx
Related
I am relatively new to authorization/memberships in asp.net, so pls excuse if I ask anything silly. I have been looking at lot of examples to implement a custom membership provider in .net (in stackoverflow, codeproject, devX, and www.asp.net) and coded based on that but somehow couldn't get it working.
My requirement - our organization heavily uses HP's Quality center(QC), I am developing an asp.net application, its login page will use QC'a API for authenticating a user. I also have a SQL database in which I'll store the QC users who have registered to my application (just store QC user id's in DB, not password, like I said, password authentication is done using QC API). There will be a user-roles table in my DB to define the roles for registered users.
Why use 'membership' instead of some simple 'forms authentication' - because maybe in future I want to decouple QC authentication.
So, with this I started with first step - developing custom membership class(named AutoCenterMembershipProvider) and login page. I only need validateuser method. following is the approach I took to start with:
1. Ask user for QC user id/password, user clicks 'Authenticate' button
2. login page's code behind-'Authenticate' button's onClick method- checks if user is found in SQL database and if found, then uses QC API to authenticate user id-password
3. Second set of controls on Login page is enabled - ask user to select which QC Domain and Project user wants to login. Options for Domain and Project dropdown lists are also obtained using QC API after authenticating user. User selects those and clicks Login button
4. On Login button's click - call Membership.ValidateUser(objQCSession.UserName, objQCSession.Password). Since user is already validated using QC api, for simplicity I just return 'true' from my custom implementation of Membership.ValidateUser. Then I call - FormsAuthentication.RedirectFromLoginPage(obj_ACUser.QCSession.UserName, True) to direct user to apps default page provieded in web.config's - app_FAs.aspx.
The issue is - after user is redirected to app_FAs.aspx page, it directs user back to login page. I am trying to find out the mistake or missing piece.
Web.config looks like below:
<authentication mode="Forms">
<forms loginUrl="~\Pages\Login.aspx" defaultUrl="App_FAs.aspx"></forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
<membership defaultProvider="AutoCenterMembershipProvider">
<providers>
<clear/>
<add name="AutoCenterMembershipProvider"
type="CustomMembership.Models.AutoCenterMembershipProvider"
enablePasswordRetrieval="false" enablePasswordReset="false"
requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="100" minRequiredPasswordLength="100"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="100" applicationName="/" />
</providers>
</membership>
and customMembership class is like:
Public Class AutoCenterMembershipProvider
Inherits System.Web.Security.MembershipProvider
Public Overrides Function ValidateUser(ByVal username As String, ByVal password As String) As Boolean
Return True
End Function
rest all members are 'Not implemented'
any help, pointers to missing piece, mistake is greatly appreciated, thanks in advance
Authenticate button click code
Private Sub btn_Authenticate_Click(ByVal sender as Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btn_Authenticate.click
objQCSession = Session("QCUserSession")
If Membership.ValidateUser(objQCSession.UserName, objQCSession.Password) then
FormaAuthentication.RedirectFromLoginPage(objQCSession.UserName, True)
End if
End Sub
Currenlty, 2nd step - btn_Authenticate_Click method 1 - is just to assign FormAuthenticationTicket to cookie, and redirecting user to app_FAs.aspx page. It doesn't really need Custom Membership Provider's features.
If I understand your problem correctly, I would change the logic like this.
1) After validating user for QC, create FormAuthenticationTicket like this in the same method.
FormsAuthentication.SetAuthCookie("UserName", true|false);
2) btn_Authenticate_Click (does something and) redirects user to app_FAs.aspx
You do not even need Custom Membership Provider. If you want to use Custom Membership Provider, you can implement in 1st step (Not in 2nd step).
I am creating an ASP.NET MVC 4 web application. I googled about custom membership, but I couldn't find good resources or video lectures.
Most of them are either outdated or dead links. Please could you suggest some resources about how to start writing a membership and role provider.
Understanding about membership and roles was pretty difficult for me too, as you said there are not many reliable and detailed content you will find on web. I tried watching several videos to Understand about this topic but wasn't clear. But then two articles from a website called Code Project came for the rescue. I am sharing these Link where you can see a step by step guide about customize membership
Link 1
The link 1 will help you to replace an email with username for login authentication this is one of the most common customization the developers need in the microsoft provided Identity Module.
Link2
The second article will help you understand adding and attaching roles to the created user and how to limit the access of user registration page to an Admin only. This way with the help of these two articles I hope that you will Understand the Basics of Authentication and Authorization.
I suggest using ASP.Net Identity instead of old membership.ASP.Net Identity is a way better and more flexible than old membership, it also supports role-based authentication using action filters and you can implement your own customized providers (such as role and user providers).
see links below
https://weblog.west-wind.com/posts/2015/Apr/29/Adding-minimal-OWIN-Identity-Authentication-to-an-Existing-ASPNET-MVC-Application
http://www.c-sharpcorner.com/article/create-identity-in-simple-ways-using-asp-net-mvc-5/
The ASP.NET MVC 4 Internet template adds some new, very useful features which are built on top of SimpleMembership. These changes add some great features, like a much simpler and extensible membership API and support for OAuth. However, the new account management features require SimpleMembership and won't work against existing ASP.NET Membership Providers
Check out resources for ASP.NET Identity here:
http://www.asp.net/identity/overview/getting-started/aspnet-identity-recommended-resources
http://logcorner.com/how-to-configure-custom-membership-and-role-provider-using-asp-net-mvc4/
**for creating a CustomerMemberShipClass** your class must implement System.Web.Security.MembershipProvider abstarct class. and you override the method ValidateUser()
in this ValidateUser() you have to write your own logic based on which you want authenticate user and return true or false according to it.
Sample ValidateUser method
public override bool ValidateUser(string username, string password)
{
int count=db.GetAll().Where(x => x.UserEmail == username && x.password == password).Count();
if (count != 0)
return true;
else
return false;
}
later in web.config file you have add the fallowing under <sytem.web> element
<membership defaultProvider="MyMembershipProvider">
<providers>
<clear/>
<add name="MyMembershipProvider" type="Write your class name that is implementing membershipproviderclas"/>
</providers>
</membership>
after doing this you can validate user using **MemberShip.Validate(Username,password)** which returns true or false based on ur code in ValidateUser() in CustomMemberShipProvider class and this will also set **[Authorize] attribute**
**for creating a CustomRoleProviderClass** your class must inherit System.Web.Secuirty.RoleProvider and override the appropriate method to get the roles for the user
SAmple method for getting roles for user
public override string[] GetRolesForUser(string username)
{
string[] str={db.GetAll().Where(x=>x.UserEmail==username).FirstOrDefault().Role};
return str;
}
after this you must add the fallowing in web.config file in <system.web> element
<roleManager enabled="true" defaultProvider="MyRoleProvider">
<providers>
<clear/>
<add name="MyRoleProvider" type="BLL.DoctorAppointmentRoleProvider"/>
</providers>
</roleManager>
and after this u can check the role of the user using attribute **[Authorize(role="admin"])** and in Razor view you can check using User.IsinROle("A").
I would like to take advantage of:
Page.User.IsInRole("CustomRole");
Page.User.Identity.IsAuthenticated
when working inside Page methods, as well as authorization section in web.config:
<authorization>
<allow roles="Administrators, Supervisors" />
<deny users="*" />
</authorization>
and also apply rules on classes and methods level:
[PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
In my application I authenticate with ... custom mechanism that provides me user identity in ... http header. I get users PIN number (some kind of ID) + roles. But that is a side plot. It doesn't matter.
What I actually want to achieve is to take advantage of ASP .NET build in Authorization features but having my custom authentication mechanism. I guess I have to implement IPrincipal and IIdentity, is that right? I saw plenty of samples on the web but all of them include web.config configuration that specifies providers, and also FormsAuthentication like classes, that I guess I don't need. I just need to inject my user object (which is prepared by me) into request and that's it.
So:
what's the easiest way to achieve it?
what is the difference between GenericPrincipal / IPrincipal?
how to get/create IIdentity object? I saw samples with:
var id = new FormsIdentity(authTicket);
but I'm not using FormsAuthentication.
Thanks
In short, you have to implement your own authentication module.
An authentication module is just an ASP.NET module but having special purpose. Its AuthenticateRequest method should populate HttpContext.Current.User property with an instance of IPrincipal.
Answering your other questions: IPrincipal is just an interface while GenericPrincipal is one of its implementations. You can use it, as the name suggests it's just a generic implementation which means that it should suit you. Since IPrincipal is just IIdentity plus roles, you probably will also need GenericIdentity.
Other implementations, like RolePrincipal + FormsIdentity are designed for specific purposes, these two for example are used by the Forms Authentication Module.
There are some good examples available, just google for "custom authentication module".
Before you do (create/implement your own), have you tried/considered adapting Forms Authentication to your existing auth scheme?
I think you're "almost there" (using all of the built-in ASP.net auth/membership/profiles/roles), and it maybe easier/simpler to just "plug in" your existing auth scheme into Forms Authentication.
This snippet of code should give you an idea of how flexible Forms Authentication can be:
if ((UserEmail.Text == "jchen#contoso.com") && (UserPass.Text == "37Yj*99Ps"))
{
FormsAuthentication.RedirectFromLoginPage
(UserEmail.Text, Persist.Checked);
}
else
{ ... }
So, it works with a hard coded "auth scheme" (not that you should, but gives you an idea of the possibilities), or even a list in web.config - again, just a sample:
<authentication mode="Forms">
<forms name=".FUBAR">
<credentials passwordFormat="MD5">
<user name="foo" password="b7ab5072e8fba7bed20384cc42e96193"/>
<user name="bar" password="1c42e49a360aa7cc337a268a1446a062"/>
<user name="john" password="5f4dcc3b5aa765d61d8327deb882cf99"/>
<user name="jane" password="7c6a180b36896a0a8c02787eeafb0e4c"/>
</credentials>
</forms>
</authentication>
Just a thought - hth....
I know this question is asked (and answered) a lot already, but I believe my situation is unique.
We are using the ASP.NET SqlMembershipProvider. However, we also have some less-secure content we would like to secure by adding users directly to the web.config, like so...
<forms loginUrl="login.aspx" defaultUrl="default.aspx">
<credentials passwordFormat="Clear">
<user name="user1" password="123" />
<user name="user2" password="456" />
</credentials>
</forms>
Is it possible to use this method alongside a SQL Membership Provider? If so, how?
I know it's bad practice to do this. This is only a stepping stone as we move parts of our website into the asp.net application. We would like some of those password to be easily editable without going to the database.
We would like some of those password
to be easily editable without going to
the database.
What is that logic I don't understand. Why you need two of them while you have built-in feature to change password easily in membership provider.
Now, you can use both at a time but you will need mechanism to decide when you use what or you will have to to two times authentication i.e. first validate user against web.config and if it fails then validate against membership DB.
But if you have other stuff depending on Membership explicitly, then some of those things won't work on your site.
So authentication, yes it is doable as you want.
I found my answer here: ASP.NET - Login Control with Credentials in web.config file
For my ValidateUser logic, I needed to use:
if (_provider.ValidateUser(username, password)) {
return true;
}
else {
return FormsAuthentication.Authenticate(username, password);
}
I knew how to authenticate using a provider, but the key was the ELSE clause, and authenticating using the web.config credentials.
How can I access UserId in ASP.NET Membership without using Membership.GetUser(username) in ASP.NET Web Application Project?
Can UserId be included in Profile namespace next to UserName (System.Web.Profile.ProfileBase)?
Try this:
MembershipUser CurrentUser = Membership.GetUser(User.Identity.Name);
Response.Write("CurrentUser ID :: " + CurrentUser.ProviderUserKey);
Is your reason for this to save a database call everytime you need the UserId? If so, when I'm using the ASP.NET MembershipProvider, I usually either do a custom provider that allows me to cache that call, or a utility method that I can cache.
If you're thinking of putting it in the Profile, I don't see much reason for doing so, especially as it also will still require a database call and unless you are using a custom profile provider there, it has the added processing of parsing out the UserId.
If you're wondering why they did not implement a GetUserId method, it's simply because you're not always guaranteed that that user id will be a GUID as in the included provider.
EDIT:
See ScottGu's article on providers which provides a link to downloading the actual source code for i.e. SqlMembershipProvider.
But the simplest thing to do really is a GetUserId() method in your user object, or utility class, where you get the UserId from cache/session if there, otherwise hit the database, cache it by username (or store in session), and return it.
For something more to consider (but be very careful because of cookie size restrictions): Forms Auth: Membership, Roles and Profile with no Providers and no Session
I decided to write authentication of users users on my own (very simple but it works) and I should done this long time ago.
My original question was about UserId and it is not available from:
System.Web.HttpContext.Current.User.Identity.Name
Try the following:
Membership.GetUser().ProviderUserKey
public string GetUserID()
{
MembershipUser _User;
string _UserId = "";
_User = Membership.GetUser();
Guid UserId = (Guid)_User.ProviderUserKey;
return _UserId = UserId.ToString();
}
You have two options here:
1) Use username as the primary key for your user data table
i.e:
select * from [dbo.User] where Username = 'andrew.myhre'
2) Add UserID to the profile.
There are pros and cons to each method. Personally I prefer the first, because it means I don't necessarily need to set up the out-of-the-box profile provider, and I prefer to enforce unique usernames in my systems anyway.
Andrew: I'd be careful of doing a query like what you've shown as by default, there's no index that matches with that so you run the risk of a full table scan. Moreover, if you're using your users database for more than one application, you haven't included the application id.
The closest index is aspnet_Users_Index which requires the ApplicationId and LoweredUserName.
EDIT:
Oops - reread Andrew's post and he's not doing a select * on the aspnet_Users table, but rather, a custom profile/user table using the username as the primary key.
I had this problem, the solution is in the web.config configuration, try configuring web.config with these:
<roleManager
enabled="true"
cacheRolesInCookie="true"
defaultProvider="QuickStartRoleManagerSqlProvider"
cookieName=".ASPXROLES"
cookiePath="/"
cookieTimeout="30"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
createPersistentCookie="false"
cookieProtection="All">
<providers>
<add name="QuickStartRoleManagerSqlProvider"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ASPNETDB"
applicationName="SecurityQuickStart"/>
</providers>
</roleManager>
{
MembershipUser m = Membership.GetUser();
Response.Write("ID: " + m.ProviderUserKey.ToString());
}
Will give you the UserID (uniqueidentifier) for the current user from the aspnet_Membership table - providing the current has successfully logged in. If you try to <%= %> or assign that value before a successful authentication you will get the error "Object reference not set to an instance of an object".
http://www.tek-tips.com/viewthread.cfm?qid=1169200&page=1
Have you tried using System.Web.HttpContext.Current.User.Identity.Name? (Make sure to verify that User and Identity are non-null first.)
internally it's executing below script in sql server
select * from vw_aspnet_MembershipUsers where USERNAME like '%username%'