I have a Web Server:
Windows Server 2008 R2 X64
IIS version : 7.5.7600.16385
(By this link We checked) installed .net on our machine is: 4.7 (460805)
Our website has been developed on .net 4.7 and MVC 5 and we use ASP.NET Forms Authentication to authenticate our clients.
On the loading of login page, we write a simple test cookie:
HttpCookie cookie = new HttpCookie("test", "123");
cookie.Expires = DateTime.UtcNow.AddYears(1);
Response.Cookies.Add(cookie);
when user click on the login button we read that cookie and count all cookies:
if (Request.Cookies["test"] == null)
{
if (Request.Cookies.Count > 0)
{
for(int i=0;i< Request.Cookies.Count;i++)
Loger.PointLoger.LogIt("Cookies:" +
Request.Cookies[i].Name
+" Value: "+ Request.Cookies[i].Value);
}
HttpBrowserCapabilitiesBase bc = Request.Browser;
...//Some codes to log
}
By this way we can be sure, writing cookies are enable and we can write our authentication cookie. If we can not read that test cookie we redirect user to another page and ....
Some our users reported, they can not login to our website and our server logs shows that we can not write cookie on their devices , the important thing is writing cookies are enable on their devices.
After doing some testes we found that writing cookies are randomly or something like that and one time its OK and another time its not.
By this codes we collected some information of out users:
HttpBrowserCapabilitiesBase bc = Request.Browser;
...
"IsMobileDevice:" + bc.IsMobileDevice
"-Browser:" + bc.Browser
...
For example :
Cookies.Count: 2
Cookies:_ga Value: GA1.2.163980100.1507000247
Cookies:_gid Value: GA1.2.1373100693.1518900032
IsMobileDevice:True
-Browser:Chrome
-Beta:False
-Platform:Unknown
-Type:Chrome47
-Version:47.0
-MobileDeviceModel:Unknown
-MobileDeviceManufacturer:Unknown
-GatewayMajorVersion:0
-MinorVersion:0
-MinorVersionString:0
-MajorVersion:47
-GatewayVersion:None
-Id:chrome
-HasBackButton:True
-Cookies:True
-ClrVersion: 0.0
-InputType:keyboard
Whey these cookies ( _gid and _ga) have been written but our test cookie not?
I read some posts like :
Asp.Net Forms Authentication when using iPhone UIWebView
ASP MVC Cookies not persisting
C# Login code not work on safari
Strange problem with cookies in Safari and Asp.net
Now the question is that: IS THAT A BUG ON .NET 7 ? IF YES WHAT IS THE SOLUTION?
I past here some codes of our project and because of security I replaced some codes with "....." :
On Web.config:
<authentication mode="Forms">
<forms domain=".mysite.com" name="abc" cookieless="UseCookies"
enableCrossAppRedirects="true" loginUrl="/Accounts/Login"
timeout="2880" requireSSL="false" path="/" />
</authentication>
<machineKey compatibilityMode="Framework45" validationKey="C121487......"
decryptionKey="7E43716E4C97....." validation="SHA1" decryption="AES" />
<sessionState mode="InProc" customProvider="DefaultSessionProvider" cookieless="UseCookies" cookieName="debnf">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf38...." connectionStringName="DefaultConnection" />
</providers>
</sessionState>
In App_Browsers :
<browsers>
<browser refID="Default">
<capabilities>
<capability name="cookies" value="true" />
</capabilities>
</browser>
</browsers>
UPDATE:
This is my main codes :
I write this test cookie here
public ActionResult Login()
{
HttpCookie cookie = new HttpCookie("test", "123");
cookie.Expires = DateTime.UtcNow.AddHours(1);
Response.Cookies.Add(cookie);
return View();
}
and when user click login I check that cookie here:
[HttpPost]
public ActionResult Login(LoginModel loginModel)
{
if (Request.Cookies["test"] == null)
{
.....
}
}
Related
I have developed a Windows Forms Application in C# and It's perfectly working. Recently, my client raised a requirement that is, he wants to load this website inside an iframe of another website.
So, I created a simple HTML application with a iframe to test this scenario.
While testing, I have identified some properties were not set in the process of ticket building of Forms Authentication. Does anyone know what is the issue here?
This is the way I set cookie,
var cookie = FormsAuthentication.GetAuthCookie(userId, chkRememberMe.Checked);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration,
ticket.IsPersistent, "insured", ticket.CookiePath);
var encTicket = FormsAuthentication.Encrypt(newTicket);
cookie.Value = encTicket;
Response.Cookies.Add(cookie);
Here is the properties of the Page.User.Identity object,
AuthenticationType = ""
IsAuthenticated = false
Name = ""
Ticket object is not available
Web.config
<system.web>
<sessionState cookieSameSite="None" timeout="20"/>
<compilation debug="true" targetFramework="4.5.2"/>
<httpRuntime targetFramework="4.5.2"/>
<authentication mode="Forms">
<forms name=".ASPXAUTH" loginUrl="Login.aspx">
</forms>
</authentication>
.
.
</system.web>
I have an ASP.Net Application. The requirement is to implement Form Authentication using ADFS.
If the user is accessing the WebSite from within the Domain(the same Domain as the Active Directoris), then the Form Authentication should be performed.
i.e. Using the User's Windows logged in email Id, we should check if the user exists in the Active Directory or not. If the user exists, then the Website is made accessible to the user.
If the user is not found on the basis of his/her email id, then the user is asked his/her UserName and Password, and to select one of the Two Active Directories on which the user should be searched.
(PN: There are two Active Directories. One Default for using with-in the Domain.)
If the User is accessing the Website from outside the Domain, then the user is always asked his/her UserName and Password, and to select one of the two Active Directories to which the User Belongs.
So, there is one URL to access the Website from with in the Domain, and one to access from Outside the Domain.
And I need help to accomplish this task.
The project is in Dot.Net, using Framework 3.5 on ASP.Net and C#.
Help with code solution highly appreciated.
I have done this. The basic idea is that your main form of authentication is Forms. However you make your default login page use Windows authentication. If the Windows authentication succeeds, then you create the Forms ticket and proceed. If not, then you display the login page.
The only caveat is that since Windows authentication always sends a 401 response to the browser (challenging it for Windows credentials), then non-Domain users will always get a credentials pop-up that they will have to click Cancel on.
I used MVC in my project. My Windows login page is /Login/Windows and my manual login page is /Login.
Here are the relevant areas of my web.config:
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Login/Windows" defaultUrl="~/" name=".MVCFORMSAUTH" protection="All" timeout="2880" slidingExpiration="true" />
</authentication>
<system.web>
<location path="Login">
<system.web>
<authorization>
<allow users="?" />
<allow users="*" />
</authorization>
</system.web>
</location>
<location path="Login/Windows">
<system.webServer>
<security>
<authentication>
<windowsAuthentication enabled="true" />
<anonymousAuthentication enabled="false" />
</authentication>
</security>
<httpErrors errorMode="Detailed" />
</system.webServer>
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
Here is my LoginController:
[RoutePrefix("Login")]
public class LoginController : Controller {
[Route("")]
public ActionResult Login() {
//Clear previous credentials
if (Request.IsAuthenticated) {
FormsAuthentication.SignOut();
Session.RemoveAll();
Session.Clear();
Session.Abandon();
}
return View();
}
[Route("")]
[HttpPost]
public ActionResult TryLogin(string username, string password) {
//Verify username and password however you need to
FormsAuthentication.RedirectFromLoginPage(username, true);
return null;
}
[Route("Windows")]
public ActionResult Windows() {
var principal = Thread.CurrentPrincipal;
if (principal == null || !principal.Identity.IsAuthenticated) {
//Windows authentication failed
return Redirect(Url.Action("Login", "Login") + "?" + Request.QueryString);
}
//User is validated, so let's set the authentication cookie
FormsAuthentication.RedirectFromLoginPage(principal.Identity.Name, true);
return null;
}
}
Your Login View will just be a normal username / password form that does a POST to /Login.
At this point, you have a /Login page that people can manually go to to login. You also have a /Login/Windows page that is the default login page that people are automatically redirected to. But if Windows login fails, it'll display a generic 401 error page.
The key to making this seamless is using your Login view as your custom 401 error page. I did that by highjacking the response content in Application_EndRequest using the ViewRenderer class written by Rick Strahl.
Global.asax.cs:
protected void Application_EndRequest(object sender, EventArgs e) {
if (Response.StatusCode != 401 || !Request.Url.ToString().Contains("Login/Windows")) return;
//If Windows authentication failed, inject the forms login page as the response content
Response.ClearContent();
var r = new ViewRenderer();
Response.Write(r.RenderViewToString("~/Views/Login/Login.cshtml"));
}
Another caveat I've found is that this doesn't work in IIS Express (although it's been a version or two since I last tried). I have it setup in IIS and point the debugger at that.
There is an OOTB solution that may work for you.
Use a ADFS WAP as well and set up split-brain DNS.
Internal users (inside the domain) get the DNS of the ADFS box. The default is Windows auth. (IWA)
External users (outside the domain) get the DNS of the ADFS WAP box. The default is FBA.
I know Forms Authentication is old, but when I run the web application locally using IIS Express, everything works well. But when I publish it to our development/test server, it just reloads the page. The dev server is running IIS 6.
One more thing to note, locally it runs as localhost:50264/Login. On the dev server, the url is more like http://dev1.server.com/op/webapp/Account/Login.
I notice that both of the cookies have the path "/". I did try to set change that by having this in my local web.config:
<add key="CookiePath" value="/" />
And then when I publish to our dev server it changest to:
<add key="CookiePath" value="http://dev1.server.com/op/webapp/" xdt:Transform="Replace" xdt:Locator="Match(key)" />
That didn't seem to work.
In another thread that I found in Stack Overflow, someone suggested to add this to the :
<system.webServer>
<modules>
<add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />
</modules>
</system.webServer>
That didn't work either. Any help would be greatly appreciated!
UPDATE: 9/29/2016
I removed the CookiePath app setting and, instead made an adjustment to the authentication node. In my Web.config I now have:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" requireSSL="false" slidingExpiration="true" path="/" />
</authentication>
And in my Web.Debug.config I have:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" requireSSL="false" slidingExpiration="true" path="/op" xdt:Transform="Replace" />
</authentication>
Finally, when I create the cookie:
var authTicket = new FormsAuthenticationTicket(
1,
user.Email,
DateTime.Now,
DateTime.Now.AddDays(14),
true,
userData,
FormsAuthentication.FormsCookiePath);
When I deploy to the dev server, I check the web.config there and it did transform the forms node correctly.
When I go to login, I enter my credentials and it still refreshes the Login page. With the Chrome extension "EditThisCookie" I still see that the path of the cookie is "/". It doesn't recognize the change AT ALL. Even when I manually set the path of authTicket path to "/op" the cookie STILL has the path as "/". I have no idea what's going on. Ugh...
I use forms authentication also, here's my settings. You didn't show all your forms Authentication code, but hopefully this will point you in the right direction.
Web.Config
<authentication mode="Forms">
<forms loginUrl="members/login.aspx" name=".ASPXFORMSAUTH" requireSSL="false" slidingExpiration="true" timeout="120" />
</authentication>
Then I set the cookie in the code behind when the user logs in.
Dim authCookie As HttpCookie = FormsAuthentication.GetAuthCookie(iMembersID, False)
Dim ticket As FormsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value)
Dim newTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, "Member")
authCookie.Value = FormsAuthentication.Encrypt(newTicket)
Response.Cookies.Add(authCookie)
Then I test to see if they are authenticated on all pages that require the user to be logged in.
If Request.IsAuthenticated Then
Dim ident As FormsIdentity = CType(User.Identity, FormsIdentity)
If ident IsNot Nothing Then
Dim ticket As FormsAuthenticationTicket = ident.Ticket
Dim userDataString As String = ticket.UserData
Select Case ticket.UserData
Case "Member"
m_MemberLoggedIn = ident.Name
Case Else
Response.Redirect("~/members/login/", True)
End Select
Else
Response.Redirect("~/members/login/", True)
End If
Update 9/29:
Check to make sure the IIS Authentication mode to set to Anonymous
I went the easy way out and asked our IT Dept to create a subdomain so the path of the cookie will always be "/". Not an answer, but it's what I did.
I have problems with Forms Authentication on our Azure WebRole. It does not store the authentication cookie for the login. Once the user initiates a new session, he has to login again.
First I tried:
FormsAuthentication.SetAuthCookie(userIdent, rememberMe);
Now doing it manually:
var ticket = new FormsAuthenticationTicket(1, userIdent, DateTime.Now, DateTime.Now.AddMonths(6),rememberMe,string.Empty, FormsAuthentication.FormsCookiePath);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,encryptedTicket)
{
Path = FormsAuthentication.FormsCookiePath,
HttpOnly = true
};
if (rememberMe)
{
cookie.Expires = ticket.Expiration;
}
Response.Cookies.Add(cookie);
Here a snippet from the web.config:
<machineKey decryption="Auto" decryptionKey="<My Decryption Key>" validation="SHA1" validationKey="<MyValidationKey>" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" slidingExpiration="true" timeout="2880" cookieless="UseCookies" />
</authentication>
But the problem remains. Sometimes it does remember it ?. Because it's running in an Azure WebRole, we added the MachineKey to web.config.
The problem might not be related to Azure Web Role, because we noticed the same behavior, running locally. Eg. localhost:7778
BACKGROUND
I have two websites under the same domain. One website encapsulates Login/Account Management functions only and the other website is the real website.
LoginWeb - only Login Page/css/images/javascript folder allow anonymous access
AdminWebsite - completely locked down via forms auth. i.e not even javascript/images/css folders have <authorization><allow users=*>
WHAT I AM TRYING TO ACHIEVE
This is the workflow I am trying to achieve and have accomplished 99% of it :
If the user hits any page on AdminWebsite he is sent back to LoginWeb by FormsAuthentication
User supplies credentials in the loginpage and LoginWeb website issues a forms auth ticket. User is still not logged into AdminWebSite yet. (This way user can go to changepassword page etc and do account management functions)
User goes to two more steps in LoginWeb and now can be issued the FormsAuth ticket for AdminWebsite and redirected to it.
99% IS ALREADY WORKING
This is the code in LoginWeb which tries to issue the FormsAuth ticket for AdminWeb, but it is not working. i.e AdminWeb is still redirecting me back to Login. I am sure there is something very trivial I am missing but I can't figure out what exactly it is?????????
public void SetAuthenticationTicket(string username)
{
MachineKeySection sec=(MachineKeySection)WebConfigurationManager.OpenWebConfiguration("").SectionGroups["system.web"].Sections["machineKey"];
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
username,
DateTime.Now,
DateTime.Now.AddMinutes(30),
false, //true or false
sec.DecryptionKey, //Custom data like your webkey can go here
FormsAuthentication.FormsCookiePath);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie("ADMINWEB", encryptedTicket)
{
Path = FormsAuthentication.FormsCookiePath,
Domain = "xxx.com"
};
Response.AppendCookie(cookie);
}
These are my web.config sections for Forms Auth:
LoginWeb
<machineKey validationKey="XXXXXX" decryptionKey="XXX" validation="SHA1"/>
<authentication mode="Forms">
<forms name="LoginWeb"
domain="xxx.com"
loginUrl="~/account/Logon"
timeout="1440"
cookieless="UseCookies"
slidingExpiration="false"
protection="All"
path="/"/>
</authentication>
AdminWebSite
<machineKey validationKey="XXXXXX" decryptionKey="XXX" validation="SHA1"/>
<authentication mode="Forms">
<forms name="ADMINWEB"
domain="xxx.com"
loginUrl="http://loginweb/account/Logon"
timeout="1440"
cookieless="UseCookies"
slidingExpiration="false"
protection="All"
path="/"/>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
This site, Forms Authentication Across Applications, implies that the Name on the forms attribute should be the same.