ASP.Net: Login control, LoginUser_LoggedIn, and Role population - asp.net

I have a forms based application. The application is standard ASP.Net wizard generated with login controls. The root's web.config appears to be in order for forms based authentication. I did have to change the <roleManager> element to use type="System.Web.Security.SqlRoleProvider" (rather than a Windows token) per How To: Use Role Manager in ASP.NET.
I have setup three roles - Administrators, Engineers, Customers. There are three users - admin (administrator), eddie (engineer), and cathy (customer). I have verified the users and their roles using ASP.Net Configuration Tool.
Each role has its own directory on disk, and each role has its own collection of ASPX files and 'landing page'. Each directory has a web.config to limit access to the role in question. For example:
<location path="~/Engineers">
<system.web>
<authorization>
<allow roles="Engineers" />
<deny users="*"/>
</authorization>
</system.web>
</location>
Upon successful login, I hook LoginUser_LoggedIn to write a destination URL. The problem I am having is the user's roles are not populated upon login, so I'm not getting a good redirect. In the code below, rolesArray has a zero size.
Any ideas? Should I be approaching this from a different angle?
Private Sub LoginUser_LoggedIn(sender As Object, e As System.EventArgs) Handles LoginUser.LoggedIn
Try
Dim rolesArray() As String
rolesArray = Roles.GetRolesForUser()
Debug.Assert(rolesArray.Length > 0)
If (Roles.IsUserInRole("Administrators") = True) Then
LoginUser.DestinationPageUrl = "~/Administrators/Dashboard.aspx"
ElseIf (Roles.IsUserInRole("Engineers") = True) Then
LoginUser.DestinationPageUrl = "~/Engineers/Workspace.aspx"
ElseIf (Roles.IsUserInRole("Customers") = True) Then
LoginUser.DestinationPageUrl = "~/Customers/Dashboard.aspx"
Else
Debug.Assert(False)
End If
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
End Sub

The same request upon logging in, the cookie is not available for use (for instance, if you check this.User.Identity.IsAuthenticated, it returns false too). It's because the cookie is established during that request, and will be available upon subsequent requests.
I'd recommend redirecting to a common page, then doing this check and redirect again, or query the roles directly from the database using the user Id of the login control.

Related

ASP.NET Forms Authentication Across Applications Issue

This has been the bane of my existence for the better part of a week.
I have four existing webforms applications that utilize forms authentication. The URL for each is mydomain/app1/, mydomain/app2/, etc. I have been tasked with creating a new application that will function as a single sign-on application with the URL mydomain/ssoapp. Once a user logs in, it basically compiles everything from the pre-existing apps that the user has access to, so our users don't have to go out and log into each of them separately. But the old applications need to function as they currently do.
The important part of my web.config is as follows:
<authentication mode="Forms" >
<forms loginUrl="frmLogin.aspx?Type=login" name="sqlAuthCookie" protection="All" path="/" domain="mydomain"
timeout="60" cookieless="UseCookies" enableCrossAppRedirects="true" />
</authentication>
<machineKey validation="SHA1" decryption="AES" decryptionKey="mykey" validationKey="myvalkey"/>
Simply adding this to the web.config for all of the applications worked like a charm....for three of them.
In the SSO application I'm creating a formsauthenticationticket, cookie, and adding that to the response with the following code. Each of the four pre-existing applications uses this same code as well:
Dim lTicket As New FormsAuthenticationTicket( _
1, _
pstrUserId.ToString, _
System.DateTime.Now, _
System.DateTime.Now.AddMinutes(60), _
True, _
pstrUserId.ToString, _
FormsAuthentication.FormsCookiePath)
' Encrypt the ticket.
Dim lencTicket As String = FormsAuthentication.Encrypt(lTicket)
' Create the cookie and add to response
Dim cookie As HttpCookie = New HttpCookie(FormsAuthentication.FormsCookieName, lencTicket)
cookie.Domain = ".mydomain.gov"
pobjResponse.SetCookie(cookie)
pobjResponse.Cookies.Add(cookie)
'Cleanup
lencTicket = Nothing
lTicket = Nothing
In chrome debugger for the SSO application, I log in and the cookie is created with the correct information.
I can click on my menu list, which uses a response.redirect to go out to the other applications. For the 3 working applications, I bypass the login screen, go directly to the form I need, and the cookie is unchanged
For the problem child application, I can still see the cookie however I am redirected back to the login screen.
If I login from this point, a new cookie is created, with the same name as the preexisting one, however the domain has the "www" prefix on it
Other useful information (maybe):
I've ensured that all machinekey, decryption key, validation method, etc match across applications
My domain is in the format of sub1.mid1.gov . I've tried every combination of the format for this in the cookie assignment and web.config. Both with and without the preceding dot.
I've removed httpRuntime from the web.config as some others had mentioned this causes issues.
There are no errors in the IIS logs
All applications are running under the same apppool currently
Currently I'm contemplating taking some vacation time so I don't feel bad about crying in the corner on my employers dime. I'm sure it's something ridiculously simple, but I appreciate any help in the matter. Thanks!

