I am integrating the asp.net webforms project with single sign on(SSO) using Openidconnect and Cookie Authentication using Owin libraries. Once authenticated, the cookie should be active for the day and on browser close need to reauthenticate again(which sets up the cookie again).
After certain hours of inactivity it shows user is authenticated, but the ClaimsIdentity is lost. So the app does not work. I need to able to get the name/email address from the Claims.
How can I fix this?
Startup.cs
public void ConfigureAuth(IAppBuilder app)
{
try
{
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.SetDefaultSignInAsAuthenticationType("Identity.Application");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Identity.Application",
ExpireTimeSpan = 1440,//min
CookieName = "ABC",
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = _clientId,
Authority = _authority,
RedirectUri = _redirectUri,
ResponseType = "code",
Scope = "openid",
SignInAsAuthenticationType = "Identity.Application",
RedeemCode = true,
SaveTokens = true,
ClientSecret = _clientSecret,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = (context) =>
{
return Task.FromResult(0);
},
AuthorizationCodeReceived = (context) =>
{
Console.WriteLine("ConfigureAuth: AuthorizationCodeReceived");
return Task.FromResult(0);
},
MessageReceived = (context) =>
{
Console.WriteLine("ConfigureAuth: MessageReceived");
return Task.FromResult(0);
},
RedirectToIdentityProvider = (context) =>
{
Console.WriteLine("ConfigureAuth: RedirectToIdentityProvider");
return Task.FromResult(0);
},
SecurityTokenReceived = (context) =>
{
Console.WriteLine("ConfigureAuth: SecurityTokenReceived");
return Task.FromResult(0);
},
SecurityTokenValidated = (context) =>
{
Console.WriteLine("ConfigureAuth: SecurityTokenValidated");
return Task.FromResult(0);
}
}
});
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.ToString());
}
}
Web.config
<authentication mode="Forms">
<forms loginUrl="AuthenticationHandler.ashx" name=".ASPNETAUTH" protection="None" path="/Default3.aspx" timeout="420" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
<sessionState timeout="420" />
AuthenticationHandler
public class AuthenticationHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (!context.Request.IsSecureConnection)
{
string absoluteUri = context.Request.Url.AbsoluteUri;
context.Response.Redirect(absoluteUri.Replace("http://", "https://"), true);
}
if (context.Request.IsAuthenticated)
{
string userName = String.Empty;
var claimsIdentity = context.User.Identity as ClaimsIdentity;
foreach (var claim in claimsIdentity.Claims)
{
if (claim.Type == "name")
{
userName = claim.Value;
break;
}
}
// Redirect back to original URL.
string redirectUrl = FormsAuthentication.GetRedirectUrl(userName, true);
if (!redirectUrl.Contains("default.aspx"))
{
context.Response.Redirect(redirectUrl);
}
}
else
{
ChallengeAuthentication(context);
}
if (!String.IsNullOrEmpty(context.Request.QueryString["signout"]))
{
context.Request.GetOwinContext()
.Authentication
.SignOut(HttpContext.Current.Request.GetOwinContext()
.Authentication.GetAuthenticationTypes()
.Select(o => o.AuthenticationType).ToArray());
}
}
private static void ChallengeAuthentication(HttpContext context)
{
try
{
HttpContext.Current.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = context.Request.RawUrl },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
var claimsIdentity = context.User.Identity as ClaimsIdentity;
string userName = string.Empty;
foreach (var claim in claimsIdentity.Claims)
{
string claimType = claim.Type.Replace("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/", "");
string claimValue = claim.Value;
sbMessage.Append(claimType + " = " + claimValue + "<br/>");
if (claimType == "emailaddress")
{
userName = claimValue;
}
}
context.Response.Write(sbMessage.ToString());
string userData = "";
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
userName,
DateTime.Now,
1440,
true,
userData,
FormsAuthentication.FormsCookiePath);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
// Create the cookie.
context.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
}
catch (Exception ex)
{
Console.WriteLine("exception authenticating: " + ex.ToString());
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Default3.aspx.cs
string userName = String.Empty;
var claimsIdentity = User.Identity as ClaimsIdentity;
foreach (var claim in claimsIdentity.Claims)
{
// WEC:: might need a more bulletproof check here.
string claimType = claim.Type.Replace("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/", "");
string claimValue = claim.Value;
if (claimType == "emailaddress")
{
userName = claimValue;//NO VALUE after certain hours of inactivity
}
}
Related
I created a application using ASP.NET with EF. I did the login function and when the user logged redirect to WelcomePage. The login was succeeded and redirect to the page but in the page I have the user authenticated.
I put this to see and its false
<p>#User.Identity.IsAuthenticated</p>
I'm just having trouble understanding how to authenticate them. I try to clean cache but thats not the problem.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string Con = ConUri();
services.AddDbContext<SysContext>(options =>
{
options.UseNpgsql(Con);
});
services.AddIdentity<User, IdentityRole<Guid>>()
.AddEntityFrameworkStores<SysContext>()
.AddDefaultTokenProviders();
services.AddControllersWithViews().AddRazorRuntimeCompilation();
services.AddControllersWithViews().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromDays(30);
options.Cookie.HttpOnly = true;
});
services.ConfigureApplicationCookie(options =>
{
options.AccessDeniedPath = new PathString("/Login");
options.LoginPath = new PathString("/Login");
});
}
HomeController.cs
public object Login(String Username, String Password)
{
try
{
if (ModelState.IsValid)
{
var user = _userManager.FindByEmailAsync(Username).Result;
if (user == null)
throw new Exception("Error 1");
var result = _signInManager.CheckPasswordSignInAsync(user,
Password, lockoutOnFailure: false).Result;
if (result.IsLockedOut)
throw new Exception("Error 2");
if (!result.Succeeded)
throw new Exception("Error 3");
var response = _signInManager.PasswordSignInAsync(Username, Password, true, lockoutOnFailure: false).Result;
if (result.Succeeded)
{
var location = new Uri($"{Request.Scheme}://{Request.Host}/WelcomePage");
Response.Cookies.Append("_UserId", user.Id.ToString());
HttpContext.Session.SetString("_User" + user.Id, string.Empty);
return new
{
Sucesso = true,
Url = location
};
}
else
{
throw new Exception("Error ex");
}
}
throw new Exception("Error 4");
}
catch (Exception ex)
{
return new
{
Sucesso = false,
Mensagem = ex.Message
};
}
}
}
You could check the EmailConfirmed Colum if it has a value in your database,if you did not set to send you a confirmed e-mail when you sign up,try to set as below to avoid varify the e-mail:
services.Configure<IdentityOptions>(options =>
{
.......
options.SignIn.RequireConfirmedAccount=false ;
......
})
Why you passed the username as an e-mail address?
var user = _userManager.FindByEmailAsync(Username).Result;
i am new to this authentication mechanism and still learning.What i am trying to achieve is that..when the user tries to use multiple instances of the application like say for by opening different tabs,the application should automatically logoff.
My login Code
public static bool SignIn(int officeId, string userName, string password, bool remember, System.Web.UI.Page page)
{
int userId = BusinessLayer.Office.Users.GetUserId(userName);
bool active = BusinessLayer.Office.Users.IsUserActive(userId);
if(!active)
{
return false;
}
if (page != null)
{
try
{
string remoteAddress = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
string remoteUser = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_USER"];
DateTime? serverDate = BusinessLayer.Core.DateConversion.GetCurrentServerDate();
string pass = BusinessLayer.Security.Password.GetHash(password, userName);
long logOnId = Everest.Net.DatabaseLayer.Security.User.SignIn(officeId, userName,
BusinessLayer.Security.Password.GetHash(password, userName),
page.Request.UserAgent, remoteAddress, remoteUser);
// var isActive = BusinessLayer.Office.Users.GetUserId(userName);
if (logOnId > 0)
{
if (IsBoDStarted(Conversion.TryCastDate(serverDate)))
{
var isSessionSet = SetSession(page, userName);
if (isSessionSet)
{
var ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now,
DateTime.Now.AddHours(12), remember, String.Empty, FormsAuthentication.FormsCookiePath);
string encryptedCookie = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookie);
cookie.Expires = DateTime.Now.AddHours(12);
page.Response.Cookies.Add(cookie);
System.Web.Security.FormsAuthentication.RedirectFromLoginPage(userName, true, "Everest.Net");
return true;
}
}
else
{
var ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now,
DateTime.Now.AddHours(12), remember, String.Empty, FormsAuthentication.FormsCookiePath);
string encryptedCookie = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookie);
cookie.Expires = DateTime.Now.AddHours(12);
page.Response.Cookies.Add(cookie);
page.Response.Redirect("~/Utilities/BodOperation.aspx");
return true;
}
}
}
catch (DbException)
{
//Swallow the exception
return false;
}
}
if (page != null)
{
page.Session.Clear();
}
return false;
}
Any ideas by you experts around here would be helpful.I did searched about this in SO and in here.Couldnt get the grasp of it.Any help appreciated.
My webconfig
<authentication mode="Forms">
<forms loginUrl="~/SignIn.aspx" timeout="6" slidingExpiration="true" defaultUrl="~/Index.aspx" />
</authentication>
In my above webconfig since the timeout is set to 6minutes, this doesnot works too.
Help Please.
I trying impliment Active Directory authentication for my ASP.NET MVC application. I use System.DirectoryServices and during login find user in UserManager. If user not found I'm trying find user in Active Directory and if successful register user in asp.net mvc app with UserManager.CreateAsync().
private ApplicationUserManager _userManager;
private ApplicationRoleManager _roleManager;
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel loginModel, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(loginModel.UserName, loginModel.Password);
if (user != null)
{
await SignInAsync(user, loginModel.RememberMe);
return RedirectToLocal(returnUrl);
}
string userFullName;
if (AuthenticateActiveDirectoryUser("mydomain.local", loginModel.UserName, loginModel.Password, out userFullName))
{
var newUser = new ApplicationUser { UserName = loginModel.UserName, FullName = userFullName };
var result = await UserManager.CreateAsync(newUser, loginModel.Password);
if (result.Succeeded)
{
await SignInAsync(newUser, loginModel.RememberMe);
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
else
{
ModelState.AddModelError("", "Invalid UserName or Password");
}
}
return View(loginModel);
}
private bool AuthenticateActiveDirectoryUser(
string domain,
string username,
string password,
out string fullName)
{
fullName = string.Empty;
var domainAndUsername = string.Format("{0}\\{1}", domain, username);
var ldapPath = "";
var entry = new DirectoryEntry(ldapPath, domainAndUsername, password);
try
{
// Bind to the native AdsObject to force authentication.
var obj = entry.NativeObject;
var search = new DirectorySearcher(entry) { Filter = "(SAMAccountName=" + username + ")" };
search.PropertiesToLoad.Add("cn");
var result = search.FindOne();
if (result == null)
return false;
try
{
fullName = (string)result.Properties["cn"][0];
}
catch
{
fullName = string.Empty;
}
}
catch (Exception ex)
{
return false;
}
return true;
}
But in my implementation ignored cases if user change password in Active Directory account or AD Account was deleted.
I can check it manually in my code, but maybe exists other ways in ASP.NET Identity to implement authentication by Active Directory user account?
see if this can help u
protected bool ActiveDirectoryLogin(string Username, string Password, string Domain)
{
bool Success = false;
//System.DirectoryServices.DirectoryEntry Entry =
// new System.DirectoryServices.DirectoryEntry("LDAP://***.**.**.**:389/cn=***-People,o=**,dc=**,dc=edu,dc=sa", "uid=" + Username + ",cn=***-People,o=***,dc=***,dc=edu,dc=sa", Password, AuthenticationTypes.None);
System.DirectoryServices.DirectoryEntry Entry =
new System.DirectoryServices.DirectoryEntry("LDAP://ldapmaster.***.edu.sa:389/cn=***-People,o=***,dc=***,dc=edu,dc=sa", "uid=" + Username + ",cn=***-People,o=***,dc=***,dc=edu,dc=sa", Password,AuthenticationTypes.None);
//System.DirectoryServices.DirectoryEntry Entry =
// new System.DirectoryServices.DirectoryEntry("LDAP://ldapmaster.***.edu.sa:389/cn=***-People,o=***,dc=***,dc=edu,dc=sa", Username , Password, AuthenticationTypes.None);
System.DirectoryServices.DirectorySearcher Searcher = new System.DirectoryServices.DirectorySearcher(Entry);
try
{
Object nat = Entry.NativeObject;
Success = true;
// System.DirectoryServices.SearchResult Results = Searcher.FindOne();
// Success = (Results != null);
}
catch (Exception e)
{
Success = false;
}
return Success;
}
I have hosted a Windows Web API using a basic authentication header with username and password.
I'm trying to create a login form that takes a username and password and sends back a token.
so i have the following code.
I'm using a Attributed method
public class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
private IPromiseRepository promiseRepository;
public BasicAuthenticationAttribute()
{
this.promiseRepository = new EFPromiseRepository(new PropellorContext());
//repository = promiseRepository;
}
public BasicAuthenticationAttribute(IPromiseRepository promiseRepository, INewsFeedRepository newsfeedRepository)
{
this.promiseRepository = promiseRepository;
}
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
else
{
string authToken = actionContext.Request.Headers.Authorization.Parameter;
string decodedToken = authToken;
// Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
string username = decodedToken.Substring(0, decodedToken.IndexOf(":"));
string password = decodedToken.Substring(decodedToken.IndexOf("^")+1);
string APIToken = decodedToken.Substring(decodedToken.IndexOf("="));
APIToken = APIToken.Replace("=", string.Empty);
password = password.Replace("=", string.Empty);
if (!string.IsNullOrEmpty(APIToken))
{
password = password.Replace(APIToken, string.Empty);
}
if (username != null && password != null)
{
try
{
var user = promiseRepository.GetUserByName(username);
var salt = user.PasswordSalt;
System.Security.Cryptography.SHA512Managed HashTool = new System.Security.Cryptography.SHA512Managed();
Byte[] PasswordAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(password, salt));
Byte[] EncryptedBytes = HashTool.ComputeHash(PasswordAsByte);
HashTool.Clear();
var hashedpass = Convert.ToBase64String(EncryptedBytes);
if (hashedpass == user.Password)
{
if (string.IsNullOrEmpty(user.APIToken))
{
String guid = System.Guid.NewGuid().ToString();
user.APIToken = guid;
promiseRepository.UpdateUser(user);
promiseRepository.Save();
}
if (user != null)
{
user = promiseRepository.GetUserByUserID(user.UserID);
HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(user), new string[] { });
base.OnActionExecuting(actionContext);
}
}
if (APIToken != null)
{
if (user.APIToken == APIToken)
{
var userbytoken = promiseRepository.GetUserByAPIToken(APIToken);
HttpContext.Current.User = new GenericPrincipal(new ApiIdentity(userbytoken), new string[] { });
base.OnActionExecuting(actionContext);
}
}
}
catch (Exception)
{
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
base.OnActionExecuting(actionContext);
}
throw;
}
}
}
}
}
This works with Fiddler when the correct credentials are passed
I'm attempting to produce the same authentication in my windows phone application.
Passes a username and password into the basic authentication http header.
However I'm not sure how to do this after a large amount of diggging on the internet alot of the exmaples are windows phone 7 and certain methods don't exist anymore.
This is the code i have arrived at.
private void Login1_Click(object sender, RoutedEventArgs e)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:5650/api/start");
NetworkCredential credentials = new NetworkCredential(userName.Text + ":^",password.Text + "=");
request.Credentials = credentials;
request.BeginGetResponse(new AsyncCallback(GetSomeResponse), request);
Hopefully someone can guide me into the right direction.
it should be simple in principle :(
Here is a sample using HttpClient:
public static async Task<String> Login(string username, string password)
{
HttpClient Client = new HttpClient();
Client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(StringToAscii(string.Format("{0}:{1}", username, password))));
var response = await Client.GetAsync(new Uri(new Uri("http://yourdomain.com"), "/login"));
var status= await response.Content.ReadAsAsync<String>();
return status;
}
And of course you can find the ToBase64String function on the internet. The tricky part here is the Authorization header.
I'm trying to create my own authentication mechanism which relies on FormsAuthentication. I'm basically using OAuth to allow users to authenticate in an Authorization Server, and once they are authenticated, I need to use FormsAuthentication to authenticate them across the session. So anyway, I created an HttpModule and a helper class to make this work. Unfortunately, it does not.
What happens is that on PostAuthenticateRequest I encrypt the ticket and add a cookie to the response, then redirect the user to the root of the website. Once the user is re-directed, another HTTP request is issued so the HttpModule is triggered again, and on the AuthenticateRequest event I'm checking whether this user is authenticated or not. In order to check if the user is authenticated, I'm trying to read the cookie, get the username from it and then set the Thread.CurrentPrincipal property. But, for some reason, the cookie cannot be found.
Here's my code:
public class OAuthModule : IHttpModule
{
private const String USERNAME = "username";
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AuthenticateRequest += context_AuthenticateRequest;
context.PostAuthenticateRequest += context_PostAuthenticateRequest;
}
void context_PostAuthenticateRequest(object sender, EventArgs e)
{
var application = sender as HttpApplication;
if (application != null)
{
String username = application.Context.Items[USERNAME].ToString();
String uri = RemoveQueryStringFromUri(application.Context.Request.Url.AbsoluteUri);
var cookie = IdentityHelper.GetEncryptedFormsAuthenticationCookie(username, uri);
application.Context.Response.Cookies.Add(cookie);
application.Context.Response.Redirect(uri);
}
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
if (sender != null)
{
if (!application.Context.Request.Url.AbsolutePath.Contains("."))
{
if (!IdentityHelper.IsAuthenticated)
{
HttpContextWrapper wrapper = new HttpContextWrapper(application.Context);
String clientId = WebConfigurationManager.AppSettings["ClientId"];
String clientSecret = WebConfigurationManager.AppSettings["ClientSecret"];
String authorizationServerAddress = WebConfigurationManager.AppSettings["AuthorizationServerAddress"];
var client = OAuthClientFactory.CreateWebServerClient(clientId, clientSecret, authorizationServerAddress);
if (String.IsNullOrEmpty(application.Context.Request.QueryString["code"]))
{
InitAuthentication(wrapper, client);
}
else
{
OnAuthCallback(wrapper, client);
}
}
}
}
}
private void InitAuthentication(HttpContextWrapper context, WebServerClient client)
{
var state = new AuthorizationState();
var uri = context.Request.Url.AbsoluteUri;
uri = RemoveQueryStringFromUri(uri);
state.Callback = new Uri(uri);
var address = "https://localhost";
state.Scope.Add(address);
OutgoingWebResponse outgoingWebResponse = client.PrepareRequestUserAuthorization(state);
outgoingWebResponse.Respond(context);
}
private void OnAuthCallback(HttpContextWrapper context, WebServerClient client)
{
try
{
IAuthorizationState authorizationState = client.ProcessUserAuthorization(context.Request);
AccessToken accessToken = AccessTokenSerializer.Deserialize(authorizationState.AccessToken);
String username = accessToken.User;
context.Items[USERNAME] = username;
}
catch (ProtocolException e)
{
EventLog.WriteEntry("OAuth Client", e.InnerException.Message);
}
}
private String RemoveQueryStringFromUri(String uri)
{
int index = uri.IndexOf('?');
if (index > -1)
{
uri = uri.Substring(0, index);
}
return uri;
}
}
public class IdentityHelper
{
public static Boolean IsAuthenticated
{
get
{
String username = DecryptFormsAuthenticationCookie();
if (!String.IsNullOrEmpty(username))
{
SetIdentity(username);
return Thread.CurrentPrincipal.Identity.IsAuthenticated;
}
return false;
}
}
private static String DecryptFormsAuthenticationCookie()
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
return ticket.UserData;
}
return String.Empty;
}
internal static HttpCookie GetEncryptedFormsAuthenticationCookie(String username, String domain)
{
var expires = DateTime.Now.AddMinutes(30);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, username, DateTime.Now, expires, true, username, FormsAuthentication.FormsCookiePath);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
cookie.Value = FormsAuthentication.Encrypt(ticket);
cookie.Domain = domain;
cookie.Expires = expires;
return cookie;
}
private static void SetIdentity(String username)
{
ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim> { new Claim(ClaimTypes.Name, username) });
var principal = new ClaimsPrincipal(claimsIdentity);
Thread.CurrentPrincipal = principal;
}
}
Where did I go wrong? Any ideas?
Ok so I finally got it solved. It was as simple as the following:
application.Context.Response.Redirect(uri, false);
I needed to tell the module not to kill the current response (hence the false) so it would preserve the cookie in the coming request.