How Authenticate by WebMethod - asp.net

I Passed userName and Pass to webmethod in .aspx page by Ajax in Json Format,
now i want authenticate users and redirect user to same page and update LoginView with LogedIn State;
How Can i do it?
here's my WebMethod
[WebMethod]
// [ [System.Web.Script.Services.ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet=false)]
public static void login(object myData)
{
JavaScriptSerializer js = new JavaScriptSerializer();
List<nameVal> myfrm = js.Deserialize<List<nameVal>>(myData.ToString());
// MembershipUser u = Membership.GetUser(myfrm.SingleOrDefault(rs=>rs.name=="userName").value);
if ( Membership.ValidateUser(myfrm[0].value,myfrm[1].value))
{
FormsAuthentication.Authenticate(myfrm[0].value, myfrm[1].value);
//FormsAuthentication.RedirectFromLoginPage(myfrm[0].value, false);
FormsAuthenticationTicket tkt;
string cookiestr;
HttpCookie ck;
tkt = new FormsAuthenticationTicket(1, myfrm[0].value, DateTime.Now,
DateTime.Now.AddMinutes(30), true, "my custom data");
cookiestr = FormsAuthentication.Encrypt(tkt);
ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
ck.Path = FormsAuthentication.FormsCookiePath;
// ******* now i must somthing like this: --> Response.Cookies.Add(ck);
// but im in static method don't have respons request objects
// i want respons in json form and proccess the json
// return "Success";
}
else
{
//return "Faild";
}
}
so tanks

You can do the following:
FormsAuthentication.SetAuthCookie(myfrm[0].value, createPersistentCookie: false);
return FormsAuthentication.GetRedirectUrl(user.Name, false);
and then in your javascript:
var onSuccess = function (result) {
if (result === null) {
// login failed
return;
}
window.location.href = result;
};
PageMethods.login(myData, onSuccess);
This unfortunately still has a "silent" ThreadAbortException that I can't seem to get rid of, but it doesn't seem to cause any problems. I think it's probably unavoidable and benign.

Related

Force logout from asp.net application when the same url is pasted in another tab

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.

LDAP Authentication with Asp.NET Identity

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;
}

Confirmation email got Invalid token

I'm adding confirmation email feature to my ASP.NET WebAPI project. The server can send email fine, however, the confirmation link always return "Invalid token".
I checked some reasons as pointed out here
http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/
but it seems that none of them is the root cause
Below is my code:
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
try
{
await userManager.AddToRoleAsync(user.Id, "Player");
//Generate email confirmation token
//var provider = new DpapiDataProtectionProvider("GSEP");
var provider = new MachineKeyProtectionProvider();
userManager.UserTokenProvider = new DataProtectorTokenProvider<GSEPUser>(provider.Create("EmailConfirmation"));
var code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
code = System.Web.HttpUtility.UrlEncode(code);
EmailHelper emailHelper = new EmailHelper();
string callBackUrl = emailHelper.GetCallBackUrl(user, code);
EmailMessage message = new EmailMessage();
message.Body = callBackUrl;
message.Destination = user.Email;
message.Subject = "GSEP Account confirmation";
emailHelper.sendMail(message);
}
catch (Exception e)
{
return Ok(GSEPWebAPI.App_Start.Constants.ErrorException(e));
}
}
And now is EmailHelper
public class EmailHelper
{
public string GetCallBackUrl(GSEPUser user, string code)
{
var newRouteValues = new RouteValueDictionary(new { userId = user.Id, code = code });
newRouteValues.Add("httproute", true);
UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext, RouteTable.Routes);
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
return callbackUrl;
}
public void sendMail(EmailMessage message)
{
#region formatter
string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
string html = "Please confirm your account by clicking this link: link<br/>";
html += HttpUtility.HtmlEncode(#"Or click on the copy the following link on the browser:" + message.Body);
#endregion
MailMessage msg = new MailMessage();
msg.From = new MailAddress("myemail#example.com");
msg.To.Add(new MailAddress(message.Destination));
msg.Subject = message.Subject;
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient("smtp-mail.outlook.com", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("myemail#example.com", "mypassword!");
smtpClient.Credentials = credentials;
smtpClient.EnableSsl = true;
smtpClient.Send(msg);
}
}
And 2 MachineKey class
public class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
public class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, _purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, _purposes);
}
}
I also added machineKey tag in Web.config as some instruction pointed out.
And finally is my confirmation email API
[AllowAnonymous]
[HttpGet]
public async Task<IHttpActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return Ok("Confirm error");
}
IdentityResult result;
try
{
result = await UserManager.ConfirmEmailAsync(userId, code);
}
catch (InvalidOperationException ioe)
{
// ConfirmEmailAsync throws when the userId is not found.
return Ok("UserID not found");
}
if (result.Succeeded)
{
return Ok("Confirmation succesfully");
}
else
{
return Ok(result.Errors);
}
}
Please show me where am I go wrong
I know this is an old thread. But I though of adding the answer as it could help others.
You are using the below code
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
and the UrlHelper.Action already does the url encoding for you in the latest MVC versions. So here in your code you are doing the encoding twice (one inside the Register and another inside GetCallBackUrl using urlHelper.Action) and that is why you are getting the invalid token error.

ASP.NET MVC Remember me