ASP.net Custom membership on top of quality center authorization

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).

ASP.Net authentication: Can I have multiple responses when user fails to authenticate/authorize to access a page

I am using ASP.net form authentication for my web application. I have folder "admin" for administration work, and also I can lock one user if he/she misbehaves.
currently if an normal user tries to access the admin page, it will be redirected to the logon page, although he/she is already logged on.
The question is: how can I configure the web app, so that when the user fails to access a page, I can show different pages such as "you need admin privilege to access this page"/"your account is locked out"/(normal logon page)?
ValidateUser() can only return bool. :(
Thanks a lot
You'll need to implement roles and add people to them. Once you assign people to the proper roles, you would check to see if the person is in the proper role to access a page. If not, redirect them or show the proper error message. You would be able to do this with code behind like it seems like you are already trying:
if(!Roles.IsUserInRole("Administrator")) Response.Redirect("~/");
Or you can use the web.config
<configuration>
<location path="memberPages">
<system.web>
<authorization>
<allow roles="Administrator" />
<deny users="*" />
</authorization>
</system.web>
</location>
<configuration>
See the links below for more info:
https://web.archive.org/web/20210417083524/https://www.4guysfromrolla.com/articles/121405-1.aspx
http://msdn.microsoft.com/en-us/library/ff647401.aspx
I solved this kind of problem giving different urls to diffenrent roles.
To admin you give www.yoursite.com/admin
to user you give www.yoursite.com/private
asp.net will automatically redirect both to the login.aspx page but you can get from the url parameter which kind of user it is.
//I detect where the request originated from
string str = Request.QueryString["ReturnUrl"] == null ? "" : Request.QueryString["ReturnUrl"].ToString();
//if this is Admin can access to Admin Area only
if (str.Contains("Admin") == true || str.Contains("admin") == true || str.Contains("ADMIN") == true)
{ .......

login control forms authentication

I setup a login control to use on my web application and having issues validating the users. I created the membership tables in my own database in sql server 2008 using a suggestion on another site. Then I opted to just use forms authentication and created two users in the WSAT and thought that this would work fine. But it returns false for all users including the two I created. Why this is so I am not sure and if I were to use the sql database tables how would I do this?
<authentication mode="Forms">
</authentication>
<authorization>
<allow users="boy"/>
<allow users="girl"/>
</authorization>
<roleManager enabled="true" />
code behind login:
If Page.IsValid then
If username <>"" and password <>"" then
If FormsAuthentication.Authenticate(username,passwprd) = False then
Return false
else
response.redirect("~/default.aspx")
End If
End If
End If
You need to configure your web.config to use the MembershipProvider.
Take a look here for more info. Are you trying to use the SqlMembershipProvider?
To authenticate using MembershipProvider use the Login user control or you can create your own and call the following methods:
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
FormsAuthentication.RedirectFromLoginPage(userName, createPersistentCookie);
}

In my codebehind class, how do I retrieve the authorized roles?

I have the following in my web.config:
<location path="RestrictedPage.aspx">
<system.web>
<authorization>
<allow roles="Group1Admin, Group3Admin, Group7Admin"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Within RestrictedPage.aspx.cs, how do I retrieve the allowed roles collection that contains Group1Admin, Group3Admin, and Group7Admin?
Here's why I ask:
The web.config is handling the authorization to the page. That works fine. But I'm going to have a couple of these pages (say RestrictedPage.aspx, RestrictedPage2.aspx, RestrictedPage3.aspx). Each of these pages is going to have my custom webcontrol on it. And each of these pages will have different allowed roles. My webcontrol has a dropdown list. The choices within the dropdown depend on the intersection of the user's roles and the page's allowed roles.
As mentioned below, searching the web.config with XPath would probably work. I was just hoping for something more framework-y. Kind of like SiteMap. When I put roles in my web.sitemap, I can grab them using SiteMap.CurrentNode.Roles (my website is using Windows authentication, so I can't use web.sitemap for security trimming and I'd rather maintain roles in only one file).
// set the configuration path to your config file
string configPath = "??";
Configuration config = WebConfigurationManager.OpenWebConfiguration(configPath);
// Get the object related to the <identity> section.
AuthorizationSection section = (AuthorizationSection)config.GetSection("system.web/authorization");
from the section object get the AuthorizationRuleCollection object where you can then extract the Roles.
Note: You'll probably need to modify the path to the section a bit since you start with "location path="RestrictedPage.aspx"", I didn't try that scenario.
if {User.IsInRole("Group1Admin"){//do stuff}
Is that what your asking?
I'm not sure for certain, but I would have thought that this is checked before your page is even processed, so if a user is not in a role they would never reach your page. Which ultimately would make the visibility of this redundant in the page.
I'm convinced that there is a better way to read this information, but here is a way that you can read the allow values from a web.config file.
XmlDocument webConfigReader = new XmlDocument();
webConfigReader.Load(Server.MapPath("web.config"));
XmlNodeList root = webConfigReader.SelectNodes("//location[#path="RestrictedPage.aspx"]//allow//#roles");
foreach (XmlNode node in root)
{
Response.Write(node.Value);
}
Of course, the ASP.NET role provider will handle this for you, so reading these values is only really relevant if you plan to do something with them in the code-behind beside authorizing users, which you may be doing.
Hope this helps--you may have to split your result using the , character.
What typically happens is this...
When the user hits your page, if authentication/authorization is active, the Application_Authentication event is raised. Unless you are using Windows Authentication against something like Active Directory, the IPrincipal and Identity objects will not be available to you, so you can't access the User.IsInRole() method. However, you CAN do this by adding the following code into your Global.asax file:
Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim formsAuthTicket As FormsAuthenticationTicket
Dim httpCook As HttpCookie
Dim objGenericIdentity As GenericIdentity
Dim objMyAppPrincipal As CustomPrincipal
Dim strRoles As String()
Log.Info("Starting Application AuthenticateRequest Method...")
httpCook = Context.Request.Cookies.Get("authCookieEAF")
formsAuthTicket = FormsAuthentication.Decrypt(httpCook.Value)
objGenericIdentity = New GenericIdentity(formsAuthTicket.Name)
strRoles = formsAuthTicket.UserData.Split("|"c)
objMyAppPrincipal = New CustomPrincipal(objGenericIdentity, strRoles)
HttpContext.Current.User = objMyAppPrincipal
Log.Info("Application AuthenticateRequest Method Complete.")
End Sub
This will put a cookie into the browser session with the proper user and role credentials you can access in the web app.
Ideally, your user is only going to be in one role in an application, so I believe that is why you have the role check method available to you. It would be easy enough to write a helper method for you that would iterate through the list of roles in the application and test to see what role they are in.

Resources