I'm having problem with our login procedure.
Some customers complain that they can't login. I can see in our logs that their login is successful and that they are redirected from the login page to the member area. But there somehow the login isn't detected and they are bounced back to the login page.
I've asked customers to check if cookies are supported (http://www.html-kit.com/tools/cookietester/) but problem remains even if this test returns true.
This is how I've implemented the login procedure (simplyfied):
protected void Login(string email, string password)
{
FormsAuthentication.SignOut();
Guid clientId = /* Validate login by checking email and password, if fails display error otherwise get client id */
FormsAuthentication.SetAuthCookie(clientId.ToString(), true);
HttpContext.Current.Response.Redirect("~/Members.aspx");
}
On the member page I check for authentication by in Page_Load function:
public static void IsAuthenticated()
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
HttpContext.Current.Response.Redirect("~/Login.aspx", true);
}
}
Maybe I'm using FormsAuthentication completely wrong?
I've asked this before but still haven't been able to figure this out, I'd appreciate any help.
From my Web.Config:
<system.web>
<compilation debug="false">
<assemblies>
...
</assemblies>
</compilation>
<authentication mode="Forms"/>
<sessionState mode="InProc" cookieless="false" timeout="180"/>
<customErrors mode="On"/>
<httpHandlers>
...
</httpHandlers>
<httpModules>
...
</httpModules> </system.web>
public static void IsAuthenticated()
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
HttpContext.Current.Response.Redirect("~/Login.aspx", true);
}
}
is not necessary when you use forms authentication.
When you specify the forms authentication in the web.config (in which you also specify the login page)
<authentication mode="Forms">
<forms loginUrl="/Authorization/Login" timeout="60" />
</authentication>
and you deny all non-athenticated users access
<authorization>
<deny users="?" />
</authorization>
you don't have to check the authentication of a user yourself, the framework takes care of that.
I would place the FormsAuthentication.SignOut(); code behind a 'logout' link
Seperate the call of SignOut() and SetAuthCookie() in different methods. You may call FormsAuthentication.SignOut(); when the Login page loads first time - simply just do away from calling SignOut() on Login page. And Call
FormsAuthentication.SetAuthCookie(clientId.ToString(), true); after authentication is successful.
Normally you would use FormsAuthentication.Authenticate together with some membership provider, but this should work, and it actually does in my machine.
Are you removing the FormsAuthentication from your registered HTTP modules? Normally, this is in the machine wide web.config:
<configuration>
<system.web>
<httpModules>
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
</httpModules>
</system.web>
</configuration>
If you put a <clear /> inside that same section of your own web.config, you're effectively removing that module.
My tested Web.config is pretty clean, it only has <authentication mode="Forms"/> configured.
Related
I am encountering an infinite redirect loop between login.microsoftonline.com and my application. My project is implementing authentication and authorization in an Asp.net 4.8 web forms project. I am able to add authentication using the default Owin startup file and then require authentication in the web config file. The below works correctly for requiring a user to sign in before being able to access pages/AuthRequired
StartupAuth.CS
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string postLogoutRedirectUri = ConfigurationManager.AppSettings["ida:PostLogoutRedirectUri"];
private static string authority = ConfigurationManager.AppSettings["ida:Authority"];
private static string clientSecret = ConfigurationManager.AppSettings["AppRegistrationSecret-Local"];
public void ConfigureAuth(IAppBuilder app)
{
//for debugging
//IdentityModelEventSource.ShowPII = true;
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
ClientSecret = clientSecret,
RedirectUri = postLogoutRedirectUri,
//This allows multitenant
//https://github.com/Azure-Samples/guidance-identity-management-for-multitenant-apps/blob/master/docs/03-authentication.md
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = (context) =>
{
return Task.FromResult(0);
}
}
}
);
// This makes any middleware defined above this line run before the Authorization rule is applied in web.config
app.UseStageMarker(PipelineStage.Authenticate);
}
}
Web.Config
<configuration>
...
<system.web>
<authentication mode="None" />
</system.web>
<location path="Pages/AuthRequired">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
...
</configuration>
I need to add authorization so that only users with the admin role will be able to access Pages/AuthRequired. I have done that by updating the web config:
<configuration>
...
<system.web>
<authentication mode="None" />
</system.web>
<location path="Pages/AuthRequired">
<system.web>
<authorization>
<allow roles="Admin" />
<deny users="*" />
</authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
...
</configuration>
Adding authorization to the authenticated page works correctly if the user has that role, but if a user who doesn't have the role tries to access the page they are redirected back to login.microsoftonline.com and then back to the application in an infinite loop.
I can see that Owin UseOpenIdConnectAuthentication is returning a 302 response on unauthorized and that is causing the loop.
How can I change it so that instead of redirecting unauthorized (but authenticated) users to login.microsoftonline.com, that user should be directed to an app page that displays a 401 error?
Please check if below work around helps:
Its usually possible that if forms authentication is enabled, you will be redirected to the login page when status code is 401.
As a workaround try Adding the below to global.asax in the application end request and you can create own unauthorized page if needed and redirect to that.
if (this.Response.StatusCode == 302&& this.Response.StatusCode == 401
&& this.Response.RedirectLocation.ToLower().Contains("login.aspx"))
{
this.Response.StatusCode = 401;
//or Response.Redirect("Unauthorized.aspx");
}
You can also check this > Redirect unauthorised user to message page in ASP .Net. (microsoft.com)
Other references
Prevent redirect to login on status code 401 (Unauthorized)
(microsoft.com)
asp.net - In-place handling (no redirect) of 401 unauthorized? -
Stack Overflow
ASP.NET URL Authorization doesn't appear to interoperate well with OIDC (i.e. Azure AD).
First remove the URL Authorization from your Web.config:
<configuration>
...
<system.web>
<authentication mode="None" />
</system.web>
<location path="Pages/AuthRequired">
<system.web>
-- <authorization>
-- <allow roles="Admin" />
-- <deny users="*" />
-- </authorization>
</system.web>
</location>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
...
</configuration>
Optionally make authenticated required for all pages globally:
<system.web>
<deny users="?" />
</system.web>
You can override this behaviour with <Allow users="?" /> for specific pages i.e. logins/logouts/erorr pages/etc.
Second add authorization logic to your AuthRequired.aspx page:
public partial class AuthRequired {
protected void Page_Load(object sender, EventArgs e)
{
Authorization.AuthorizeAuthRequiredPage();
...
}
}
public static class Authorization
{
public static void AuthorizeAuthRequiredPage()
{
if (!Authorized(HttpContext.User))
{
Redirect("/Anauthorized.aspx");
}
}
private static bool Authorized(User user) => { ... }
}
I have one login page for admin, another login page for general user. I have created a custom membership provider for general user section, now I want to give form authentication in web.config file. How to do that ?
We can not set two login urls for login inside webconfig file.If we create our own custom Membership provider, we have to set it as defaultprovider for making the [Authorize] attribute workable for it. But in my case, there were two providers. Both are custom providers, and I wasn't allowed to change the default provider. One provider is used for Admin login(the default provider), another provider used for user login (custom provider). In web config form authentication was enabled
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
So, when I was using [Authorize] attribute, it was taking me to the admin login page and it is expected. But I needed an attribute which would take me to user login page. So I created a [AuthorizeUser] attribute which is now taking users to user login section.
public class AuthorizeUserAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var username = filterContext.HttpContext.User.Identity.Name;
if (username != "")
{
base.HandleUnauthorizedRequest(filterContext);
}
else
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Login", action = "Index" }));
}
}
}
This attribute is taking my users into user login page at ~/login
When i work with custom membership provider, i also configure custom role provider and then add the following lines into my web.config file. You can see if it supports your scenario.
Step 1:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
<membership defaultProvider="YourCustomMembershipProviderName">
<providers>
<clear/>
<add name="YourCustomMembershipProviderName" type="Logger.SampleApp.Security.Infrustructure.CustomeMembershipProvider" connectionStringName="YourConnectionStringName" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="Logger.SampleApp.Client.Web"/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="YourRoleProvider"
<providers>
<clear/>
<add name="YourRoleProvider" type="Logger.SampleApp.Security.Infrustructure.CustomRoleProvider" />"
</providers>
</roleManager>
Step 2:
Add [Authorize] attribute to Index method of HomeController.
Step 3:
under the <appSettings> section:
<add key= "enableSimpleMembership" value= "false"/>
<add key= "autoFormsAuthentication" value= "false"/>
Step 4:
Comment on InitializeSimpleMembership from AccountController and override login action as per requirement.
I am an active directory user and I am simply trying to print the name of the current user out in a Respnse.Write() method. From what I read from several other questions posted here I need to use
using System.Security.Principal;
string username = WindowsIdentity.GetCurrent().Name
However, when I try to write the username to the screen I get
NT AUTHORITY\NETWORK SERVICE
instead of
domain\12345678
Here is the code I am using to write to the screen:
Response.Write(WindowsIdentity.GetCurrent().Name);
and I have identity impersonate set to true in my web.config. What do I do next?
Edited to show suggested answers
my pageload
protected void Page_Load(object sender, EventArgs e)
{
string userName = User.Identity.Name;
Response.Write(userName);
//currently returning null
}
In your web.config you need authentication mode switched on to Windows and you need to disabled anonymous users
<system.web>
<authentication mode="Windows" />
<anonymousIdentification enabled="false" />
<authorization>
<deny users="?" />
</authorization>
</system.web>
The reason your approach isn't working is because User.Identity isn't physically referencing your Active Directory Membership. For all intensive purposes, is trying to grab your active user through Internet Information Systems (IIS) which it can't do in the current state. Since your utilizing Web-Forms, the easiest approach would be:
<asp:LoginView> : The following template will allow you to specify visible data for an anonymous user, logged in user, or logged out user. Which will help manage your membership system accordingly.
Membership Not Needed - Membership isn't regulated, but would like to display or access whom is logged in for certain instances.
To implement:
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP://..." />
</connectionStrings>
That will be your connectionString to your directory. Now to ensure the application authenticates correctly:
<authentication mode="Windows">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>
<membership>
<providers>
<clear />
<add name="MyADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ADConnectionString" />
</providers>
</membership>
Now you'll be able to properly run User.Identity.
Hopefully that helps.
string yourVariable = User.Identity.Name;
I have this application where I login by the PC user. I'm using this:
public static bool IsAuthenticated()
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
CurrentUser = Factory.Users.List(item => item.Username.ToLower() == cToLower()).FirstOrDefault();
}
return CurrentUser != null;
}
Note: .List(), is a method I created to list all database Users (in
this case).
Everything works fine. But when I publish my Website on my IIS, HttpContext.Current.User.Identity.Name is returning nothing, no user at all. What is wrong with it? Any suggestion?
You have to enable IIS Windows Authentication and Deny Annomyous acces. You can either configure your IIS or update your configuration file as follows,
<configuration>
<system.web>
<authentication mode="Windows" />
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
I am having difficulties implementing a custom ASP.NET RoleProvider.
First off, let me show you the relevant settings in my web.config file:
<?xml version="1.0"?>
<configuration>
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
name="FormsAuthentication"
path="Default.aspx"
timeout="20"/>
</authentication>
<membership defaultProvider="MembershipProvider">
<providers>
<clear />
<add name="MembershipProvider"
type="CompanyName.Security.MembershipProvider" />
</providers>
</membership>
<roleManager defaultProvider="RoleProvider"
enabled="true">
<providers>
<clear />
<add name="RoleProvider"
type="CompanyName.Security.RoleProvider" />
</providers>
</roleManager>
</system.web>
<location path="Employees.aspx">
<system.web>
<authorization>
<deny users="?"/>
<allow roles="Employees"/>
</authorization>
</system.web>
</location>
</configuration>
Here's the code for the login button's event handler:
if (Membership.ValidateUser(tbxUsername.Text, tbxPassword.Text))
Response.Redirect("./Employees.aspx");
else
{
tbxUsername.Text = string.Empty;
tbxPassword.Text = string.Empty;
tbxUsername.Focus();
lblLogin.Visible = true;
}
Side Note based on FormsAuthentication.RedirectFromLoginPage() suggestion:
[It has been suggested that I use FormsAuthentication.RedirectFromLoginPage() instead of Response.Redirect(). Eventually, I'd like to redirect the user to a different page based on his/her role. I don't know how FormsAuthentication.RedirectFromLoginPage() would allow me to do this as it does not accept a redirection url as a parameter. In addition, it is my understanding that I could call FormsAuthentication.SetAuthCookie() prior to Response.Redirect() in order to create the authentication cookie that FormsAuthentication.RedirectFromLoginPage() creates. Please let me know if my thought process here is wrong.]
After stepping through the source, I can see that Membership.ValidateUser() is executing the ValidateUser() function of my custom MembershipProvider class. However, when a valid user logs in, and is redirected to Employees.aspx, the user is returned to Login.aspx**?ReturnUrl=%2fEmployees.aspx**. I assume that this is because although the user authenticates, s/he is failing authorization to the Employees.aspx resource.
With that assumption, I created breakpoints on every function in my custom RoleProvider class to see where things run amuck. Not one of them breaks execution when I debug. Most of the code in my RoleProvider throws NotYetImplementetExceptions, but I would still expect to hit the breakpoints (and would then implement those required functions). Here are two dumbed-down functions I have implemented:
public override string[] GetRolesForUser(string username)
{
return new string[1] {"Employees"};
}
public override bool IsUserInRole(string username, string roleName)
{
return true;
}
I assume that since the RoleProvider code never executes, that something must be wrong with my web.config.
I've searched for an answer to this for the past two days and have tried various changes without success. Does anyone see where I'm going wrong?
Thanks in advance!
After authenticating the user using Membership.ValidateUser, you should call FormsAuthentication.RedirectFromLoginPage rather than Response.Redirect to create the forms authentication ticket.
See the MSDN documentation for Membership.ValidateUser for an example.
EDIT
Or if you want to redirect to a specific page, call FormsAuthentication.SetAuthCookie to create the forms authentication ticket before calling Response.Redirect.
It redirects authenticated users to default.aspx
Actually it redirects back to the page that was originally requested, which is not necessarily default.aspx
EDIT 2
Also there is a problem with your configuration:
The path attribute should not point to a specific page (Default.aspx in your case), but the root directory of the site. The default is "/" because most browsers are case-sensitive and so won't send the cookie if there is a case mismatch.
<forms loginUrl="Login.aspx"
name="FormsAuthentication"
path="/"
timeout="20"/>
Check if user is in role:
If (Roles.IsUserInRole("Employees"))
{
}
or try if it works without role checking:
<allow users="*"/>
maybe helps configuration change:
<location path="Employees.aspx">
<system.web>
<authorization>
<allow roles="Employees"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
I changed the path value (see below) from "Default.aspx" to "/" and now the breakpoints in the custom RoleProvider are being hit!
Does not work:
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
name="FormsAuthentication"
path="Default.aspx"
timeout="20"/>
</authentication>
Works:
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
name="FormsAuthentication"
path="/"
timeout="20"/>
</authentication>