Asp.Net Mvc "Remember Me" not working on server - asp.net-mvc

I am developing web application with asp.net mvc.
It's seems to work in local, but in a shared hosting, It last for about 10 minutes then logout.
Here is the code:
AccountController.cs
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
var context = Request.GetOwinContext();
var authenticationManager = context.Authentication;
authenticationManager.SignIn(new AuthenticationProperties { ExpiresUtc = DateTime.UtcNow.AddDays(90), IsPersistent = true }, identity);
return RedirectToAction("Index", "Dashboard");
Startup.cs
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = "social",
CookieSecure = CookieSecureOption.Never
});
}

Solving my problem by adding machine key, hope helps someone

Related

Force claim on user

I integrated with and old Active Directive through LDAP, where some users are to be looked up.
If I find the user, it should have access - no additional requirements.
I have a specific page, which I have placed a restriction on, so that only user from MyGroup can see. When I go to the site, I get redirected to my Login-page and get a nice ReturnUrl, but I get a 401 back for the page.
EPiServer refuses to let me in, although I can see I actual get my user.
How can I tell EPiServer, that a given user is allowed access?
I created my own LoginController, which calls a method like this:
public AuthenticationResult SignInAsLdapUser(string username, string password)
{
var principalContext = new PrincipalContext(/*...*/);
isAuthenticated = principalContext.ValidateCredentials(username, password);
if (!isAuthenticated)
return;
var userPrincipal = UserPrincipal.FindByIdentity(principalContext, username);
//Attempt to force additional claims on user
var identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
identity.AddClaim(new Claim(ClaimTypes.Role, "MyGroup")); //Group I am trying to add
HttpContext.Current.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.Current.GetOwinContext().Authentication.SignIn(new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.Now.AddMinutes(30),
AllowRefresh = true
}, identity);
return new AuthenticationResult();
}
in my web.config I specified the group MyGroup:
<virtualRoles addClaims="true">
<providers>
...
<add name="CmsEditors" type="EPiServer.Security.MappedRole, EPiServer.Framework" roles="MyGroup, ..." mode="Any"/>
...
</providers>
</virtualRoles>
In my startup.cs I specified the built-in Identity and cookies:
public void Configuration(IAppBuilder app)
{
app.AddCmsAspNetIdentity<ApplicationUser>(); //OWIN from EPiServer
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
AuthenticationMode = AuthenticationMode.Active,
CookieSecure = CookieSecureOption.Always,
LoginPath = new PathString("/Login"),
CookieName = "MyCookie",
ExpireTimeSpan = TimeSpan.FromDays(7),
ReturnUrlParameter = "ReturnUrl",
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator
.OnValidateIdentity<ApplicationUserManager<ApplicationUser>, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user)),
OnApplyRedirect = context => context.Response.Redirect(context.RedirectUri),
OnResponseSignIn = context => context.Response.Redirect(GetReturnUrl()),
}
});
app.UseStageMarker(PipelineStage.Authenticate);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}

ASP.NET MVC 5 Owin Identity got lost before allowed ExpiresUtc

public void ConfigureAuth(IAppBuilder app)
{
app.UseKentorOwinCookieSaver(PipelineStage.Authenticate);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login"),
LogoutPath = new PathString("/Logout"),
CookieSecure = CookieSecureOption.SameAsRequest ,
SlidingExpiration = true,
CookieName = ".app",
CookieHttpOnly = true,
CookiePath = "/",
CookieDomain = Domain
});
My sign in method:
private void IdentitySignin(AppUserState appUserState, bool isPersistent = false)
{
var Browser = Request.Browser + Request.Browser.Version;
var claims = new List<Claim>
{
// create required claims
new Claim(ClaimTypes.NameIdentifier, appUserState.UserId),
new Claim(ClaimTypes.Name, appUserState.Name),
new Claim(ClaimTypes.Role, appUserState.RoleName),
new Claim(ClaimTypes.UserData, Browser.GetHashCode().ToString()),
// User State Info
new Claim("userState", appUserState.ToString())
};
var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = isPersistent,
//Dictionary = { { "RememberMe", isPersistent ? "true" : "false" } },
ExpiresUtc = isPersistent ? DateTime.UtcNow.AddHours(3) : DateTime.UtcNow.AddMinutes(20)
}, identity);
}
I'm expecting that cookie should be alive for 3 hours, but it expires after less than 15 minutes.
It works as expected on local, but this happens only when i deploy to IIS.
Should I set asp.net session timeout to be same as expiration timeout?
Should I include any other IIS configuration?
After long research, I found that I have to add the following line to my web.config file
<system.web>
<sessionState mode="StateServer" timeout="1200" cookieless="false" />
</system.web>

How to get Owin identity in Signalr hub