I've got a project based in ASP.NET MVC 4 that simple authentication.
I'm trying to get my site to automatically log the user in when they check the remember me checkbox. However I'm having problems getting this working. After closing down the browser and reopening it the user is never logged in.
After checking (http://forums.asp.net/t/1654606.aspx#4310292) I've added a machine key in, generated by IIS. I've set automatically generate at runtime and generate a unique key for each application have both been disabled and I've Generated Keys). Unfortunately this hasn't worked.
Looking at "Remember me" with ASP.NET MVC Authentication is not working, I've added in the line FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe) but that didn't work either so I've now commented it out.
I tried the answer given on ASP.NET MVC RememberMe but that doesn't seem to work either.
Am I missing something obvious?
//FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (model.RememberMe)
{
//int timeout = model.RememberMe ? 525600 : 2; // Timeout in minutes,525600 = 365 days
int timeout = 525600;
var ticket = new FormsAuthenticationTicket(model.UserName, model.RememberMe, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = System.DateTime.Now.AddMinutes(timeout);//My Line
Response.Cookies.Add(cookie);
}
this is how i do it
public class MyAuthentication
{
public static HttpCookie GetAuthenticationCookie(LoginModel model, bool persistLogin)
{
// userData storing data in ticktet and then cookie
JavaScriptSerializer js = new JavaScriptSerializer();
var userData = js.Serialize(model);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
"akash",
DateTime.Now,
DateTime.Now.AddHours(1),
persistLogin,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie cookie= new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Expires = authTicket.Expiration; //must do it for cookie expiration
return cookie;
}
internal static bool Login(string UserName, string Password)
{
//UserName="akash" Password="akash"
//check can be done by DB
if (UserName== "akash" && Password == "akash")
return true;
else
return false;
}
}
and then
[HttpGet]
[AllowAnonymous]
public ActionResult Login()
{
//ViewBag.Message = "Your contact page.";
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
// var ek = cookie.Value;
try
{
//some times no cookie in browser
JavaScriptSerializer js = new JavaScriptSerializer();
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
//string data = ticket.UserData;
LoginModel model = js.Deserialize<LoginModel>(ticket.UserData);
if (MyAuthentication.Login(model.UserName, model.Password) == true)
{
RedirectToAction("Index", "Home");
}
}
catch
{
}
return View();
you can check it on Global.asax or authorization filter.
make sure you have web.config has
<authentication mode="Forms">
<forms defaultUrl="/Home/Login" loginUrl="/home/Login" timeout="2880">
</forms>
</authentication>
and [Authorize] attribute before all controller.
builder.Services.AddControllersWithViews();
var constr = builder.Configuration["ConnectionStrings:Default"];
builder.Services.AddDbContext<AppDbContext>(opt =>
{
opt.UseSqlServer(constr);
});
builder.Services.AddIdentity<AppUser, IdentityRole>(opt =>
{
opt.Password.RequiredLength = 8;
opt.Password.RequireDigit= true;
opt.Password.RequireLowercase= true;
opt.Password.RequireUppercase= true;
opt.Password.RequireNonAlphanumeric= true;
opt.User.RequireUniqueEmail= true;
opt.Lockout.MaxFailedAccessAttempts= 5;
opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(10);
opt.Lockout.AllowedForNewUsers= true;
}).AddEntityFrameworkStores<AppDbContext
().AddDefaultTokenProviders();
builder.Services.AddSession(opt =>
{
opt.IdleTimeout = TimeSpan.FromSeconds(15);
});
builder.Services.ConfigureApplicationCookie(opt =>
{
opt.LoginPath = "/Auth/Login";
});
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();

User is in role "admin" but [Authorize(Roles="admin")] won't authenticate

I found a great answer on SO describing how to set up custom user roles, and I've done the same in my project. So in my Login service I have:
public ActionResult Login() {
// password authentication stuff omitted here
var roles = GetRoles(user.Type); // returns a string e.g. "admin,user"
var authTicket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddMinutes(20), // expiry
false,
roles,
"/");
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(authTicket));
Response.Cookies.Add(cookie);
return new XmlResult(xmlDoc); // don't worry so much about this - returns XML as ActionResult
}
And in Global.asax.cs, I have (copied verbatim from the other answer):
protected void Application_AuthenticateRequest(Object sender, EventArgs e) {
var authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null) {
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
var roles = authTicket.UserData.Split(new Char[] { ',' });
var userPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), roles);
Context.User = userPrincipal;
}
}
Then, in my ServicesController class, I have:
[Authorize(Roles = "admin")]
//[Authorize]
public ActionResult DoAdminStuff() {
...
}
I login as a user with the "admin" role, and that works. Then I call /services/doadminstuff - and I get access denied, even though when I put a breakpoint in Global.asax.cs, I can see that my roles do include "admin". If I comment out the first Authorize attribute (with roles) and just use a plain vanilla Authorize, then I can access the service.
I must be missing something critical here - but where to start looking?
I would recommend you use a custom authorize attribute instead of Application_AuthenticateRequest:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
string cookieName = FormsAuthentication.FormsCookieName;
if (!filterContext.HttpContext.User.Identity.IsAuthenticated ||
filterContext.HttpContext.Request.Cookies == null ||
filterContext.HttpContext.Request.Cookies[cookieName] == null
)
{
HandleUnauthorizedRequest(filterContext);
return;
}
var authCookie = filterContext.HttpContext.Request.Cookies[cookieName];
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(',');
var userIdentity = new GenericIdentity(authTicket.Name);
var userPrincipal = new GenericPrincipal(userIdentity, roles);
filterContext.HttpContext.User = userPrincipal;
base.OnAuthorization(filterContext);
}
}
and then:
[CustomAuthorize(Roles = "admin")]
public ActionResult DoAdminStuff()
{
...
}
Also a very important thing is to ensure that when you login an authentication cookie is emitted because you return an XML file. Use FireBug to inspect whether the authentication cookie is properly sent when you try to access the url /services/doadminstuff.
I would change principal assign at first:
Thread.CurrentPrincipal = userPrincipal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = userPrincipal;
}
as ASP.NET documentation stands.

Resources