OpenId ASP MVC Authentication with long expiry - asp.net-mvc

Stackoverflow uses OpenId as many other websites. However, I rarely need to provide my OpenId to Stackoverflow while with other OpenId enabled websites, I have to do it once a day or week.
This suggests to me that the expiry of the session is with the website and not the OpenId provider.
Looking at the DotNetOpenId code in ASP MVC, I can see that after a successful authentication by the OpenId provider FormsAuthentication.SetAuthCookie is called with the identifier and a boolean parameter to determine if the cookie should be persisted.
How can I force this cookie to expire, say in 2020 instead of whatever the default value is.

From MSDN - Explained: Forms Authentication in ASP.NET 2.0:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
"userName",
DateTime.Now,
new DateTime(2020, 01, 01), // value of time out property
false, // Value of IsPersistent property
String.Empty,
FormsAuthentication.FormsCookiePath);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
encryptedTicket);
authCookie.Secure = true;
Response.Cookies.Add(authCookie);

You can use FormsAuthentication.RenewTicketIfOld() to update the ticket. This method would check if the current ticket has expired and if not, to extend its expiration. You can call this method on every request to your site, which will "slide" th expiration further in future as the user keeps using your site.

Related

MVC App using Azure AD with ADAL 3 - Authentication Cookie expires after 1 hour