I have an application written in ASP.NET MVC using SignalR with Owin external authentication (steam).
Problem is that I can't obtain any identity information inside SignalR hub. Identity.Name returns empty string, Identity.Claims is empty.
Startup.cs
public class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Home/Index"),
AuthenticationMode = AuthenticationMode.Active
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
app.UseSteamAuthentication("API KEY");
}
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.MapSignalR();
}
}
In SteamCallBack
authenticateResult?.Identity.Claims
is not empty, it returns correct Identity.Name provided by Steam.
public async Task<ActionResult> SteamCallback()
{
....
var authenticateResult =
await HttpContext.GetOwinContext().Authentication.AuthenticateAsync("ExternalCookie");
var firstOrDefault = authenticateResult?.Identity.Claims.FirstOrDefault(claim => claim.Issuer == "Steam" && claim.Type.Contains("nameidentifier"));
...
}
Inside Hub all of the following are null/empty
var z = Context.User.Identity.Name;
var b = Context.User.Identity.AuthenticationType;
var x = ((ClaimsIdentity)Context.User.Identity).Claims.ToList();
I solve my problem. I forgot to sign in user using IAuthenticationManager.SignIn method.
Example use of that method:
var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddDays(7)
}, identity);

authenticate both mvc controller and api controller from one login entry

I use Web API2 and MVC5 in the same project with Asp.net Identity 2 for authentication and authorization, for Web APIs I use AngularJs as front end framework,
Now I need to make one login entry for both controllers, MVC controllers and Apicontrollers
this code for my configuration function
public void Configure(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.CreatePerOwinContext(TemplateEntities.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
ExpireTimeSpan = TimeSpan.FromMinutes(5),
LoginPath = new PathString("/Home/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ApplicationCookie))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
//{
// ClientId = "",
// ClientSecret = ""
//});
}
}
and this my provider code
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var signInManager = context.OwinContext.Get<ApplicationSignInManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
//userManager.lo
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
var result = await signInManager.PasswordSignInAsync(context.UserName, context.Password, true, shouldLockout: false);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
Uri expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
{
context.Validated();
}
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
I used this line to authorize MVC Controllers
var result = await signInManager.PasswordSignInAsync(context.UserName, context.Password, true, shouldLockout: false);
and this to set token cookie for APIs
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
in my GrantResourceOwnerCredentials function in previous provider code
Now the problem is APIs run perfectly with authenticated user
but when decorating MVC Controller action with [authorize] attribute it doesn't run in spite of this line var result = await signInManager.PasswordSignInAsync(context.UserName, context.Password, true, shouldLockout: false); runs successfully

Authenticate MVC Application with UseCookieAuthentication and an exisiting Web API OAuth Application

I have created my own web api OAuth authentication server with my customized Microsoft.Owin implementation:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/Auth/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthBearerTokens(OAuthOptions);
Now I want to use that OAuth authentication in an external mvc application but I've been really confused.
In fact my main concern is authorizing controllers and actions based on my existing OAuth server.
After 2 days research finally I implemented that based on a custom OAuthBearerAuthenticationProvider which is worked based on a cookie created during sign in process. The functionality works correctly But I think (actually I know) something is wrong.
this is my Custom OAuthBearerAuthenticationProvider :
public class ApplicationOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var tokenCookie = context.OwinContext.Request.Cookies["BearerToken"];
if (!string.IsNullOrEmpty(tokenCookie))
{
context.Token = tokenCookie;
}
return Task.FromResult<object>(null);
}
}
and this is my MVC auth startup configure method:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Auth/SignIn")
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new ApplicationOAuthBearerAuthenticationProvider(),
});
}
If someone has related experience please advise me.
UPDATE: I think finally I found a solution.
In my solution during sign in process I create a ticket and protect that inside OAuthBearerOptions which is defined inside Startup.Auth class.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SignIn(LoginPageModel pageModel, string returnUrl)
{
if (!ModelState.IsValid)
{
return RedirectToAction("SignIn", new { returnUrl = returnUrl });
}
try
{
var result = await AuthService.Instance.AuthenticateAsync(pageModel.LoginModel);
CreateIdentity(result);
return RedirectToLocal(returnUrl);
}
catch (Exception ex)
{
return RedirectToAction("SignIn", new { returnUrl = returnUrl });
}
}
private void CreateIdentity(TokenResponseModel result)
{
IDictionary< String, String> data = new Dictionary< String, String>
{
{ "userName", result.Username }
};
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, result.Username));
claims.Add(new Claim(ClaimTypes.Email, result.Username));
if (!String.IsNullOrEmpty(result.ExternalIdentity))
{
claims.Add(new Claim(CustomClaimTypes.ExternalIdentity, result.ExternalIdentity));
}
if (result.Roles != null && result.Roles.Length != 0)
{
foreach (var role in result.Roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
}
ClaimsIdentity oAuthIdentity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationProperties properties = new AuthenticationProperties(data);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
AuthenticationManager.SignIn(cookiesIdentity);
}
And the Auth Configure is changed to this:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Auth/SignIn"),
});
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}

Resources