Form Authentication issue - asp.net

Trying to use form authentication to only allow access to a page once they have logged in via the login page. When I login and attempt the redirect it just redirects me back to the login page.
Web Login Control
protected void WebGenLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
//Verify user against active directory
if (new AD().validate(WebGenLogin.UserName, WebGenLogin.Password))
{
Session["UserAuthentication"] = WebGenLogin.UserName;
Session.Timeout = 30;
FormsAuthentication.RedirectFromLoginPage(WebGenLogin.UserName, WebGenLogin.RememberMeSet);
Response.Redirect("~/WebGen/Gen/Create.aspx");
}
else
{
Session["UserAuthentication"] = "";
Response.Redirect("http://thekickback.com/rickroll/rickroll.php");
}
}
Create.aspx Web.config
<authentication mode="Forms">
<forms defaultUrl="~/WebGen/Gen/Create.aspx" loginUrl="../Login.aspx" slidingExpiration="true" timeout="30" />
</authentication>

Can you try this:
if (new AD().validate(WebGenLogin.UserName, WebGenLogin.Password))
{
Session["UserAuthentication"] = WebGenLogin.UserName;
Session.Timeout = 30;
FormsAuthentication.SetAuthCookie(WebGenLogin.UserName, false);
FormsAuthentication.RedirectFromLoginPage(WebGenLogin.UserName, WebGenLogin.RememberMeSet);
***SNIP***

I don't know what type of object AD() calls into, but you may not be using the default ASP.NET membership functionality. As I recall, the ValidateUser method on the membership class has the side-effect of actually logging the user in if it returns true.
After authenticating the user, you may need to set HttpContext.User to a new IPrincipal representing the user, and then call FormsAuthentication.SetAuthCookie() before redirecting them.

Ok I figured it out. It had nothing to do with my code. I did however remove storing the username in the session.
What I have to do was change the root site on IIS to an application.
Authentication mode line was placed in the root with Login.aspx
Create.aspx was in another folder. I removed the authentication mode from it's Web.config and just put in the deny section and all is working correctly.

The code actually worked. Found it to be an issue with IIS. Needed to turn the entire folder structure into an application rather than other parts of it.

Related

Set Admin Home to Forbidden without Correct Login Credentials

I am making a website and i want Admin Home/User Home Page to Be Forbidden without Verifying with Correct Login Credentials. But How i Can.
protected void btn_Login_Click(object sender, EventArgs e)
{
if (CheckFields())
{
user.Employee_ID = txtEID.Text;
user.Employee_Password = txtEPassword.Text;
user.Role = ddlRole.SelectedItem.ToString();
if (uc.Login(user)==true && user.Role=="Admin")
{
Session["userID"] = user.Employee_ID;
Response.Redirect("~/Admin/Admin.aspx");
}
else if (uc.Login(user) == true && user.Role == "Team Admin")
{
Session["userID"] = user.Employee_ID;
Response.Redirect("TeamAdmin.aspx");
}
else if (uc.Login(user) == true && user.Role == "Team Admin")
{
Session["userID"] = user.Employee_ID;
Response.Redirect("TeamMember.aspx");
}
}
}
upto here it is working fine. but when i set the path directly to admin page (http://mysite.com/Admin/Admin.aspx) of the site it is showing all the contents of the admin page. i need admin page to b forbidden without verifying correct login credentials
Create a web.config file in the Admin directory with this:
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
If you're using some form of asp.net authentication it will deny any user that is not authenticated.
You need to implement authorization (http://msdn.microsoft.com/en-us/library/wce3kxhd.aspx).
If your admin page is in a separate folder that only administrators should have access to, then you can put a web.config file in that folder with an authorization section as described in the link above. You could set this authorization section to restrict access to only users who are members of the Admin role. In order for this to work properly, you must be using ASP.Net security and authorization.
Alternatively, in the Page_Load() method of the Admin.aspx page, you could put code to check that the user is a member of the Admins role. If they are not, redirect them to another page.
I prefer configuring page level authorization in the .config files because it keeps it in one place and allow it to be easily updated in the future.

Prevent FormsAuthenticationModule of intercepting ASP.NET Web API responses

In ASP.NET the FormsAuthenticationModule intercepts any HTTP 401, and returns an HTTP 302 redirection to the login page. This is a pain for AJAX, since you ask for json and get the login page in html, but the status code is HTTP 200.
What is the way of avoid this interception in ASP.NET Web API ?
In ASP.NET MVC4 it is very easy to prevent this interception by ending explicitly the connection:
public class MyMvcAuthFilter:AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && !filterContext.IsChildAction)
{
filterContext.Result = new HttpStatusCodeResult(401);
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.HttpContext.Response.SuppressContent = true;
filterContext.HttpContext.Response.End();
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
But in ASP.NET Web API I cannot end the connection explicitly, so even when I use this code the FormsAuthenticationModule intercepts the response and sends a redirection to the login page:
public class MyWebApiAuth: AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if(actionContext.Request.Headers.Any(h=>h.Key.Equals("X-Requested-With",StringComparison.OrdinalIgnoreCase)))
{
var xhr = actionContext.Request.Headers.Single(h => h.Key.Equals("X-Requested-With", StringComparison.OrdinalIgnoreCase)).Value.First();
if (xhr.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
{
// this does not work either
//throw new HttpResponseException(HttpStatusCode.Unauthorized);
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
return;
}
}
base.HandleUnauthorizedRequest(actionContext);
}
}
What is the way of avoiding this behaviour in ASP.NET Web API? I have been taking a look, and I could not find a way of do it.
Regards.
PS: I cannot believe that this is 2012 and this issue is still on.
In case someone's interested in dealing with the same issue in ASP.NET MVC app using the Authorize attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class Authorize2Attribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new HttpStatusCodeResult((int) HttpStatusCode.Forbidden);
}
else
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
}
base.HandleUnauthorizedRequest(filterContext);
}
}
}
This way browser properly distinguishes between Forbidden and Unauthorized requests..
The release notes for MVC 4 RC imply this has been resolved since the Beta - which are you using?
http://www.asp.net/whitepapers/mvc4-release-notes
Unauthorized requests handled by ASP.NET Web API return 401 Unauthroized: Unauthorized requests handled by ASP.NET Web API now return a standard 401 Unauthorized response instead of redirecting the user agent to a login form so that the response can be handled by an Ajax client.
Looking into the source code for MVC there appears to be an functionality added via SuppressFormsAuthRedirectModule.cs
http://aspnetwebstack.codeplex.com/SourceControl/network/forks/BradWilson/AspNetWebStack/changeset/changes/ae1164a2e339#src%2fSystem.Web.Http.WebHost%2fHttpControllerHandler.cs.
internal static bool GetEnabled(NameValueCollection appSettings)
{
// anything but "false" will return true, which is the default behavior
So it looks this this is enabled by default and RC should fix your issue without any heroics... as a side point it looks like you can disable this new module using AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815:
<appSettings>
<Add Key = "webapi:EnableSuppressRedirect" value = "false" />
</appSettings>
Edit (example and clarification)
I have now created an example for this approach on GitHub. The new redirection suppression requires that you use the two correct "Authorise" attribute's; MVC Web [System.Web.Mvc.Authorize] and Web API [System.Web.Http.Authorize] in the controllers AND/OR in the global filters Link.
This example does however draw out a limitation of the approach. It appears that the "authorisation" nodes in the web.config will always take priority over MVC routes e.g. config like this will override your rules and still redirect to login:
<system.web>
<authentication mode="Forms">
</authentication>
<authorization>
<deny users="?"/> //will deny anonymous users to all routes including WebApi
</authorization>
</system.web>
Sadly opening this up for some url routes using the Location element doesn't appear to work and the WebApi calls will continue to be intercepted and redirected to login.
Solutions
For MVC applications I am simply suggest removing the config from Web.Config and sticking with Global filters and Attributes in the code.
If you must use the authorisation nodes in Web.Config for MVC or have a Hybrid ASP.NET and WebApi application then #PilotBob - in the comments below - has found that sub folders and multiple Web.Config's can be used to have your cake and eat it.
I was able to get around the deny anonymous setting in web.config by setting the following property:
Request.RequestContext.HttpContext.SkipAuthorization = true;
I do this after some checks against the Request object in the Application_BeginRequest method in Global.asax.cs, like the RawURL property and other header information to make sure the request is accessing an area that I want to allow anonymous access to. I still perform authentication/authorization once the API action is called.

Getting Forms Authentication from an ASP.NET logon page used by Silverlight 4 application

This is supposed to just work. I've read all the articles I could find via google on the topic, tried to copy as much as I could from other articles on both StackOverflow and CodeProject and others, but regardless of what I try - it doesn't work.
I have a silverlight application that runs fine using Windows Authentication.
To get it running under Forms Authentication I've:
Edited the web.config file to enable Forms Authentication (and delete the Windows Authentication configuration):
<authentication mode="Forms">
<forms name=".ASPXAUTH" loginUrl="logon.aspx" defaultUrl="index.aspx" protection="All" path="/" timeout="30" />
</authentication>
Created a standard logon.aspx and logon.aspx.cs code behind page to take a user input name and password, and create a authentication cookie when the logon was successful, and then redirected the user to the root page of the web site, which is a silverlight application:
private void cmdLogin_ServerClick( object sender, System.EventArgs e )
{
if ( ValidateUser( txtUserName.Value, txtUserPass.Value ) )
{
FormsAuthentication.SetAuthCookie(txtUserName.Value, true);
var cookie = FormsAuthentication.GetAuthCookie(txtUserName.Value, true);
cookie.Domain = "mymachine.mydomain.com";
this.Response.AppendCookie(cookie);
string strRedirect;
strRedirect = Request["ReturnUrl"];
if ( strRedirect == null )
strRedirect = "index.aspx";
Response.Redirect( strRedirect, true );
}
}
So the redirect after successfully logging in launches my silverlight application.
However the user is not authenticated when executing the Silverlight startup code:
public App()
{
InitializeComponent();
var webContext = new WebContext();
webContext.Authentication = new FormsAuthentication();
ApplicationLifetimeObjects.Add( webContext );
}
private void ApplicationStartup( object sender, StartupEventArgs e )
{
Resources.Add( "WebContext", WebContext.Current );
// This will automatically authenticate a user when using windows authentication
// or when the user chose "Keep me signed in" on a previous login attempt
WebContext.Current.Authentication.LoadUser(ApplicationUserLoaded, null);
// Show some UI to the user while LoadUser is in progress
InitializeRootVisual();
}
The error occurs in the ApplicationUserLoaded method, which always has its HasError property set to true on entry to the method.
private void ApplicationUserLoaded( LoadUserOperation operation )
{
if((operation != null) && operation.HasError)
{
operation.MarkErrorAsHandled();
HandlerShowWebServiceCallBackError(operation.Error, "Error loading user context.");
return;
}
...
}
The error reported is as follows - from what it appears to me is that the user isn't considered authenticated on entry to the silverlight app, so it is directing the code to try to return the logon page, which is returning data unexpected by the silverlight app:
An exception occurred while attempting to contact the web service.
Please try again, and if the error persists, contact your administrator.
Error details:
Error loading user context.
Exception details:
Load operation failed for query 'GetUser'. The remote server returned an error: NotFound.
Any ideas?
Based on everything I read, this is supposed to be pretty simple and just work - so I'm obviously making a very basic error.
I'm wondering if after I authenticate the user on my logon.aspx web page, I need to somehow pass an authenticated WebContext instance over from the logon page to my silverlight application instead of creating a new instance in the silverlight app startup code - but have no idea how to do that.
Appreciate any or all suggestions.
I suspect the Response.Redirect("...", true);
According to this article you should pass false to keep the session.

FormsAuthentication.RedirectFromLoginPage to a custom page

Hi i'm using the FormsAuthentication.RedirectFromLoginPage for the user login and for redirect to default.aspx page.
I want that if a user called admin do the login is redirected to the page admin.aspx
Is it possible?
Try this, I think it's the closest you will get with a simple solution:
FormsAuthentication.SetAuthCookie(username, true);
Response.Redirect("mypage.aspx");
Authenticating Users
Assuming you have gone through my previous article mentioned above, you have a login page. Now when user clicks Login button Authenticate method fires, lets see code for that method.
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
string userName = Login1.UserName;
string password = Login1.Password;
bool rememberUserName = Login1.RememberMeSet;
// for this demo purpose, I am storing user details into xml file
string dataPath = Server.MapPath("~/App_Data/UserInformation.xml");
DataSet dSet = new DataSet();
dSet.ReadXml(dataPath);
DataRow[] rows = dSet.Tables[0].Select(" UserName = '" + userName + "' AND Password = '" + password + "'");
// record validated
if (rows.Length > 0)
{
// get the role now
string roles = rows[0]["Roles"].ToString();
// Create forms authentication ticket
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
userName, // Username to be associated with this ticket
DateTime.Now, // Date/time ticket was issued
DateTime.Now.AddMinutes(50), // Date and time the cookie will expire
rememberUserName, // if user has chcked rememebr me then create persistent cookie
roles, // store the user data, in this case roles of the user
FormsAuthentication.FormsCookiePath); // Cookie path specified in the web.config file in <Forms> tag if any.
// To give more security it is suggested to hash it
string hashCookies = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashCookies); // Hashed ticket
// Add the cookie to the response, user browser
Response.Cookies.Add(cookie); // Get the requested page from the url
string returnUrl = Request.QueryString["ReturnUrl"];
// check if it exists, if not then redirect to default page
if (returnUrl == null) returnUrl = "~/Default.aspx";
Response.Redirect(returnUrl);
}
else // wrong username and password
{
// do nothing, Login control will automatically show the failure message
// if you are not using Login control, show the failure message explicitely
}
}
you can check it by placing hard core role name or by fetching user roll from database. i have modified this for my entity framework.
TestEntities entities = new TestEntities();
var user = (from s in entities.UserTables
where s.UserName == loginControl.UserName
&& s.Password == loginControl.Password
select s).SingleOrDefault();
and placed the user role as:
user.Role
Along this you have do some changes in the Global.asax file
Till now we have set the Forms Authentication ticket with required details even the user roles into the cookie, now how to retrive that information on every request and find that a request is coming from which role type? To do that we need to use Application_AuthenticateRequest event of the Global.asx file. See the code below.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
// look if any security information exists for this request
if (HttpContext.Current.User != null)
{
// see if this user is authenticated, any authenticated cookie (ticket) exists for this user
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// see if the authentication is done using FormsAuthentication
if (HttpContext.Current.User.Identity is FormsIdentity)
{
// Get the roles stored for this request from the ticket
// get the identity of the user
FormsIdentity identity = (FormsIdentity)HttpContext.Current.User.Identity;
// get the forms authetication ticket of the user
FormsAuthenticationTicket ticket = identity.Ticket;
// get the roles stored as UserData into the ticket
string[] roles = ticket.UserData.Split(',');
// create generic principal and assign it to the current request
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(identity, roles);
}
}
}
}
In this even, after checking if user exists, he/she is authenticated and the identy type of th user is FormsIdentity, I am getting the current Identity of the user and getting the ticket I have set at the time of Authentiacting. Once I have the authenticated ticket, I just got the UserData from the ticket and split it to get roles (remember, we had stored the roles as comma separated values). Now, we have current users roles so we can pass the roles of the current user into the GenericPrincipal object along with the current identity and assign this to the curent user object. This will enable us to use the IsInRole method to check if a particular user belongs to a particular role or not.
How to Check if user has a particular role?
To check if a user belong to a particulr role, use below code. This code will return true if the current record is coming from the user who is authenticated and has role as admin.
HttpContext.Current.User.IsInRole( "admin" )
How to check if user is authenticated?
To check if the user is authenticated or not, use below code.
HttpContext.Current.User.Identity.IsAuthenticated
To get UserName of the Authenticated User
HttpContext.Current.User.Identity.Name
Remember on thing .. this code require some webconfig settings in the forms tag as:
Add following Authentication setting into your web.config file under .
<authentication mode="Forms">
<forms defaultUrl="default.aspx" loginUrl="~/login.aspx" slidingExpiration="true" timeout="20" ></forms>
</authentication>
For every user if you want to secure a particular folder, you can place setting for them either in parent web.config file (root folder) or web.config file of that folder.
Specify Role settings for the folder in root web.config file (in this case for Admin)
<location path="Admin">
<system.web>
<authorization>
<allow roles="admin"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Write this code outside but under tag in the root's web.config file. Here, I am specifying that if the path contains the name of folder Admin then only user with "admin" roles are allowed and all other users are denied.
Specify Role settings for the folder in folder specific web.config file (in this case for User)
<system.web>
<authorization>
<allow roles="User"/>
<deny users="*"/>
</authorization>
</system.web>
Write this code into web.config file user folder. You can specify the setting for the user in root's web.config file too, the way I have done for the Admin above. This is just another way of specifying the settings. This settings should be placed under tag.
Specify setting for Authenticated user
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
Write this code into web.config file of the Secure folder. This is specifying that all anonymous users are denied for this folder and only Authenticated users are allowed irrespective of their roles.
hope this will give you little idea to solve your problem. it is working fine for me.
hope you will also solve your problem.
If you are using the ASP.NET MembershipProvider login control, you can write your logic in the LoggedIn event
<asp:Login id="Login1" runat="server" OnLoggedIn="OnLoggedIn"></asp:Login>
protecetd void OnLoggedIn(object sender, EventArgs e)
{
if(Roles.IsUserInRole(User.Identity.Name, "Administrators"))
{
//Redirect to admin page
Response.Redirect("~/Admin.aspx");
}
}
Don't forget to put some protection on the admin.aspx page aswell, incase someone types in the url directly
The default behavior is to redirect to the originally requested resource, so if a user tried to access 'admin.aspx' and isn't authenticated, the user is sent to the login page. After successfully authenticating, the user is sent to the originally requested url (admin.aspx).
user -> "admin.aspx" -> noauth -> login -> "admin.aspx"
So instead of manually trying to send users somewhere, is using this default behavior not going to work for you? The default behavior is actually "robust" (it can be "admin2.aspx", "admin3.aspx" and so on... you can have any number of "protected resources" and the built in process handles all of it....)

