So I am using LDAP to authenticate my users, and this works fine for most all of my users, but for some of them it does not. I know for a fact I have two users that it is not working for. The code pulls down all the information about the person, creates a formsAuthenticationticket, but when it gets to [authorize] it just bounces them back to the login page. The question is why?
Login controller:
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
string logon_user = model.UserName.ToString();
string logon_password = model.Password.ToString();
ConnHelper connhelper = new ConnHelper();
string encryptedTicket = null;
String adPath = "#####"; //Path to the 2003 LDAP directory server
ADAuthorize adAuth = new ADAuthorize(adPath);
FormsAuthenticationTicket authTicket = null;
try
{
if (true == adAuth.IsAuthenticated("#####", logon_user, logon_password))
{
string groups = adAuth.GetGroups();
Account acc = new Account();
acc.windows_id = logon_user;
acc.password = logon_password;
acc.gers_id = connhelper.GetGersID(acc.windows_id);
acc.region = connhelper.IsNull(connhelper.GetRegionManager(acc.gers_id));
acc.home_store_region = connhelper.IsNull(connhelper.GetHomeStoreRegion(acc.gers_id));
acc.store_group = connhelper.IsNull(connhelper.GetStoreGroup(acc.gers_id));
acc.home_store = connhelper.IsNull(connhelper.GetStore(acc.gers_id));
acc.arr = connhelper.GetStores(acc.gers_id);
//acc.home_store_phone = misc.IsNull(misc.GetHomeStorePhoneNumber("hzs"), "");
acc.home_store_phone = connhelper.IsNull(connhelper.GetHomeStorePhoneNumber(acc.gers_id), "");
acc.full_name = connhelper.IsNull(connhelper.GetFullName(acc.gers_id), "");
// Onlt use the following in the core
// acc.full_name = adAuth.getuserFname("#####", logon_user, logon_password);
misc.GetStore(acc.gers_id);
//Add information to the session
Session.Add("roles", groups);
Session.Add("Account", acc);
// Create the authentication ticket
authTicket =
new FormsAuthenticationTicket(1, // version
acc.windows_id,
DateTime.Now,
DateTime.Now.AddMinutes(500),
false, groups);
// Now encrypt the ticket.
encryptedTicket = FormsAuthentication.Encrypt(authTicket);
// Create a cookie and add the encrypted ticket to the cookie as data.
HttpCookie authCookie =
new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
// Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
if (FormsAuthentication.GetRedirectUrl(acc.windows_id, false).EndsWith("Logout.aspx"))
{
return RedirectToAction("Login", "Account");
}
//
// Validate code this does the redirect to where you want the logged in person to go to.
//
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Authentication failed, check username and password.");
return View(model);
}
}
catch (Exception ex)
{
ModelState.AddModelError("", "Error authenticating. " + ex.Message + ex.StackTrace);
return View(model);
}
// return View(model);
}
Adauth is authenticated ( this returns true even for the people who get bounced)
public bool IsAuthenticated(string domain, string username, string pwd)
{
cred(username, pwd);
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("SAMAccountName");
//search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
// Update the new path to the user in the directory
_path = result.Path;
_filterAttribute = (String)result.Properties["SAMAccountName"][0];
//_filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return true;
}
Then the home index controller
[HttpGet]
[Authorize]
public ActionResult Index()
{
//grab all events and pass to view
//
int count = D.getEventRows();
if (count != 0)
{
Event[] events = new Event[count];
events = D.getEvents(count);
ViewBag.host = globals.hosts();
ViewBag.events = events;
DateTime curr = DateTime.Now;
ViewBag.curr = curr;
return View(events);
}
return View();
}
web config:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="28800" />
</authentication>
<authorization>
<allow users="*" />
</authorization>
Related
I'm Trying to reset active directory user password by .NET core web API but always return below exception, even if I put very complex password
System.DirectoryServices.AccountManagement.PasswordException:
'The password does not meet the password policy requirements.
Check the minimum password length, password complexity
and password history requirements. (0x800708C5)'
I tried both ways (DirectoryEntry and the new one) but I get the same exception.
Here is my code, but I think
public bool ResetPassword(string oldPassword, string newPassword, string userNameI)
{
/* // set up domain context
PrincipalContext context = new PrincipalContext(ContextType.Domain, LDAP_PATH, userName, password);
if (context != null)
{
// find the user you want to delete
UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userNameI);
if (user != null)
{
user.Enabled = true;
user.ChangePassword(oldPassword,newPassword);
user.ExpirePasswordNow();
user.Save();
return true;
}
}*/
/*
var entry = new DirectoryEntry
{
Path = "LDAP://MyIP",
Username = userName,
Password = password
};
using (var searcher = new DirectorySearcher(entry))
{
searcher.Filter = "(SAMAccountName=" + userNameI + ")";
var result = searcher.FindOne();
var user = result.GetDirectoryEntry();
user.Invoke("ChangePassword", new object[] { oldPassword.Trim(), newPassword.Trim() });
user.CommitChanges();
return true;
}
*/
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "LDAPIP", userName, password))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, userNameI))
{
if (user != null)
{
user.ChangePassword(oldPassword, newPassword);
user.Save();
return true;
}
else
{
throw new Exception(string.Format("Username not found: {0}", userNameI));
}
}
return false;
}
}
The below code is working fine, the Old password is not needed in resetting password and account owner user name is needed :
public bool ResetPassword(string newPassword, string accountOwneruserName /*user name for the user that you want to change his password*/)
{
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "17x.xx.xx.x" /*Active Directory server Ip*/, adminUserName, adminPassword ))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, accountOwneruserName))
{
if (user != null)
{
user.SetPassword(newPassword.Trim());
user.Save();
return true;
}
else
{
throw new Exception(string.Format("Username not found: {0}", accountOwneruserName));
}
}
return false;
}
}
I'm working on a project using Asp.NET web api, and my authentication system is based on identity 2.0. When user sends the ResetPassword form, he gets "Invalid token"
this is my forgotpassword method
public async Task<HttpResponseMessage> ForgotPassword(ForgotPasswordViewModel model)
{
if (!ModelState.IsValid)
{
HttpError error = new HttpError(ModelState, false);
error.Message = Resource.No_Item_Found_Message;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
HttpError error = new HttpError();
error.Message = Resource.Process_Failed;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
var provider = new DpapiDataProtectionProvider("ECommerceWebApp");
UserManager.UserTokenProvider = new DataProtectorTokenProvider<ECommerceUser, string>(provider.Create("UserToken"));
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
code = HttpUtility.UrlEncode(code);
try
{
// var callbackUrl = new Uri(Url.Link("ResetPasswordRoute", new { userId = user.Id, code = code, newPassword = model.Password }));
var callbackUrl = Url.Link("Default", new { Controller = "Account", action = "ResetPassword", userId = user.Id, code = code });
await UserManager.SendEmailAsync(user.Id, "تغییر رمز عبور در IRI1", "<div style='font-family:tahoma;direction:rtl;text-align:right;font-size:12px;'>" + "<h3>اولین و بزرگترین مرکز دادوستد بدون واسطه در ایران و کشورهای همسایه</h3>لطفاً با کلیک بر روی گزینۀ تغییر رمز به صفحۀ مربوطه بروید : <br/><br/>تغییر رمز عبور <br/><br/><br/><a href='iri1.com'>Iri1 Web Sites</a>" + "</div>");
}
catch (Exception ex)
{
HttpError error = new HttpError();
error.Message = ex.Message;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, error);
}
return Request.CreateResponse(Resource.Reset_Password_Message_Client);
}
and this is my ResetPassword method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
var code = HttpUtility.UrlDecode(model.Code);
var result = await UserManager.ResetPasswordAsync(user.Id, code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
AddErrors(result);
return View();
}
I still get invalid token error
I've just begun learning Identity Authentication and have no way to run samples from the Internet(I've got no visual studio). But I've noticed this method from GidHub samples, which seems to me to be wrong:
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
return code == null ? View("Error") : View();
}
In my humble opinion this method should do this:
return code == null ? View("Error") : View(new ResetPasswordViewModel{Code = code});
And thus the hidden field in ResetPassword view contains the Code. When the user clicks the submit button this code will be posted with the email and password to the httppost ResetPassword action where you can access the code thus: model.Code
Now I hope you've got a valid token
I have an mvc4 forms application that uses the simple membership OOTB account controller. I have a view model for the application where I was successfully able to retrieve the username after completing registration as follows:
this.UserName = HttpContext.Current.User.Identity.Name;
At the point this was working my registration method was as follows:
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, propertyValues: new
{
//Form defined values
Forename = model.Forename,
Surname = model.Surname,
Email = model.Email,
Password = model.Password,
Answer = model.SecretAnswer,
DOB = model.DOB,
//Auto defined values
JoinDate = DateTime.Today,
LastLogin = DateTime.Now,
CompanyID = 5,
ParticipationPoints = 0,
Privacy = 0,
IsDeleted = 0,
ImageURL = "/Images/user-holder.jpg"
});
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
After consultation with my customer it was decided that to prevent anyone from just registering on the internet they should already be contained with the usertable with the username value found as a pre existing user. So after this the registration was changed to:
Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
avm.Username = model.UserName;
avm.Forename = model.Forename;
avm.Surname = model.Surname;
avm.Email = model.Email;
avm.Password = model.Password;
avm.Answer = model.SecretAnswer;
avm.DOB = model.DOB;
avm.RegisterUser();
if (avm.StatusCode == "Success")
{
return RedirectToAction("Index", "Home");
}
else
{
//ModelState.AddModelError("", ErrorCodeToString(avm.StatusCode));
return View();
}
}
}
ViewModel
try
{
this.dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
userRepository = new Repository<MyUser>(dbcontext);
//Step 1 - Check User is in user table.
MyUser userCheck = userRepository.Get(u => u.Username == this.Username).ToList().FirstOrDefault();
if (userCheck == null)
{
StatusCode = "NoUserError";
return;
}
else
{
//Step 2 - Check user has not already registered
if (userCheck.Password != null || userCheck.Answer != null)
{
StatusCode = "AlreadyRegistered";
return;
}
}
//Step 3 - Check the email is valid and the password confirms to password length.
Regex expEmail = new Regex(#"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
if (!expEmail.IsMatch(this.Email))
{
StatusCode = "InvalidEmail";
return;
}
if (this.Password.Length < 8)
{
StatusCode = "InvalidPassword";
return;
}
//Encrypt the password to store in SQL Azure. It does not at this point have any encryption.
EncryptionUtils encryptor = new EncryptionUtils();
string encrytpedPassword = encryptor.Encrypt(this.Password);
//Form defined fields
userCheck.Username = this.Username;
userCheck.Password = encrytpedPassword;
userCheck.Forename = this.Forename;
userCheck.Surname = this.Surname;
userCheck.Email = this.Email;
userCheck.Answer = this.Answer;
userCheck.DOB = this.DOB;
//Automatically defined values
userCheck.JoinDate = DateTime.Today;
userCheck.LastLogin = DateTime.Now;
userCheck.CompanyID = 5;
userCheck.RoleID = 3;
userCheck.ParticipationPoints = 0;
userCheck.Privacy = 0;
userCheck.IsDeleted = false;
userCheck.ImageURL = "/Images/user-holder.jpg";
userRepository.Update(userCheck);
userRepository.SaveChanges();
StatusCode = "Success";
}
catch (Exception ex)
{
StatusCode = "Error";
return;
}
}
Now when I hit the home controller I am not able to access the HttpContext.Current.User.Identity.Name value. Has the authenticated username been stored elsewhere due to the changes?
Authentication cookie must be issued after registration success. Try,
if (avm.StatusCode == "Success")
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Index", "Home");
}
hope this helps.
I am creating one web app (mvc 4) to authorize customers (using membership provider) to view the reports(SSRS 2008) for which they are registered but they don't have any kind of access to our report server.
Based on the link How do I render a remote ReportViewer aspx page in MVC4?, I have implemented Elsimer's latest answer and it works well in downloading as a pdf file.
But when I try to render as html using the same code mentioned in the above link it is asking for the windows credentials to access the report server.
So I am giving a general credential which has all access to all the reports in the reportserver through the code. but it is still asking for the credentials for the report server when they try to view as html in the client side browser. Report is getting rendered but the images and graphs are not rendering without credentials.
Please advise, I have tried many things to solve this. but no luck.
My controller and credential class code as follows:
[Route("report/MonthlySummary")]
[ValidateAntiForgeryToken]
public ActionResult MonthlySummary(MonthlyReportParameters model)
{
if (ModelState.IsValid)
{
try
{
var actionType = model.ActionType;
if (actionType == "View Report")
{
return ExportMonthlyReportToHtml(model);
}
else if (actionType == "Download pdf report")
{
return ExportMonthlyReportToPdf(model);
}
}
catch (Exception ex)
{
//Logging errors
}
}
return null;
}
private ActionResult ExportMonthlyReportToHtml(MonthlyReportParameters monthlyParams)
{
ReportViewer reportViewer = BuildMonthlyReport(monthlyParams);
reportViewer.ServerReport.Refresh();
byte[] streamBytes = null;
string mimeType = "";
string encoding = "";
string filenameExtension = "";
string[] streamids = null;
Warning[] warnings = null;
//To view the report in html format
streamBytes = reportViewer.ServerReport.Render("HTML4.0", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
var htmlReport = File(streamBytes, "text/html");
return htmlReport;
}
private static ReportViewer BuildMonthlyReport(MonthlyReportParameters model)
{
ReportViewer reportViewer = new Microsoft.Reporting.WebForms.ReportViewer();
try
{
var rptParameters = new List<ReportParameter>
{
//Building parameters
};
reportViewer.ProcessingMode = ProcessingMode.Remote;
reportViewer.ServerReport.ReportPath = "/reportFolder/reportName";
var reportServerUrl = ConfigurationManager.AppSettings["ReportServerUrl"];
if(!string.IsNullOrEmpty(reportServerUrl))
{
reportViewer.ServerReport.ReportServerUrl = new Uri(reportServerUrl);
}
reportViewer.ServerReport.ReportServerCredentials = new ReportServerCredentials();
reportViewer.ServerReport.SetParameters(rptParameters);
}
catch (Exception ex)
{
var errorMessage = ex.Message;
//TODO: handle errors;
}
return reportViewer;
}
public sealed class ReportServerCredentials : IReportServerCredentials
{
public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
{
authCookie = null;
userName = null;
password = null;
authority = null;
return false;
}
public WindowsIdentity ImpersonationUser
{
get
{
return null;
}
}
public ICredentials NetworkCredentials
{
get
{
string userName = ConfigurationManager.AppSettings["ReportUserName"];
if ((string.IsNullOrEmpty(userName)))
{
throw new Exception("Missing user name from web.config file");
}
string password = ConfigurationManager.AppSettings["ReportPassword"];
if ((string.IsNullOrEmpty(password)))
{
throw new Exception("Missing password from web.config file");
}
string domain = ConfigurationManager.AppSettings["DomainName"];
if ((string.IsNullOrEmpty(domain)))
{
throw new Exception("Missing domain from web.config file");
}
return new NetworkCredential(userName, password, domain);
}
}
}
Thanks in advance,
my colleague and myself are working on an application form with login functionality the user logs in from the mvc 4 app and there details are submitted to the web api to be checked against the values held in the database once verified the web api returns a loginResult class that contains the error message (if any) and a bool for stating whether it has been successful or not.
at the mvc 4 application level the code below is used to submit the login details to the web api:
Login Action
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(AccountViewModel model)
{
if (!ModelState.IsValid) return View("Login", model);
await _client.PostAsJsonAsync("api/Applicant/CheckApplicant", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
var service = DependencyResolver.Current.GetService<IApplyService>();
var loginResult = service.GetLoginResult();
var loginSuccess = loginResult.LoginSuccess;
if (loginSuccess != null && (bool) loginSuccess)
{
FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe);
return RedirectToRoute("Terms And Conditions");
}
return View("Login");
}
the login details are then received at the web api in this method:
Check Applicant Method
public String CheckApplicant(Applicant applicant)
{
Int32 passwordFailureTimeoutMins = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["PasswordFailureTimeoutMins"]);
Int32 passwordFailureAttempts = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["PasswordFailureAttempts"]);
ApplicantRepository applicantRepository = new ApplicantRepository();
Applicant applicantDB = applicantRepository.GetById(applicant.Email);
LoginResult loginResult = new LoginResult();
PasswordHelper passwordHelper = new PasswordHelper();
if (applicantDB == null)
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "Your password or login may not be correct.";
}
else
{
bool loginFailureCheck;
if (applicantDB.LoginFailureCount > passwordFailureAttempts)
{
System.TimeSpan diffResult = DateTime.Now.Subtract(Convert.ToDateTime(applicantDB.LastLoginFailure));
if (diffResult.Minutes < passwordFailureTimeoutMins)
{
loginFailureCheck = false;
}
else
{
loginFailureCheck = true;
}
}
else
{
loginFailureCheck = true;
}
if (passwordHelper.CheckPassword(applicant.Password, applicantDB.Password))
{
if(loginFailureCheck)
{
if(applicantDB.AccountActive)
{
loginResult.LoginSuccess = true;
loginResult.LoginError = "Login Successful.";
applicantDB.LastLoginFailure = null;
applicantDB.LastLoginSuccess = DateTime.Now;
applicantDB.LoginFailureCount = 0;
applicantRepository.Update(applicantDB);
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "This account has been permanently banned.";
}
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "This account is now temporarily disabled please wait " + passwordFailureTimeoutMins + " minutes before trying again";
applicantDB.LastLoginFailure = DateTime.Now;
applicantDB.LoginFailureCount = applicantDB.LoginFailureCount + 1;
applicantRepository.Update(applicantDB);
}
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "Your password or login may not be correct.";
applicantDB.LastLoginFailure = DateTime.Now;
applicantDB.LoginFailureCount = applicantDB.LoginFailureCount + 1;
applicantRepository.Update(applicantDB);
}
}
return JsonConvert.SerializeObject(loginResult);
}
as you can see it returns a JsonConvert.SerializeObject(loginResult).
when this is done the process returns to the Login ActionResult as above it then moves to the GetLoginResult() method as shown below:
GetLoginResult
public LoginResult GetLoginResult()
{
const string uri = "http://localhost:55830/api/Applicant/CheckApplicant";
using (var httpClient = new HttpClient())
{
var response = httpClient.GetStringAsync(uri);
return JsonConvert.DeserializeObject<LoginResult>(response.Result);
}
}
when it get to this point it returns an error 405 method not allowed.
How do I consume the loginResult at the mvc 4 app level and what is the best way of sending the loginResult from the web api?
Any advice would be greatly appreciated.
Not sure what exactly you are trying to do but are you making a GET to read the result of the previous POST? You can read the response message of POST to get the result, like this.
public async Task<ActionResult> Login(AccountViewModel model)
{
if (!ModelState.IsValid) return View("Login", model);
var message = await _client.PostAsJsonAsync
("api/Applicant/CheckApplicant", model);
message.EnsureSuccessStatusCode();
LoginResult result = await message.Content.ReadAsAsync<LoginResult>();
// do other stuff here
}
Change the web API action method to return LoginResult directly. The framework will serialize it for you.
public LoginResult CheckApplicant(Applicant applicant)
{
}