I work on an MVC Web Application using Azure AD with OAuth 2 and Open ID Connect for Authorization of users.
Per documentation tokens are refreshed automatically when a token expires after 60 minutes (which is fine).
Now the problem is, to acquire a token I need to know the currently authenticated user which is stored in a cookie. The code to acquire a Token is like this:
public async Task<AuthenticationToken> GetTokenForApplication(string resourceID)
{
string signedInUserID = ClaimsPrincipal.Current.SignedinUserId();
var tenantID = ClaimsPrincipal.Current.TenantId();
string userObjectID = ClaimsPrincipal.Current.SignedinUserObjectId();
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(Config.ClientId, Config.AppKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
AuthenticationContext authenticationContext = new AuthenticationContext(string.Format("{0}{1}", Config.AadInstance, tenantID), new ADALTokenCache(signedInUserID));
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(resourceID, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
var token = new AuthenticationToken(authenticationResult.AccessToken) { ExpiresOn = authenticationResult.ExpiresOn };
return token;
}
Now I am in the dilemma, that the ClaimsPrincipal.Current.SignedinUserId() method call throws a null reference exception. When I inspect the ClaimsPrincipal.Current object, no data about the logged in user is available. But this is the Information needed to renew / request a token.
What is the best practice in an MVC Web App? Is there a way to extend the validity of the cookie or is there any way to reauthenticate the current user without redirecting to the root page of the web application?
After doing more research I have found these two pages which describe some options to deal with my problem pretty good:
Controlling a Web App’s session duration
and ASP.NET-Identity-Cookie-Authentication-Timeouts
are these good approaches?
After doing more research I have found these two pages which describe some options to deal with my problem pretty good:
Controlling a Web App’s session duration
and ASP.NET-Identity-Cookie-Authentication-Timeouts
are these good approaches?

Is it possible to update FormsAuthentication cookie value?

I have to set FormsAuthentication cookie value (FormsAuthentication.SetAuthCookie(UserDesignation, false)) at the time of login.
Now I need to provide designation change option. So when user change their designation, I need to update the FormsAuthentication cookie value from old designation to new designation.
Is it possible to do that?
If yes means, how can I do this?
You can modify the cookie data as shown below, but it is preferable as per me to keep the role in a separate cookie and authenticate it using the FormsAuthentication cookie
HttpCookie cookie = FormsAuthentication.GetAuthCookie(Username, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var newticket = new FormsAuthenticationTicket(ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
true, //persistent
"user data,designation",
ticket.CookiePath);
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.Expires = newticket.Expiration.AddHours(2);
HttpContext.Current.Response.Cookies.Set(cookie);

Restrict Auth & Session Cookies to a Subdomain in ASP.NET MVC5

I have a multi-tenanted application with several clients, who are distinguished by subdomain:
client1.mydomain.com
client2.mydomain.com
etc
I'm using forms authentication and the ASP.NET Auth & Session cookies on the client are set for the subdomain, e.g. client1.mydomain.com. This means that if I browse to client2.mydomain.com then I'm not logged in and the browser doesn't post the client1 cookies. Which is as it should be.
However something that has been picked up by our security testing is that you can take the cookie values from client1 and use the values to create cookies for client2 (we've done this in firebug). ASP.NET accepts these cookies and thinks you're authorised on client2.
How can I configure ASP.NET so that this doesn't happen?
The forms element in web.config allows you to set domain but I can't use this as I've a multi-tenanted app. I'm setting the cookie with
FormsAuthentication.SetAuthCookie(userName, false);
but I don't see a why to limit this to subdomain.
You should add the domain name to the user data of the cookie. To do this you have to switch to another cookie api:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
... other parameters ..., domain );
HttpCookie cookie = new HttpCookie( FormsAuthentication.FormsCookieName );
cookie.Value = FormsAuthentication.Encrypt( ticket );
Response.SetCookie( cookie );
Then, in your global application class have an event handler that fires after the identity is established for the request. In the handler, verify that the domain name in the cookie is equal to a domain of the current request:
public void Application_PostAuthorizeRequest( object sender, EventArgs e )
{
HttpApplication app = sender as HttpApplication;
HttpContext ctx = app.Context;
if ( ctx.User.Identity.IsAuthenticated )
{
// current domain
string currentDomain = ctx.Request.Url.... // get the domain
// domain from cookie
FormsIdentity id = (FormsIdentity)ctx.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
string cookieDomain = ticket.UserData;
if ( currentDomain != cookieDomain )
throw new Exception( "break the execution of the current request" );
...
This check will validate if the cookie was issued for the current domain or rather someone tries to reuse cookies between different domains.

External Cookie for External Login in ASP.NET OWIN

We have a legacy system which is built on ASP.NET Mvc 4, now we would like to support Signal Sign On via Azure Active Directory for current users as well as new users. Since we have managed our own authentication workflow, ASP.NET Identity definitely does not fit in our case.
I have managed to build a demo which is working on OWIN OpenIdConnect middleware passive mode without using ASP.NET Identity. The below code works correctly:
app.SetDefaultSignInAsAuthenticationType("ExternalCookie");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ExternalCookie",
AuthenticationMode = AuthenticationMode.Passive,
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Passive,
ClientId = ClientId,
Authority = Authority
// More code
});
And in ExternalLoginCallback action:
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var authManager = Request.GetOwinContext().Authentication;
var result = await authManager.AuthenticateAsync("ExternalCookie");
authManager.SignOut("ExternalCookie");
//More code to convert to local identity
}
This case is really common even using other providers like Google, Facebook or Twitter. One thing I have not much clear is ExternalCookie, maybe I have missed the whole thing. My understanding is when external login is successfully, external cookie is used to store the external claim identity. And then we call:
var result = await authManager.AuthenticateAsync("ExternalCookie");
authManager.SignOut("ExternalCookie");
In order to get the external claim identity and then convert external identity to local identity. I have a little bit confusion why we have to call SignOut external cookie in this case.
Also, I'm not sure whether External Cookie is a must when using external login, or do we have other ways around without using External Cookie.
Please someone give an explanation on this point.
To answer your last question, you change the name of cookie in startup.auth file where you configure external cookie -
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
You can use a string instead of DefaultAuthenticationTypes enum and directly specify the name of the cookie like -
app.UseExternalSignInCookie("myExternalCookie");

FormsAuthentication on AppHarbor

I upload my first ASP.NET MVC application to App Harbor, that uses FormsAuthentication to simple authentication of the user.
As usual on local machine operation that required authentications performes well, at the moment I tun them on AppHarbor, they failed.
I checked that authentication cookie released on access is send with the request, as it visible from image:
and my server side authentication code looks like
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
user.UserName,
DateTime.Now,
DateTime.Now.AddDays(1),
true,
user.UserName
);
string encTicket = FormsAuthentication.Encrypt(authTicket);
this.Response.Cookies.Add(
new HttpCookie(
FormsAuthentication.FormsCookieName,
encTicket)
{ Expires = authTicket.Expiration });
I read different posts from AppHarbor blogs like ASP.NET Forms Authentication Considered Broken, it says "harmflul" and not that it's not working.
So, what I do wrong here ?

Resources