asp.net: check whether session is valid

how to check whether users is authenticated and session is valid on pages after say 30 mins.
Assuming you are either hooking into the standard ASP.NET membership providers or using Basic/Digest authentication in IIS then you can easily tell if a user is authenticated using:
if (Request.IsAuthenticated)
{
// User is authenticated, allow them to do things
}
If their authentication token has expired (defaults to 20 minutes with Forms Auth, Windows auth should re-authenticate correctly with each request), then the next time you check that, IsAuthenticated will return false.
You could store a token in the users session that maps back to their user account (either a hash of their user name, or their user id or similar), and then check the two on the request - if they don't match, then the session has become invalid:
// Get the current user, and store their ID in session
MembershipUser user = Membership.GetUser();
Session["UserId"] = user.ProviderUserKey;
To check this:
if (null != Session["UserId"]) {
MembershipUser user = Membership.GetUser();
if (Session["UserId"] == user.ProviderUserKey) {
// User and session are valid
}
}
But to be honest, it depends on what you are trying to do.
If you want to restrict access to certain areas of your website if the user isn't logged in, then there are mechanisms in the configuration that allow for that:
In your web.config you can add lines like the following:
<location path="SecureDirectory">
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</location>
This will deny all anonymous users access to the directory /SecureDirectory/ and all content below it, and direct them instead to your configured login page - for more information on the Authorization element, see "How to: Configure Directories Using Location Settings".
You have to make the session expire after certain time.
So, there is a section in your web.config or you have to add the section in <system.web />
Put this section inside:
<sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424"
stateNetworkTimeout="10" cookieless="false" timeout="30" />
If you notice we are using InProc mode and timeout to be 30
Now its all up to you.
Add a key in Session object when you can find in any WebForm page.
public void btnLogin(object sender, EventArgs e) {
if (validUser) {
Session["authenticated"] = true;
}
}
and check Session["authenticated"] when required.
Session object will be expired in 30 minutes of session instantiation.
Hope this help. Please feel free to leave me a comment if you face trouble.
In the start of a session, you can store some key value in session state via the Global.asax:
void Session_Start(object sender, EventArgs e)
{
Session["userId"] = userId; // obtained from a data source or some other unique value, etc.
}
Whenever a user makes a page request or postback, on page load of any or all your pages, check if session value is null:
protected void Page_Load(object sender, EventArgs e)
{
if(Session["userId"] == null)
{
Response.Redirect("logout.aspx");
}
// do other stuff
}
If it is, then the session has expired and you can redirect then to logout page or whatever. The timeout interval is defined in your web.config file.

Resources