using Dapper; using Dapper.Contrib.Extensions; using MailKit.Security; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Options; using MimeKit; using Newtonsoft.Json; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; using System.DirectoryServices.Protocols; using System.Net; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using static ad_login.Controllers.ApiController; using static DbTableClass; namespace ad_login.Controllers { [EnableCors("any")] [Route("adApi")] public class AdApiController : ControllerBase { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IWebHostEnvironment _hostingEnvironment; private readonly PasswordManagementService _passwordManagement; private readonly string _ldapServer; private readonly string _domain; private readonly string _baseDn; DbConn dbConn = new DbConn(); SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString")); public AdApiController(IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment, PasswordManagementService passwordManagement, IOptions ldapSettings) { this._httpContextAccessor = httpContextAccessor; this._hostingEnvironment = webHostEnvironment; this._passwordManagement = passwordManagement; this._ldapServer = ldapSettings.Value.Server; this._domain = ldapSettings.Value.Domain; this._baseDn = ldapSettings.Value.BaseDn; } [EnableCors("any")] [Route("resetPassword")] [SupportedOSPlatform("windows")] public ActionResult ResetPassword(IFormCollection obj) { Result ret = new Result(); string new_password = obj["new_password"].ToString(); string token = obj["token"].ToString(); if (new_password == "") { ret.message = "new_password is null"; ret.err_code = "1003"; ret.ret = "no"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } mailToken objMailToken = conn.QueryFirstOrDefault("select * from mailToken where mailToken_value=@mailToken_value and mailToken_useed='N' and mailToken_endDate>=getdate()", new { mailToken_value = token }); if (objMailToken == null) { ret.ret = "no"; ret.err_code = "1001"; ret.message = "token無效或過期,或是已經變更密碼過了,請重新申請忘記密碼步驟"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } try { DirectoryEntry entry = new DirectoryEntry($"LDAP://{_ldapServer}/{_baseDn}", GlobalClass.appsettings("LdapSettings:User"), GlobalClass.appsettings("LdapSettings:Password")); // 使用 LDAP 伺服器和基礎 DN 建立 DirectoryEntry 物件。 DirectorySearcher mySearcher = new DirectorySearcher(entry); mySearcher.Filter = ("(&(objectClass=user)(sAMAccountName=" + objMailToken.mailToken_account + "))"); SearchResult searchResult = mySearcher.FindOne(); DirectoryEntry userEntry = searchResult.GetDirectoryEntry(); userEntry.Invoke("SetPassword", new object[] { new_password }); ret.ret = "yes"; objMailToken.mailToken_useed = "Y"; conn.Update(objMailToken); return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } catch (Exception ex) { ret.ret = "no"; ret.err_code = "1002"; ret.message = "修改密碼失敗,請聯絡系統管理員 原因為" + ex.Message; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } [EnableCors("any")] [Route("forgetPassword")] [SupportedOSPlatform("windows")] public async Task ForgetPasswordAsync(IFormCollection obj) { Result ret = new Result(); string userEmail = obj["userEmail"].ToString(); string userAccount = obj["userAccount"].ToString(); if (userAccount == "") { ret.message = "userAccount is null"; ret.err_code = "1003"; ret.ret = "no"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } if (userEmail == "") { ret.message = "userEmail is null"; ret.err_code = "1004"; ret.ret = "no"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, _domain, _baseDn, GlobalClass.appsettings("LdapSettings:User"), GlobalClass.appsettings("LdapSettings:Password"))) { UserPrincipal user = UserPrincipal.FindByIdentity(pc, userAccount); if (user != null) { if (user.Enabled == false) { ret.message = "此帳號已被停用"; ret.err_code = "1007"; ret.ret = "no"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } string emailaddress = user.EmailAddress ?? ""; if (emailaddress != userEmail) { ret.message = "帳號與Email不符,不是公司發給此帳號的Email"; ret.err_code = "1005"; ret.ret = "no"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } mailToken objMailToken = new mailToken(); objMailToken.mailToken_value = GlobalClass.CreateRandomCode(24); objMailToken.mailToken_mail = userEmail; objMailToken.mailToken_endDate = DateTime.Now.AddHours(12); objMailToken.mailToken_account = userAccount; conn.Insert(objMailToken); string htmlBody = ""; htmlBody += "

重設登入PC或公槽密碼確認信

"; htmlBody += "
如果您有重設登入PC或公槽密碼需求的話,請點下面連結開始網頁重設密碼。如果沒有請忽略此信!"; htmlBody += "

重設密碼連結:" + "https://ad-pass.bremen.com.tw/Home/reset?token=" + objMailToken.mailToken_value + ""; htmlBody += "

PS:此連結於" + objMailToken.mailToken_endDate.ToString("yyyy/MM/dd HH:mm") + "前有效!"; MailRequest mailRequest = new MailRequest(); mailRequest.ToEmail = userEmail; mailRequest.Body = htmlBody; mailRequest.Subject = "重設登入PC或公槽密碼確認信"; await SendEmailAsync(mailRequest); ret.ret = "yes"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } else { ret.message = "User not found"; ret.err_code = "1006"; ret.ret = "no"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } } return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } [EnableCors("any")] [Route("aduserList")] [SupportedOSPlatform("windows")] public ActionResult AduserList(IFormCollection obj) { Result ret = new Result(); string query_token = obj["query_token"].ToString(); if (query_token == "") { ret.message = "query_token is null"; ret.err_code = "1001"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } if (query_token != GlobalClass.appsettings("LdapSettings:query_token")) { ret.message = "query_token is wrong"; ret.err_code = "1002"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } List expiringUsers = []; DirectoryEntry entry = new DirectoryEntry($"LDAP://{_ldapServer}/{_baseDn}", GlobalClass.appsettings("LdapSettings:User"), GlobalClass.appsettings("LdapSettings:Password")); // 使用 LDAP 伺服器和基礎 DN 建立 DirectoryEntry 物件。 DirectorySearcher mySearcher = new DirectorySearcher(entry); mySearcher.Filter = "(&(objectCategory=person)(objectClass=user))"; // 篩選有「上次密碼設定時間」、「Mail」的「使用者」。 // 電子郵件 foreach (SearchResult result in mySearcher.FindAll()) { string userSAMAccountName = result.Properties["sAMAccountName"][0].ToString() ?? string.Empty; // AD 帳號 string userDisplayName = ""; string userMail = ""; if (result.Properties["displayName"].Count > 0) userDisplayName = result.Properties["displayName"][0].ToString(); else userDisplayName = userSAMAccountName; // 顯示名稱 if (result.Properties["mail"].Count > 0) { userMail = result.Properties["mail"][0].ToString() ?? string.Empty; } int flags = (int)result.Properties["userAccountControl"][0]; string expiringUsersInfo = $"{userSAMAccountName};{userDisplayName};{userMail}"; adUser adUser = new adUser { userAccount = userSAMAccountName, userDisplayName = userDisplayName, userMail = userMail }; if (!Convert.ToBoolean(flags & 0x0002) && (userMail != "")) { ret.data.Add(adUser); // 如果帳號沒有被停用,且有電子郵件,就加入結果列表。 } } ret.ret = "yes"; return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8"); } public async Task SendEmailAsync(MailRequest mailRequest) { var email = new MimeMessage(); email.Sender = MailboxAddress.Parse(GlobalClass.appsettings("MailServer:smtp_username")); email.To.Add(MailboxAddress.Parse(GlobalClass.appsettings("MailServer:smtp_username"))); foreach (string item in mailRequest.ToEmail.Split(',')) { email.Bcc.Add(MailboxAddress.Parse(item)); } email.Subject = "重設登入PC或公槽密碼確認信"; var builder = new BodyBuilder(); if (mailRequest.attach != null) { builder.Attachments.Add(mailRequest.attachName, mailRequest.attach); } builder.HtmlBody = mailRequest.Body; email.Body = builder.ToMessageBody(); using var smtp = new MailKit.Net.Smtp.SmtpClient(); smtp.Connect(GlobalClass.appsettings("MailServer:smtp_host"), int.Parse(GlobalClass.appsettings("MailServer:smtp_port")), SecureSocketOptions.StartTls); smtp.Authenticate(GlobalClass.appsettings("MailServer:smtp_username"), GlobalClass.appsettings("MailServer:smtp_password")); await smtp.SendAsync(email); smtp.Dispose(); } public class Result { public string ret = "no"; public string err_code = "0000"; public string message = ""; public List data = new List(); } public class adUser { public string userAccount { get; set; } = string.Empty; // AD 帳號 public string userDisplayName { get; set; } = string.Empty; // 顯示名稱 public string userMail { get; set; } = string.Empty; // 電子郵件 } } }