diff --git a/web/Areas/Directory/Controllers/DirectoryController.cs b/web/Areas/Directory/Controllers/DirectoryController.cs new file mode 100644 index 0000000..0239425 --- /dev/null +++ b/web/Areas/Directory/Controllers/DirectoryController.cs @@ -0,0 +1,148 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Viper.Models.AAUD; +using Viper.Areas.RAPS.Services; +using Web.Authorization; +using Viper.Classes; +using Viper.Classes.SQLContext; +using Viper.Areas.Directory.Models; +using System.Runtime.Versioning; +using System.Collections.Generic; +using Viper.Areas.Directory.Services; +using Viper.Classes.Utilities; + +namespace Viper.Areas.Directory.Controllers +{ + [Area("Directory")] + [Permission(Allow = "SVMSecure")] + [Authorize(Roles = "VMDO SVM-IT")] //locking directory for now until it's complete + public class DirectoryController : AreaController + { + public Classes.SQLContext.AAUDContext _aaud; + private readonly RAPSContext? _rapsContext; + public IUserHelper UserHelper; + + public DirectoryController(Classes.SQLContext.RAPSContext context) + { + _aaud = new AAUDContext(); + this._rapsContext = (RAPSContext?)HttpHelper.HttpContext?.RequestServices.GetService(typeof(RAPSContext)); + UserHelper = new UserHelper(); + } + + /// + /// Directory home page + /// + [Route("/[area]/")] + public async Task Index(string? useExample) + { + return await Task.Run(() => View("~/Areas/Directory/Views/Card.cshtml")); + } + + /// + /// Directory home page + /// + [Route("/[area]/nav")] + public async Task>> Nav() + { + var nav = new List + { + }; + return await Task.Run(() => nav); + } + + + /// + /// Directory list + /// + /// search string + /// + [SupportedOSPlatform("windows")] + [Route("/[area]/search/{search}")] + public async Task>> Get(string search) + { + var individuals = await _aaud.AaudUsers + .Where(u => (u.DisplayFirstName + " " + u.DisplayLastName).Contains(search) + || (u.MailId != null && u.MailId.Contains(search)) + || (u.LoginId != null && u.LoginId.Contains(search)) + || (u.SpridenId != null && u.SpridenId.Contains(search)) + || (u.Pidm != null && u.Pidm.Contains(search)) + || (u.MothraId != null && u.MothraId.Contains(search)) + || (u.EmployeeId != null && u.EmployeeId.Contains(search)) + || (u.IamId != null && u.IamId.Contains(search)) + ) + .Where(u => u.Current != 0) + .OrderBy(u => u.DisplayLastName) + .ThenBy(u => u.DisplayFirstName) + .ToListAsync(); + List results = new(); + AaudUser? currentUser = UserHelper.GetCurrentUser(); + bool hasDetailPermission = UserHelper.HasPermission(_rapsContext, currentUser, "SVMSecure.DirectoryDetail"); + individuals.ForEach(m => + { + LdapUserContact? l = new LdapService().GetUserByID(m.IamId); + results.Add(hasDetailPermission + ? new IndividualSearchResultWithIDs(m, l) + : new IndividualSearchResult(m, l)); + + var vmsearch = VMACSService.Search(results.Last().LoginId); + var vm = vmsearch.Result; + if (vm != null && vm.item != null && vm.item.Nextel != null && vm.item.LDPager != null) + { + results.Last().Nextel = vm.item.Nextel[0]; + results.Last().LDPager = vm.item.LDPager[0]; + } + }); + return results; + } + + /// + /// Directory list + /// + /// search string + /// + [SupportedOSPlatform("windows")] + [Route("/[area]/search/{search}/ucd")] + public async Task>> GetUCD(string search) + { + List results = new(); + List ldap = LdapService.GetUsersContact(search); + var individuals = await _aaud.AaudUsers + .Where(u => (u.DisplayFirstName + " " + u.DisplayLastName).Contains(search) + || (u.MailId != null && u.MailId.Contains(search)) + || (u.LoginId != null && u.LoginId.Contains(search)) + || (u.SpridenId != null && u.SpridenId.Contains(search)) + || (u.Pidm != null && u.Pidm.Contains(search)) + || (u.MothraId != null && u.MothraId.Contains(search)) + || (u.EmployeeId != null && u.EmployeeId.Contains(search)) + || (u.IamId != null && u.IamId.Contains(search)) + ) + .Where(u => u.Current != 0) + .OrderBy(u => u.DisplayLastName) + .ThenBy(u => u.DisplayFirstName) + .ToListAsync(); + AaudUser? currentUser = UserHelper.GetCurrentUser(); + bool hasDetailPermission = UserHelper.HasPermission(_rapsContext, currentUser, "SVMSecure.DirectoryDetail"); + foreach (var l in ldap) + { + AaudUser? userInfo = individuals.Find(m => m.IamId == l.UcdPersonIamId); + results.Add(hasDetailPermission + ? new IndividualSearchResultWithIDs(userInfo, l) + : new IndividualSearchResult(userInfo, l)); + }; + return results; + } + + /// + /// Directory results + /// + /// User ID + /// + [Route("/[area]/userInfo/{mothraID}")] + public async Task DirectoryResult(string mothraID) + { + // pull in the user based on uid + return await Task.Run(() => View("~/Areas/Directory/Views/UserInfo.cshtml")); + } + } +} diff --git a/web/Areas/Directory/Models/IndividualSearchResult.cs b/web/Areas/Directory/Models/IndividualSearchResult.cs new file mode 100644 index 0000000..24c5de5 --- /dev/null +++ b/web/Areas/Directory/Models/IndividualSearchResult.cs @@ -0,0 +1,118 @@ +using Microsoft.EntityFrameworkCore; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using Viper.Areas.Directory.Services; +using Viper.Models.AAUD; + +namespace Viper.Areas.Directory.Models +{ + public class IndividualSearchResult + { + public string ClientId { get; set; } = string.Empty; + public string MothraId { get; set; } = string.Empty; + public string UCDPersonUUID { get; set; } = string.Empty; + public string? LoginId { get; set; } = string.Empty; + public string? MailId { get; set; } = string.Empty; + public string? EmailHost { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string FirstName { get; set; } = string.Empty; + public string? MiddleName { get; set; } = string.Empty; + public string DisplayLastName { get; set; } = string.Empty; + public string DisplayFirstName { get; set; } = string.Empty; + public string? DisplayMiddleName { get; set; } = string.Empty; + public string DisplayFullName { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public bool CurrentStudent { get; set; } = false; + public bool FutureStudent { get; set; } = false; + public bool CurrentEmployee { get; set; } = false; + public bool FutureEmployee { get; set; } = false; + public int? StudentTerm { get; set; } = null!; + public int? EmployeeTerm { get; set; } = null!; + public string? PpsId { get; set; } = string.Empty; + public string? StudentPKey { get; set; } = string.Empty; + public string? EmployeePKey { get; set; } = string.Empty; + public string? Title { get; set; } = string.Empty; + public string? Department { get; set; } = string.Empty; + public int Current { get; set; } = -1; + public int Future { get; set; } = -1; + public string? IamId { get; set; } = string.Empty; + public bool? Ross { get; set; } = null!; + public DateTime? Added { get; set; } = null!; + public string? Phone { get; set; } = null!; + public string? Nextel { get; set; } = null!; + public string? LDPager { get; set; } = null!; + public string? Mobile { get; set; } = null!; + public string? PostalAddress { get; set; } = null!; + public string? UCDAffiliation { get; set; } = null!; + public string? UserName { get; set; } = null!; + public bool? SVM { get; set; } = null!; + public string? originalObject { get; set; } = null!; + + public IndividualSearchResult() { } + + [SupportedOSPlatform("windows")] + public IndividualSearchResult(AaudUser? aaudUser, LdapUserContact? ldapUserContact) + { + SVM = false; + originalObject = ""; + if (aaudUser != null) { + MothraId = aaudUser.MothraId; + LoginId = aaudUser.LoginId; + MailId = aaudUser.MailId; + LastName = aaudUser.LastName; + FirstName = aaudUser.FirstName; + MiddleName = aaudUser.MiddleName; + DisplayLastName = aaudUser.DisplayLastName; + DisplayFirstName = aaudUser.DisplayFirstName; + DisplayMiddleName = aaudUser.DisplayMiddleName; + DisplayFullName = aaudUser.DisplayFullName; + Name = aaudUser.DisplayFullName; + CurrentStudent = aaudUser.CurrentStudent; + FutureStudent = aaudUser.FutureStudent; + CurrentEmployee = aaudUser.CurrentEmployee; + FutureEmployee = aaudUser.FutureEmployee; + StudentTerm = aaudUser.StudentTerm; + EmployeeTerm = aaudUser.EmployeeTerm; + PpsId = aaudUser.PpsId; + StudentPKey = aaudUser.StudentPKey; + EmployeePKey = aaudUser.EmployeePKey; + Current = aaudUser.Current; + Future = aaudUser.Future; + IamId = aaudUser.IamId; + Ross = aaudUser.Ross; + SVM = true; + Added = aaudUser.Added; + UserName = aaudUser.LoginId; + } + if (ldapUserContact != null) + { + Title = ldapUserContact.Title; + //Department = ldapUserContact.Department; + Phone = ldapUserContact.TelephoneNumber; + Mobile = ldapUserContact.Mobile; + UserName = ldapUserContact.Uid; + PostalAddress = (ldapUserContact.PostalAddress ?? "").Replace("$", '\n'.ToString()); + UCDAffiliation = ldapUserContact.UcdPersonAffiliation; + UCDPersonUUID = ldapUserContact.UcdPersonUuid; + if (string.IsNullOrEmpty(DisplayFullName)) + { + DisplayFullName = ldapUserContact.DisplayName; + } + if (string.IsNullOrEmpty(Name)) + { + Name = ldapUserContact.DisplayName; + } + } + + using (var context = new Classes.SQLContext.AAUDContext()) + { + var query = $"SELECT * FROM OPENQUERY(UCDMothra,'SELECT (USERPART || ''@'' || HOSTPART) AS USERATHOST FROM MOTHRA.MAILIDS WHERE MOTHRAID = ''{MothraId}'' AND MAILID = ''{MailId}'' AND MAILSTATUS = ''A'' AND MAILTYPE = ''P''')".ToString(); + var results = context.Database.SqlQuery(FormattableStringFactory.Create(query)).ToList(); + foreach (var r in results) + { + EmailHost = r.Split("@").Last(); + } + } + } + } +} diff --git a/web/Areas/Directory/Models/IndividualSearchResultCreator.cs b/web/Areas/Directory/Models/IndividualSearchResultCreator.cs new file mode 100644 index 0000000..3ac2988 --- /dev/null +++ b/web/Areas/Directory/Models/IndividualSearchResultCreator.cs @@ -0,0 +1,98 @@ +using System.Runtime.Versioning; +using Viper.Models.AAUD; + +namespace Viper.Areas.Directory.Models +{ + public class IndividualSearchResultCreator + { + [SupportedOSPlatform("windows")] + public static IndividualSearchResult CreateIndividualSearchResult(AaudUser? aaudUser, LdapUserContact? ldapUserContact, bool includeDetail=false) + { + if (includeDetail) + { + IndividualSearchResultWithIDs indiv = new(); + if (aaudUser != null) + { + AddAaudUser(indiv, aaudUser); + AddIds(indiv, aaudUser); + } + if (ldapUserContact != null) + { + AddLdapContact(indiv, ldapUserContact); + } + + return indiv; + } + else + { + IndividualSearchResult indiv = new(); + if (aaudUser != null) + { + AddAaudUser(indiv, aaudUser); + } + if (ldapUserContact != null) + { + AddLdapContact(indiv, ldapUserContact); + } + return indiv; + } + } + + private static void AddAaudUser(IndividualSearchResult indiv, AaudUser aaudUser) + { + indiv.MothraId = aaudUser.MothraId; + indiv.LoginId = aaudUser.LoginId; + indiv.MailId = aaudUser.MailId; + indiv.LastName = aaudUser.LastName; + indiv.FirstName = aaudUser.FirstName; + indiv.MiddleName = aaudUser.MiddleName; + indiv.DisplayLastName = aaudUser.DisplayLastName; + indiv.DisplayFirstName = aaudUser.DisplayFirstName; + indiv.DisplayMiddleName = aaudUser.DisplayMiddleName; + indiv.DisplayFullName = aaudUser.DisplayFullName; + indiv.Name = aaudUser.DisplayFullName; + indiv.CurrentStudent = aaudUser.CurrentStudent; + indiv.FutureStudent = aaudUser.FutureStudent; + indiv.CurrentEmployee = aaudUser.CurrentEmployee; + indiv.FutureEmployee = aaudUser.FutureEmployee; + indiv.StudentTerm = aaudUser.StudentTerm; + indiv.EmployeeTerm = aaudUser.EmployeeTerm; + indiv.PpsId = aaudUser.PpsId; + indiv.StudentPKey = aaudUser.StudentPKey; + indiv.EmployeePKey = aaudUser.EmployeePKey; + indiv.Current = aaudUser.Current; + indiv.Future = aaudUser.Future; + indiv.IamId = aaudUser.IamId; + indiv.Ross = aaudUser.Ross; + indiv.Added = aaudUser.Added; + } + + private static void AddIds(IndividualSearchResultWithIDs indiv, AaudUser aaudUser) + { + indiv.SpridenId = aaudUser.SpridenId; + indiv.Pidm = aaudUser.Pidm; + indiv.EmployeeId = aaudUser.EmployeeId; + indiv.VmacsId = aaudUser.VmacsId; + indiv.UnexId = aaudUser.UnexId; + indiv.MivId = aaudUser.MivId; + } + + [SupportedOSPlatform("windows")] + private static void AddLdapContact(IndividualSearchResult indiv, LdapUserContact ldapUserContact) + { + indiv.Title = ldapUserContact.Title; + indiv.Department = ldapUserContact.Ou; + indiv.Phone = ldapUserContact.TelephoneNumber; + indiv.Mobile = ldapUserContact.Mobile; + indiv.UserName = ldapUserContact.Uid; + if(string.IsNullOrEmpty(indiv.DisplayFullName)) + { + indiv.DisplayFullName = ldapUserContact.DisplayName; + } + if(string.IsNullOrEmpty(indiv.Name)) + { + indiv.Name = ldapUserContact.DisplayName; + } + } + } +} diff --git a/web/Areas/Directory/Models/IndividualSearchResultWithIDs.cs b/web/Areas/Directory/Models/IndividualSearchResultWithIDs.cs new file mode 100644 index 0000000..fb74a6a --- /dev/null +++ b/web/Areas/Directory/Models/IndividualSearchResultWithIDs.cs @@ -0,0 +1,61 @@ +using System.Runtime.Versioning; +using Viper.Models.AAUD; + +namespace Viper.Areas.Directory.Models +{ + public class IndividualSearchResultWithIDs: IndividualSearchResult + { + public string? SpridenId { get; set; } = string.Empty; + + public string? Pidm { get; set; } = string.Empty; + + public string? EmployeeId { get; set; } = string.Empty; + + public int? VmacsId { get; set; } = null!; + + public string? VmcasId { get; set; } = string.Empty; + + public string? UnexId { get; set; } = string.Empty; + + public int? MivId { get; set; } = null!; + + public IndividualSearchResultWithIDs() + { + + } + + [SupportedOSPlatform("windows")] + public IndividualSearchResultWithIDs(AaudUser? aaudUser, LdapUserContact? ldapUserContact) + : base(aaudUser, ldapUserContact) + { + if (aaudUser != null) + { + SpridenId = aaudUser.SpridenId; + Pidm = aaudUser.Pidm; + EmployeeId = aaudUser.EmployeeId; + VmacsId = aaudUser.VmacsId; + UnexId = aaudUser.UnexId; + MivId = aaudUser.MivId; + } + else if(ldapUserContact != null) + { + Title = ldapUserContact.Title; + Department = ldapUserContact.Ou; + Phone = ldapUserContact.TelephoneNumber; + Mobile = ldapUserContact.Mobile; + UserName = ldapUserContact.Uid; + PostalAddress = (ldapUserContact.PostalAddress ?? "").Replace("$", '\n'.ToString()); + UCDAffiliation = ldapUserContact.UcdPersonAffiliation; + UCDPersonUUID = ldapUserContact.UcdPersonUuid; + if (string.IsNullOrEmpty(DisplayFullName)) + { + DisplayFullName = ldapUserContact.DisplayName; + } + if (string.IsNullOrEmpty(Name)) + { + Name = ldapUserContact.DisplayName; + } + } + } + } +} diff --git a/web/Areas/Directory/Models/LdapUserContact.cs b/web/Areas/Directory/Models/LdapUserContact.cs new file mode 100644 index 0000000..d069785 --- /dev/null +++ b/web/Areas/Directory/Models/LdapUserContact.cs @@ -0,0 +1,335 @@ +using Newtonsoft.Json; +using System.DirectoryServices; +using System.DirectoryServices.Protocols; +using System.Linq.Dynamic.Core; +using System.Runtime.CompilerServices; +using System.Runtime.Versioning; +using System.Security.Cryptography; +using System.Text.Json; + +namespace Viper.Areas.Directory.Models +{ + [SupportedOSPlatform("windows")] + public class LdapUserContact + { + public string Uid { get; set; } = null!; + public string SamAccountName { get; set; } = null!; + public string Ou { get; set; } = null!; + public string Sn { get; set; } = null!; + public string GivenName { get; set; } = null!; + public string MiddleName { get; set; } = null!; + public string DisplayName { get; set; } = null!; + public string EduPersonNickname { get; set; } = null!; + public string Title { get; set; } = null!; + public string PostalAddress { get; set; } = null!; + public string TelephoneNumber { get; set; } = null!; + public string Mobile { get; set; } = null!; + public string Mail { get; set; } = null!; + public string UcdStudentLevel { get; set; } = null!; + public string UcdStudentSid { get; set; } = null!; + public string UcdPersonPidm { get; set; } = null!; + public string EmployeeNumber { get; set; } = null!; + public string UcdPersonUuid { get; set; } = null!; + public string UcdPersonIamId { get; set; } = null!; + public string UcdPersonAffiliation { get; set; } = null!; + + /* + + public string? middlename { get; set; } = null!; + public string? eduPersonNickname { get; set; } = null!; + public string? ucdStudentLevel { get; set; } = null!; + public string? ucdPersonIAMID { get; set; } = null!; + public string? ucdPersonUUID { get; set; } = null!; + public string? ucdStudentSID { get; set; } = null!; + public string? ucdPersonPIDM { get; set; } = null!; + public string? employeeNumber { get; set; } = null!; + public string? ucdPersonAffiliation { get; set; } = null!; + + public string? accountexpires { get; set; } = null!; + public string? adspath { get; set; } = null!; + public string? badpasswordtime { get; set; } = null!; + public string? badpwdcount { get; set; } = null!; + public string? cn { get; set; } = null!; + public string? codepage { get; set; } = null!; + public string? company { get; set; } = null!; + public string? countrycode { get; set; } = null!; + public string? deliverandredirect { get; set; } = null!; + public string? department { get; set; } = null!; + public string? departmentnumber { get; set; } = null!; + public string Description { get; set; } = null!; + public string? displayname { get; set; } = null!; + public string? distinguishedname { get; set; } = null!; + public string? dscorepropagationdata { get; set; } = null!; + public string? edupersonaffiliation { get; set; } = null!; + public string? edupersonprincipalname { get; set; } = null!; + public string? employeenumber { get; set; } = null!; + public string? extensionattribute10 { get; set; } = null!; + public string? extensionattribute11 { get; set; } = null!; + public string? extensionattribute12 { get; set; } = null!; + public string? extensionattribute13 { get; set; } = null!; + public string? extensionattribute14 { get; set; } = null!; + public string? extensionattribute15 { get; set; } = null!; + public string? extensionattribute5 { get; set; } = null!; + public string? extensionattribute6 { get; set; } = null!; + public string? extensionattribute7 { get; set; } = null!; + public string? extensionattribute8 { get; set; } = null!; + public string? extensionattribute9 { get; set; } = null!; + public string? gidnumber { get; set; } = null!; + public string? givenname { get; set; } = null!; + public string? instancetype { get; set; } = null!; + public string? internetencoding { get; set; } = null!; + public string? l { get; set; } = null!; + public string? lastlogoff { get; set; } = null!; + public string? lastlogon { get; set; } = null!; + public string? lastlogontimestamp { get; set; } = null!; + public string? legacyexchangedn { get; set; } = null!; + public string? lockouttime { get; set; } = null!; + public string? logoncount { get; set; } = null!; + public string? mail { get; set; } = null!; + public string? mailnickname { get; set; } = null!; + public string? mapirecipient { get; set; } = null!; + public string? memberof { get; set; } = null!; + public string? mobile { get; set; } = null!; + public string? msexcharchiveguid { get; set; } = null!; + public string? msexcharchivename { get; set; } = null!; + public string? msexcharchivestatus { get; set; } = null!; + public string? msexchblockedsendershash { get; set; } = null!; + public string? msexchcomanagedobjectsbl { get; set; } = null!; + public string? msexchextensionattribute16 { get; set; } = null!; + public string? msexchextensionattribute17 { get; set; } = null!; + public string? msexchmailboxguid { get; set; } = null!; + public string? msexchpoliciesexcluded { get; set; } = null!; + public string? msexchrecipientdisplaytype { get; set; } = null!; + public string? msexchrecipienttypedetails { get; set; } = null!; + public string? msexchremoterecipienttype { get; set; } = null!; + public string? msexchsafesendershash { get; set; } = null!; + public string? msexchtextmessagingstate { get; set; } = null!; + public string? msexchumdtmfmap { get; set; } = null!; + public string? msexchuseraccountcontrol { get; set; } = null!; + public string? msexchversion { get; set; } = null!; + public string? msexchwhenmailboxcreated { get; set; } = null!; + public string? name { get; set; } = null!; + public string? objectcategory { get; set; } = null!; + public string? objectclass { get; set; } = null!; + public string? objectguid { get; set; } = null!; + public string? objectsid { get; set; } = null!; + public string? ou { get; set; } = null!; + public string? pager { get; set; } = null!; + public string? phone { get; set; } = null!; + public string? physicaldeliveryofficename { get; set; } = null!; + public string? postaladdress { get; set; } = null!; + public string? postalcode { get; set; } = null!; + public string? primarygroupid { get; set; } = null!; + public string? proxyaddresses { get; set; } = null!; + public string? pwdlastset { get; set; } = null!; + public string SamAccountName { get; set; } = null!; + public string? samaccounttype { get; set; } = null!; + public string? showinaddressbook { get; set; } = null!; + public string surName { get; set; } = null!; + public string? st { get; set; } = null!; + public string? street { get; set; } = null!; + public string? streetaddress { get; set; } = null!; + public string? targetaddress { get; set; } = null!; + public string? telephonenumber { get; set; } = null!; + public string? textencodedoraddress { get; set; } = null!; + public string? title { get; set; } = null!; + public string? ucdappointmentdepartmentcode { get; set; } = null!; + public string? ucdappointmenttitlecode { get; set; } = null!; + public string? ucdpersonaffiliation { get; set; } = null!; + public string? ucdpersoniamid { get; set; } = null!; + public string? ucdpersonnetid { get; set; } = null!; + public string? ucdpersonpidm { get; set; } = null!; + public string? ucdpersonppsid { get; set; } = null!; + public string? ucdpersonuuid { get; set; } = null!; + public string? ucdpublishitemflag { get; set; } = null!; + public string? ucdstudentsid { get; set; } = null!; + public string? uid { get; set; } = null!; + public string? uidnumber { get; set; } = null!; + public string? useraccountcontrol { get; set; } = null!; + public string? username { get; set; } = null!; + public string? userprincipalname { get; set; } = null!; + public string? usnchanged { get; set; } = null!; + public string? usncreated { get; set; } = null!; + public string? whenchanged { get; set; } = null!; + public string? whencreated { get; set; } = null!; + public string originalObject { get; set; } = null!; + + */ + + public LdapUserContact() { } + + /* + public LdapUserContact(SearchResult? ldapSearchResult) + { + if (ldapSearchResult != null) + { + originalObject = System.Text.Json.JsonSerializer.Serialize(ldapSearchResult.Properties); + foreach (System.Collections.DictionaryEntry prop in ldapSearchResult.Properties) + { + if (prop.Value != null) + { + var v = ((ResultPropertyValueCollection)prop.Value); + switch (prop.Key.ToString()) + { + case "accountexpires": accountexpires = v[0].ToString(); break; + case "adspath": adspath = v[0].ToString(); break; + case "badpasswordtime": badpasswordtime = v[0].ToString(); break; + case "badpwdcount": badpwdcount = v[0].ToString(); break; + case "cn": cn = v[0].ToString(); break; + case "codepage": codepage = v[0].ToString(); break; + case "company": company = v[0].ToString(); break; + case "countrycode": countrycode = v[0].ToString(); break; + case "deliverandredirect": deliverandredirect = v[0].ToString(); break; + case "department": department = v[0].ToString(); break; + case "departmentnumber": departmentnumber = v[0].ToString(); break; + case "Description": Description = v[0].ToString(); break; + case "description": Description = v[0].ToString(); break; + case "displayname": displayname = v[0].ToString(); break; + case "distinguishedname": distinguishedname = v[0].ToString(); break; + case "dscorepropagationdata": dscorepropagationdata = v[0].ToString(); break; + case "edupersonaffiliation": edupersonaffiliation = v[0].ToString(); break; + case "edupersonprincipalname": edupersonprincipalname = v[0].ToString(); break; + case "employeenumber": employeenumber = v[0].ToString(); break; + case "extensionattribute10": extensionattribute10 = v[0].ToString(); break; + case "extensionattribute11": extensionattribute11 = v[0].ToString(); break; + case "extensionattribute12": extensionattribute12 = v[0].ToString(); break; + case "extensionattribute13": extensionattribute13 = v[0].ToString(); break; + case "extensionattribute14": extensionattribute14 = v[0].ToString(); break; + case "extensionattribute15": extensionattribute15 = v[0].ToString(); break; + case "extensionattribute5": extensionattribute5 = v[0].ToString(); break; + case "extensionattribute6": extensionattribute6 = v[0].ToString(); break; + case "extensionattribute7": extensionattribute7 = v[0].ToString(); break; + case "extensionattribute8": extensionattribute8 = v[0].ToString(); break; + case "extensionattribute9": extensionattribute9 = v[0].ToString(); break; + case "gidnumber": gidnumber = v[0].ToString(); break; + case "givenname": givenname = v[0].ToString(); break; + case "instancetype": instancetype = v[0].ToString(); break; + case "internetencoding": internetencoding = v[0].ToString(); break; + case "l": l = v[0].ToString(); break; + case "lastlogoff": lastlogoff = v[0].ToString(); break; + case "lastlogon": lastlogon = v[0].ToString(); break; + case "lastlogontimestamp": lastlogontimestamp = v[0].ToString(); break; + case "legacyexchangedn": legacyexchangedn = v[0].ToString(); break; + case "lockouttime": lockouttime = v[0].ToString(); break; + case "logoncount": logoncount = v[0].ToString(); break; + case "mail": mail = v[0].ToString(); break; + case "mailnickname": mailnickname = v[0].ToString(); break; + case "mapirecipient": mapirecipient = v[0].ToString(); break; + case "mobile": mobile = v[0].ToString(); break; + case "msexcharchiveguid": msexcharchiveguid = v[0].ToString(); break; + case "msexcharchivename": msexcharchivename = v[0].ToString(); break; + case "msexcharchivestatus": msexcharchivestatus = v[0].ToString(); break; + case "msexchblockedsendershash": msexchblockedsendershash = v[0].ToString(); break; + case "msexchcomanagedobjectsbl": msexchcomanagedobjectsbl = v[0].ToString(); break; + case "msexchextensionattribute16": msexchextensionattribute16 = v[0].ToString(); break; + case "msexchextensionattribute17": msexchextensionattribute17 = v[0].ToString(); break; + case "msexchmailboxguid": msexchmailboxguid = v[0].ToString(); break; + case "msexchpoliciesexcluded": msexchpoliciesexcluded = v[0].ToString(); break; + case "msexchrecipientdisplaytype": msexchrecipientdisplaytype = v[0].ToString(); break; + case "msexchrecipienttypedetails": msexchrecipienttypedetails = v[0].ToString(); break; + case "msexchremoterecipienttype": msexchremoterecipienttype = v[0].ToString(); break; + case "msexchsafesendershash": msexchsafesendershash = v[0].ToString(); break; + case "msexchtextmessagingstate": msexchtextmessagingstate = v[0].ToString(); break; + case "msexchumdtmfmap": msexchumdtmfmap = v[0].ToString(); break; + case "msexchuseraccountcontrol": msexchuseraccountcontrol = v[0].ToString(); break; + case "msexchversion": msexchversion = v[0].ToString(); break; + case "msexchwhenmailboxcreated": msexchwhenmailboxcreated = v[0].ToString(); break; + case "name": name = v[0].ToString(); break; + case "objectcategory": objectcategory = v[0].ToString(); break; + case "objectclass": objectclass = v[0].ToString(); break; + case "objectguid": objectguid = v[0].ToString(); break; + case "objectsid": objectsid = v[0].ToString(); break; + case "ou": ou = v[0].ToString(); break; + case "pager": pager = v[0].ToString(); break; + case "phone": phone = v[0].ToString(); break; + case "physicaldeliveryofficename": physicaldeliveryofficename = v[0].ToString(); break; + case "postaladdress": postaladdress = v[0].ToString(); break; + case "postalcode": postalcode = v[0].ToString(); break; + case "primarygroupid": primarygroupid = v[0].ToString(); break; + case "proxyaddresses": proxyaddresses = v[0].ToString(); break; + case "pwdlastset": pwdlastset = v[0].ToString(); break; + case "SamAccountName": SamAccountName = v[0].ToString(); break; + case "samaccountname": SamAccountName = v[0].ToString(); break; + case "samaccounttype": samaccounttype = v[0].ToString(); break; + case "showinaddressbook": showinaddressbook = v[0].ToString(); break; + case "sn": surName = v[0].ToString(); break; + case "st": st = v[0].ToString(); break; + case "street": street = v[0].ToString(); break; + case "streetaddress": streetaddress = v[0].ToString(); break; + case "targetaddress": targetaddress = v[0].ToString(); break; + case "telephonenumber": telephonenumber = v[0].ToString(); break; + case "textencodedoraddress": textencodedoraddress = v[0].ToString(); break; + case "title": title = v[0].ToString(); break; + case "ucdappointmentdepartmentcode": ucdappointmentdepartmentcode = v[0].ToString(); break; + case "ucdappointmenttitlecode": ucdappointmenttitlecode = v[0].ToString(); break; + case "ucdpersonaffiliation": ucdpersonaffiliation = v[0].ToString(); break; + case "ucdpersoniamid": ucdpersoniamid = v[0].ToString(); break; + case "ucdpersonnetid": ucdpersonnetid = v[0].ToString(); break; + case "ucdpersonpidm": ucdpersonpidm = v[0].ToString(); break; + case "ucdpersonppsid": ucdpersonppsid = v[0].ToString(); break; + case "ucdpersonuuid": ucdpersonuuid = v[0].ToString(); break; + case "ucdpublishitemflag": ucdpublishitemflag = v[0].ToString(); break; + case "ucdstudentsid": ucdstudentsid = v[0].ToString(); break; + case "uid": uid = v[0].ToString(); break; + case "uidnumber": uidnumber = v[0].ToString(); break; + case "useraccountcontrol": useraccountcontrol = v[0].ToString(); break; + case "username": username = v[0].ToString(); break; + case "userprincipalname": userprincipalname = v[0].ToString(); break; + case "usnchanged": usnchanged = v[0].ToString(); break; + case "usncreated": usncreated = v[0].ToString(); break; + case "whenchanged": whenchanged = v[0].ToString(); break; + case "whencreated": whencreated = v[0].ToString(); break; + case "memberof": + List groups = new(); + foreach (string group in v) + { + groups.Add(group); + } + memberof = string.Join(",", groups); break; + default: break; + } + + } + } + } + } + */ + + public LdapUserContact(SearchResultEntry entry) + { + foreach (DirectoryAttribute attr in entry.Attributes.Values) + { + var v = attr[0]; + switch (attr.Name) + { + case "uid": Uid = v.ToString(); break; + case "sAMAccountName": SamAccountName = v.ToString(); break; + case "sn": Sn = v.ToString(); break; + case "ou": Ou = v.ToString(); break; + + case "givenName": GivenName = v.ToString(); break; + case "middleName": MiddleName = v.ToString(); break; + case "displayName": DisplayName = v.ToString(); break; + case "eduPersonNickname": EduPersonNickname = v.ToString(); break; + + case "title": Title = v.ToString(); break; + case "postalAddress": PostalAddress = v.ToString(); break; + case "telephoneNumber": TelephoneNumber = v.ToString(); break; + case "mobile": Mobile = v.ToString(); break; + case "mail": Mail = v.ToString(); break; + + case "ucdStudentLevel": UcdStudentLevel = v.ToString(); break; + case "ucdStudentSID": UcdStudentSid = v.ToString(); break; + case "ucdPersonPIDM": UcdPersonPidm = v.ToString(); break; + case "employeeNumber": EmployeeNumber = v.ToString(); break; + case "ucdPersonUUID": UcdPersonUuid = v.ToString(); break; + case "ucdPersonIAMID": UcdPersonIamId = v.ToString(); break; + case "ucdPersonAffiliation": UcdPersonAffiliation = v.ToString(); break; + + default: break; + } + + } + } + } +} diff --git a/web/Areas/Directory/Models/VMACSItem.cs b/web/Areas/Directory/Models/VMACSItem.cs new file mode 100644 index 0000000..30f5649 --- /dev/null +++ b/web/Areas/Directory/Models/VMACSItem.cs @@ -0,0 +1,51 @@ +using System.Text; +using System.Xml.Serialization; +using Viper.Areas.RAPS.Models; +using Viper.Models.AAUD; + +namespace Viper.Areas.Directory.Models +{ + [XmlRoot("item")] + public class VMACSItem + { + [XmlAttribute("dbfile")] + public int dbfile { get; set; } + + [XmlElement("Name")] + public string[]? Name { get; set; } + [XmlElement("UserID")] + public string[]? VMACSID { get; set; } + [XmlElement("Unit")] + public string[]? Unit { get; set; } + [XmlElement("Home")] + public string[]? Home { get; set; } + [XmlElement("Nextel")] + public string[]? Nextel { get; set; } + [XmlElement("LDPager")] + public string[]? LDPager { get; set; } + [XmlElement("Status")] + public string[]? Status { get; set; } + [XmlElement("Campus_LoginID")] + public string[]? Campus_LoginID { get; set; } + [XmlElement("Email_Forward")] + public string[]? Email_Forward { get; set; } + [XmlElement("LastEdit")] + public string[]? LastEdit { get; set; } + } + + [XmlRoot("query")] + public class VMACSQuery + { + [XmlElement("item")] + public VMACSItem? item { get; set; } + + [XmlElement("dbfile")] + public string[]? dbfile { get; set; } + + [XmlElement("dbfileNm")] + public string[]? dbfileNm { get; set; } + + [XmlElement("uri")] + public string[]? uri { get; set; } + } +} \ No newline at end of file diff --git a/web/Areas/Directory/Services/VMACSService.cs b/web/Areas/Directory/Services/VMACSService.cs new file mode 100644 index 0000000..9cd2a8f --- /dev/null +++ b/web/Areas/Directory/Services/VMACSService.cs @@ -0,0 +1,111 @@ +using Microsoft.AspNetCore.Mvc; +using System.DirectoryServices.AccountManagement; +using System.DirectoryServices; +using Viper.Areas.RAPS.Models; +using Viper.Areas.Directory.Models; +using System.Net.Http; +using System.Text; +using System.Xml.Serialization; +using Microsoft.CodeAnalysis.Elfie.Model.Strings; + +namespace Viper.Areas.Directory.Services +{ + public class VMACSService + { + //private const string _ldapUsername = "uid=vetmed,ou=Special Users,dc=ucdavis,dc=edu"; + private static HttpClient sharedClient = new() + { + BaseAddress = new Uri("https://vmacs-vmth.vetmed.ucdavis.edu"), + }; + + public VMACSService() { } + + /// + /// + /// + /// + public static async Task Search (String? loginID) + { + string request = $"/trust/query.xml?dbfile=3&index=CampusLoginId&find={loginID}&format=CHRIS4&AUTH=06232005".ToString(); + using HttpResponseMessage response = await sharedClient.GetAsync(request); + if (response.IsSuccessStatusCode == false){ + return null; + } + var s = await response.Content.ReadAsStringAsync(); + var buffer = Encoding.UTF8.GetBytes(s); + using (var stream = new MemoryStream(buffer)) + { + var serializer = new XmlSerializer(typeof(VMACSQuery)); + //return Encoding.ASCII.GetString(stream.ToArray()); + var vmacs_api = (VMACSQuery?)serializer.Deserialize(stream); + if (vmacs_api != null && vmacs_api.item != null && vmacs_api.item.Nextel != null) + { + return vmacs_api; + } + } + return null; + } + + + /* + * var result = ""; + var contacts = {LDPager="", Nextel="", LastEdit=""}; + cfhttp(url="https://vmacs-vmth.vetmed.ucdavis.edu/trust/query.xml?dbfile=3&index=CampusLoginId&find=#loginID#&format=CHRIS4&AUTH=06232005", + method="get", timeout="2", result="result") {} + + //the number of try/catch block here could be reduced by using more xml functions to check if something exists? + try { + var data = xmlSearch(xmlParse(result.FileContent),"/query/item"); + var exp = ""; + var lastEdit = ""; + //most users only have one, but in some cases, multiple accounts exist. + //grab the latest edited, non-expired record. + for(var d in data) { + if(d?.Campus_LoginID?.XmlText == loginID) { //mvt (Megan Rott) matches mvthomps (not Megan Rott) + //try to get dates - if this fails, assume the record is active and was lastedited today + try { + exp = getDateFromVmacsString(d.Deactive.XmlText); + lastEdit = getDateFromVmacsString(d.LastEdit.XmlText); + } + catch(Any e) { + exp = dateAdd("yyyy", 1, now()); + lastEdit = now(); + } + + if(exp > now() && (!isValid("date", contacts.LastEdit) || lastEdit > contacts.LastEdit)) { + contacts.lastEdit = lastEdit; + + //individual tries in case these fields don't exist + try { + contacts.LDPager = d.LDPager.XmlText; + if(contacts.LDPager != "") { + contacts.LDPager = "1-530-" & contacts.LDPager; + } + } + catch(Any e) {} + + try { + contacts.Nextel = d.Nextel.XmlText; + } + catch(Any e) {} + } + } + } + } + catch(Any e) {} + return contacts; + + */ + + /* + /// + /// + /// Partial name of group to search for + /// List of groups + public List GetGroups(string? name = null) + { + } + */ + + } +} diff --git a/web/Areas/Directory/Views/Card.cshtml b/web/Areas/Directory/Views/Card.cshtml new file mode 100644 index 0000000..99fa220 --- /dev/null +++ b/web/Areas/Directory/Views/Card.cshtml @@ -0,0 +1,171 @@ +@using Viper.Classes.SQLContext; +@model Viper.Models.AAUD.AaudUser; +@{ + RAPSContext? rapsContext = (RAPSContext?)Context.RequestServices.GetService(typeof(RAPSContext)); + IUserHelper UserHelper = new UserHelper(); + ViewData["Title"] = "Directory"; +} +

Directory

+ + + + + + + + + + +
+ + + + + + + + + + + + + + +

+ {{user.name}} +

+

+ {{user.title}} +

+
+
+
+ +
+ {{user.userName}} +
+
+ {{user.mailId}}@@ucdavis.edu [{{user.emailHost}}] +
+
SVM
+
+ + +
{{ user.postalAddress }}
+
{{ user.phone }}
+
{{ user.mobile }}
+
{{ user.nextel }}
+
+ + +
+ BannerID: + @if (UserHelper.HasPermission(rapsContext, UserHelper.GetCurrentUser(), "SVMSecure.SIS.AllStudents")) + { + @: {{ user.spridenId }} + } + else + { + @: {{ user.spridenId }} + } +
+
PIDM: {{ user.pidm }}
+
EmployeeID: {{ user.employeeId}}
+
IAMID: {{ user.iamId }}
+
MothraID: {{ user.mothraId }}
+
MIVID: {{ user.mivId }}
+
+ + + + + + @if (UserHelper.HasPermission(rapsContext, UserHelper.GetCurrentUser(), "SVMSecure.DirectoryUCPathInfo")) + { + @: + + } + @if (UserHelper.HasPermission(rapsContext, UserHelper.GetCurrentUser(), "SVMSecure.CATS.ServiceDesk")) + { + @: + Alt. Photo + } + + + +
+                    {{ user.originalObject }}
+                
+
+ +
+
+ +@section Scripts { + +} \ No newline at end of file diff --git a/web/Areas/Directory/Views/Table.cshtml b/web/Areas/Directory/Views/Table.cshtml new file mode 100644 index 0000000..fa68030 --- /dev/null +++ b/web/Areas/Directory/Views/Table.cshtml @@ -0,0 +1,179 @@ +@using Viper.Classes.SQLContext; +@model Viper.Models.AAUD.AaudUser; +@{ + RAPSContext? rapsContext = (RAPSContext?)Context.RequestServices.GetService(typeof(RAPSContext)); + IUserHelper UserHelper = new UserHelper(); + ViewData["Title"] = "Directory"; +} +

Directory

+ + + + + + + + + + + + + + + + + + + +@section Scripts { + + +} \ No newline at end of file diff --git a/web/Areas/Directory/Views/UserInfo.cshtml b/web/Areas/Directory/Views/UserInfo.cshtml new file mode 100644 index 0000000..87f162d --- /dev/null +++ b/web/Areas/Directory/Views/UserInfo.cshtml @@ -0,0 +1,5 @@ +@{ + ViewData["Title"] = "User Info Page"; +} +
+
diff --git a/web/Areas/RAPS/Controllers/AdGroupsController.cs b/web/Areas/RAPS/Controllers/AdGroupsController.cs index ded929d..7357e0e 100644 --- a/web/Areas/RAPS/Controllers/AdGroupsController.cs +++ b/web/Areas/RAPS/Controllers/AdGroupsController.cs @@ -2,14 +2,13 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Data; -using System.Runtime.Loader; using System.Runtime.Versioning; -using System.Text.RegularExpressions; using Viper.Areas.RAPS.Models; using Viper.Areas.RAPS.Models.Uinform; using Viper.Areas.RAPS.Services; using Viper.Classes; using Viper.Classes.SQLContext; +using Viper.Classes.Utilities; using Viper.Models.RAPS; using Web.Authorization; @@ -64,7 +63,7 @@ public AdGroupsController(RAPSContext context) [HttpGet("OU")] public ActionResult GetLdapGroups() { - List ouGroups = new LdapService().GetGroups(); + List ouGroups = ActiveDirectoryService.GetGroups(); return Ok(ouGroups); } diff --git a/web/Areas/RAPS/Controllers/RAPSController.cs b/web/Areas/RAPS/Controllers/RAPSController.cs index c572b42..50930c8 100644 --- a/web/Areas/RAPS/Controllers/RAPSController.cs +++ b/web/Areas/RAPS/Controllers/RAPSController.cs @@ -9,6 +9,7 @@ using System.Runtime.Versioning; using Microsoft.AspNetCore.Mvc.Filters; using System.Data; +using Viper.Classes.Utilities; namespace Viper.Areas.RAPS.Controllers { @@ -85,19 +86,6 @@ public async Task Index(string? instance) "VIPERFORMS" => await Task.Run(() => Redirect(string.Format("~/raps/ViperForms/rolelist"))), _ => await Task.Run(() => View("~/Views/Home/403.cshtml")), }; - - - //var data = await _RAPSContext.TblRoles.ToListAsync(); - //var skipList = new List { "Description" }; - //var altColumnNames = new List> { new Tuple("ViewName","Viewer") }; - - //ViewData["Columns"] = VueTableDefaultViewComponent.GetDefaultColumnNames(data, skipList, altColumnNames); - //ViewData["Rows"] = VueTableDefaultViewComponent.GetDefaultRows(data, skipList); - //ViewData["VisibleColumns"] = VueTableDefaultViewComponent.GetDefaultVisibleColumns(data, skipList); - - //return _RAPSContext.TblRoles != null ? - // View("~/Areas/RAPS/Views/Index.cshtml", data) : - // Problem("Entity set 'RAPSContext.TblRoles' is null.");} } public async Task Nav(int? roleId, int? permissionId, string? memberId, string instance = "VIPER", string page = "") diff --git a/web/Areas/RAPS/Models/LdapGroup.cs b/web/Areas/RAPS/Models/LdapGroup.cs index 9300dc0..c7788f9 100644 --- a/web/Areas/RAPS/Models/LdapGroup.cs +++ b/web/Areas/RAPS/Models/LdapGroup.cs @@ -1,4 +1,5 @@ using System.DirectoryServices; +using System.DirectoryServices.Protocols; using System.Runtime.Versioning; namespace Viper.Areas.RAPS.Models @@ -20,33 +21,29 @@ public class LdapGroup public string ExtensionAttribute3 { get; set; } = null!; public LdapGroup() { } - public LdapGroup(SearchResult? ldapSearchResult) + + public LdapGroup(SearchResultEntry entry) { - if(ldapSearchResult != null) { - foreach (System.Collections.DictionaryEntry prop in ldapSearchResult.Properties) + foreach (DirectoryAttribute attr in entry.Attributes.Values) + { + var v = attr[0]; + switch (attr.Name) { - if(prop.Value != null) - { - var v = ((ResultPropertyValueCollection)prop.Value)[0]; - switch (prop.Key.ToString()) - { - case "samaccountname": SamAccountName = v.ToString(); break; - case "objectguid": ObjectGuid = (byte[])v; break; - case "cn": Cn = v.ToString(); break; - case "canonicalname": CanonicalName = v.ToString(); break; - case "dn": Dn = v.ToString(); break; - case "distinguishedname": DistinguishedName = v.ToString(); break; - case "displayname": DisplayName = v.ToString(); break; - case "grouptype": GroupType = v.ToString(); break; - case "description": Description = v.ToString(); break; - case "extensionattribute1": ExtensionAttribute1 = v.ToString(); break; - case "extensionattribute2": ExtensionAttribute2 = v.ToString(); break; - case "extensionattribute3": ExtensionAttribute3 = v.ToString(); break; - default: break; - } - - } + case "sAMAccountName": SamAccountName = v.ToString(); break; + case "objectGUID": ObjectGuid = (byte[])v; break; + case "cn": Cn = v.ToString(); break; + case "canonicalName": CanonicalName = v.ToString(); break; + case "dn": Dn = v.ToString(); break; + case "distinguishedName": DistinguishedName = v.ToString(); break; + case "displayName": DisplayName = v.ToString(); break; + case "groupType": GroupType = v.ToString(); break; + case "description": Description = v.ToString(); break; + case "extensionattribute1": ExtensionAttribute1 = v.ToString(); break; + case "extensionattribute2": ExtensionAttribute2 = v.ToString(); break; + case "extensionattribute3": ExtensionAttribute3 = v.ToString(); break; + default: break; } + } } } diff --git a/web/Areas/RAPS/Models/LdapUser.cs b/web/Areas/RAPS/Models/LdapUser.cs index efd4511..34b7577 100644 --- a/web/Areas/RAPS/Models/LdapUser.cs +++ b/web/Areas/RAPS/Models/LdapUser.cs @@ -1,5 +1,4 @@ -using System.DirectoryServices; -using System.Linq.Dynamic.Core; +using System.DirectoryServices.Protocols; using System.Runtime.Versioning; namespace Viper.Areas.RAPS.Models @@ -19,46 +18,44 @@ public class LdapUser public string Description { get; set; } = ""; public string UserPrincipalName { get; set; } = null!; public string Title { get; set; } = null!; - public string Department { get; set; } = null!; + public string Department { get; set; } = null!; public string UidNumber { get; set; } = null!; public string MemberOf { get; set; } = null!; public LdapUser() { } - public LdapUser(SearchResult? ldapSearchResult) + public LdapUser(SearchResultEntry? ldapSearchResult) { if (ldapSearchResult != null) { - foreach (System.Collections.DictionaryEntry prop in ldapSearchResult.Properties) + foreach (DirectoryAttribute attr in ldapSearchResult.Attributes.Values) { - if (prop.Value != null) + var v = attr[0]; + switch (attr.Name) { - var v = ((ResultPropertyValueCollection)prop.Value); - switch (prop.Key.ToString()) - { - case "samaccountname": SamAccountName = v[0].ToString(); break; - case "objectguid": ObjectGuid = (byte[])v[0]; break; - case "cn": Cn = v[0].ToString(); break; - case "canonicalname": CanonicalName = v[0].ToString(); break; - case "dn": Dn = v[0].ToString(); break; - case "distinguishedname": DistinguishedName = v[0].ToString(); break; - case "givenname": GivenName = v[0].ToString(); break; - case "sn": Sn = v[0].ToString(); break; - case "displayname": DisplayName = v[0].ToString(); break; - case "description": Description = v[0].ToString(); break; - case "userprincipalname": UserPrincipalName = v[0].ToString(); break; - case "title": Title = v[0].ToString(); break; - case "department": Department = v[0].ToString(); break; - case "uidNumber": UidNumber = v[0].ToString(); break; - case "memberof": - List groups = new(); - foreach (string group in v) - { - groups.Add(group); - } - MemberOf = string.Join(",", groups); break; - default: break; - } - + case "sAMAaccountName": SamAccountName = v.ToString(); break; + case "objectGUID": ObjectGuid = (byte[])v; break; + case "cn": Cn = v.ToString(); break; + case "canonicalName": CanonicalName = v.ToString(); break; + case "dn": Dn = v.ToString(); break; + case "distinguishedName": DistinguishedName = v.ToString(); break; + case "givenName": GivenName = v.ToString(); break; + case "sn": Sn = v.ToString(); break; + case "displayName": DisplayName = v.ToString(); break; + case "description": Description = v.ToString(); break; + case "userPrincipalName": UserPrincipalName = v.ToString(); break; + case "title": Title = v.ToString(); break; + case "department": Department = v.ToString(); break; + case "uidNumber": UidNumber = v.ToString(); break; + + case "memberOf": + List groups = new(); + foreach (string group in attr.GetValues(typeof(string))) + { + groups.Add(group); + } + MemberOf = string.Join(",", groups); + break; + default: break; } } } diff --git a/web/Areas/RAPS/Services/OuGroupService.cs b/web/Areas/RAPS/Services/OuGroupService.cs index 5ebf40e..c95fcc9 100644 --- a/web/Areas/RAPS/Services/OuGroupService.cs +++ b/web/Areas/RAPS/Services/OuGroupService.cs @@ -1,11 +1,12 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; -using NuGet.Protocol.Plugins; +using NLog; using System.Linq.Dynamic.Core; using System.Runtime.Versioning; using Viper.Areas.RAPS.Models; using Viper.Areas.RAPS.Models.Uinform; using Viper.Classes.SQLContext; +using Viper.Classes.Utilities; using Viper.Models.RAPS; using static Viper.Areas.RAPS.Services.RAPSAuditService; @@ -16,7 +17,6 @@ public class OuGroupService { private readonly RAPSContext _context; private readonly RAPSAuditService _auditService; - private readonly LdapService _ldapService; private readonly UinformService _uInformService; private const string _exceptionRolePrefix = "RAPS.Groups."; @@ -28,7 +28,6 @@ public OuGroupService(RAPSContext context) _context = context; _auditService = new RAPSAuditService(_context); _uInformService = new(); - _ldapService = new(); } /// @@ -44,7 +43,17 @@ public async Task> GetAllGroups(string? search) .ThenInclude(gr => gr.Role) .ThenInclude(r => r.TblRoleMembers) .ToListAsync(); - List ldapGroups = _ldapService.GetGroups(); + List ldapGroups = new(); + try + { + ActiveDirectoryService.GetGroups(); + } + catch (Exception ex) + { + Logger logger = LogManager.GetCurrentClassLogger(); + logger.Error(ex); + } + List managedGroups = await _uInformService.GetManagedGroups(); List groups = new(); @@ -256,7 +265,7 @@ private async Task CompareToGroup(string groupName, List members) //For OU groups, use LdapService to get members if (IsOuGroup(groupName)) { - List usersInGroup = _ldapService.GetGroupMembership(groupName); + List usersInGroup = ActiveDirectoryService.GetGroupMembership(groupName); foreach (LdapUser user in usersInGroup) { //Record this user is in the group @@ -352,7 +361,7 @@ private void UpdateOuGroupMember(string groupName, string loginId, bool add) } if(dn == null) { - dn = _ldapService.GetUser(loginId)?.DistinguishedName; + dn = ActiveDirectoryService.GetUser(loginId)?.DistinguishedName; HttpHelper.Cache?.Set("ou.ad3-distinguishedname-" + loginId, dn, new TimeSpan(0, 20, 0)); } @@ -360,11 +369,11 @@ private void UpdateOuGroupMember(string groupName, string loginId, bool add) { if (add) { - _ldapService.AddUserToGroup(dn, groupName); + ActiveDirectoryService.AddUserToGroup(dn, groupName); } else { - _ldapService.RemoveUserFromGroup(dn, groupName); + ActiveDirectoryService.RemoveUserFromGroup(dn, groupName); } } diff --git a/web/Areas/RAPS/Services/UinformService.cs b/web/Areas/RAPS/Services/UinformService.cs index 6e4e602..fa78a1c 100644 --- a/web/Areas/RAPS/Services/UinformService.cs +++ b/web/Areas/RAPS/Services/UinformService.cs @@ -1,12 +1,8 @@ using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using NuGet.Protocol; -using System; using System.Security.Cryptography; using System.Text; -using System.Text.Json; using Viper.Areas.RAPS.Models.Uinform; -using Viper.Classes.Utilities; namespace Viper.Areas.RAPS.Services { diff --git a/web/Areas/RAPS/Views/Permissions/ListAdmin.cshtml b/web/Areas/RAPS/Views/Permissions/ListAdmin.cshtml index b9bf4c3..867d740 100644 --- a/web/Areas/RAPS/Views/Permissions/ListAdmin.cshtml +++ b/web/Areas/RAPS/Views/Permissions/ListAdmin.cshtml @@ -79,7 +79,24 @@ } }, mounted() { + var f = getItemFromStorage("RAPS_permission_filter") + if (f) { + this.permissionTable.filter = f + } + var p = getItemFromStorage("RAPS_permission_pagination") + if (p) { + this.permissionTable.pagination = p + } this.permissionTable.load(this) + }, + watch: { + permissionTable: { + handler(v) { + putItemInStorage("RAPS_permission_filter", v.filter) + putItemInStorage("RAPS_permission_pagination", v.pagination) + }, + deep: true + } } }) diff --git a/web/Areas/RAPS/Views/Permissions/Members.cshtml b/web/Areas/RAPS/Views/Permissions/Members.cshtml index 0177488..ccc4805 100644 --- a/web/Areas/RAPS/Views/Permissions/Members.cshtml +++ b/web/Areas/RAPS/Views/Permissions/Members.cshtml @@ -23,7 +23,7 @@
- diff --git a/web/Areas/RAPS/Views/Roles/Members.cshtml b/web/Areas/RAPS/Views/Roles/Members.cshtml index 4ccbd64..93bec09 100644 --- a/web/Areas/RAPS/Views/Roles/Members.cshtml +++ b/web/Areas/RAPS/Views/Roles/Members.cshtml @@ -24,7 +24,7 @@
- GetErrorList(ExceptionContext context) diff --git a/web/Classes/DuoAuthenticationRequirement.cs b/web/Classes/DuoAuthenticationRequirement.cs index 661fd9c..60836ce 100644 --- a/web/Classes/DuoAuthenticationRequirement.cs +++ b/web/Classes/DuoAuthenticationRequirement.cs @@ -22,6 +22,11 @@ protected override Task HandleRequirementAsync(AuthorizationHandlerContext conte { if (httpContext is not null) { + var env = httpContext.RequestServices.GetRequiredService(); + if (env != null && env.EnvironmentName == "Development") + { + context.Succeed(requirement); + } httpContext.Items["ErrorMessage"] = "DUO two-factor authentication is required"; } else diff --git a/web/Areas/RAPS/Services/LdapService.cs b/web/Classes/Utilities/ActiveDirectoryService.cs similarity index 57% rename from web/Areas/RAPS/Services/LdapService.cs rename to web/Classes/Utilities/ActiveDirectoryService.cs index 2f2bf09..fddeef6 100644 --- a/web/Areas/RAPS/Services/LdapService.cs +++ b/web/Classes/Utilities/ActiveDirectoryService.cs @@ -1,21 +1,27 @@ -using System.DirectoryServices; +using System.DirectoryServices.AccountManagement; +using System.DirectoryServices.Protocols; using System.Runtime.Versioning; -using System.DirectoryServices.AccountManagement; using Viper.Areas.RAPS.Models; -namespace Viper.Areas.RAPS.Services +namespace Viper.Classes.Utilities { [SupportedOSPlatform("windows")] - public class LdapService + public class ActiveDirectoryService { - private const string _username = "ou\\svc-accounts"; + //username for campus active directory servers (ou.ad3 and ad3) + //private const string _username = "CN=svc-accounts,OU=Service Accounts,OU=SVM-OU-LocalUsers,OU=SVM,OU=DEPARTMENTS,DC=ou,DC=ad3,DC=ucdavis,DC=edu"; + private const string _username = "svc-accounts"; //Start OUs for ou.ad3 (old-style groups and service accounts) and ad3 (users and api managed groups) - private const string _ouStart = "OU=SVM,OU=Departments,DC=ou,DC=ad3,DC=ucdavis,DC=edu"; + private const string _ouStart = "OU=SVM,OU=DEPARTMENTS,DC=ou,DC=ad3,DC=ucdavis,DC=edu"; private const string _ad3Users = "OU=ucdUsers,DC=ad3,DC=ucdavis,DC=edu"; + //server and start for ldap.ucdavis.edu + private const string _ouServer = "ou.ad3.ucdavis.edu"; + private const string _ad3Server = "ad3.ucdavis.edu"; + private const int port = 636; //ldap attributes/properties to return for each object type - private readonly string[] _groupProperties = + private static readonly string[] _groupProperties = { "sAMAccountName", "objectGuid", @@ -30,7 +36,7 @@ public class LdapService "extensionAttribute2", "extensionAttribute3" }; - private readonly string[] _personProperties = + private static readonly string[] _personProperties = { "sAMAccountName", "objectGuid", @@ -50,31 +56,55 @@ public class LdapService "department", "company", "uidNumber", - "memberOf" + "memberOf", + "telephoneNumber", + "mobile", + "uid", + "employeeNumber", + "labeledUri", + "middlename", + "ou", + "postalAddress", + "ucdPersonAffiliation", + "ucdPersonIAMID", + "ucdPersonPIDM", + "ucdPersonUUID", + "ucdStudentLevel", + "ucdStudentSID" }; - - public LdapService() { } - + + private enum Server { + AD3, + OU + } + + private enum ObjectType + { + Person, + Group + } + /// /// Get groups, optionally filtering with a wildcard match to name /// /// Partial name of group to search for /// List of groups - public List GetGroups(string? name = null) + public static List GetGroups(string? name = null) { string filter = "(objectClass=group)"; if (name != null) { filter = string.Format("(&{0}(cn=*{1}*))", filter, name); }; - SearchResultCollection results = new DirectorySearcher(GetRoot(true), filter, _groupProperties, SearchScope.Subtree) - { PageSize = 1000 } - .FindAll(); + + var searchResults = SearchActiveDirectory(filter, Server.OU, ObjectType.Group); List groups = new(); - foreach(SearchResult result in results) + + foreach (SearchResultEntry e in searchResults.Entries) { - groups.Add(new LdapGroup(result)); + groups.Add(new LdapGroup(e)); } + groups.Sort((g1, g2) => g1.DistinguishedName.CompareTo(g2.DistinguishedName)); return groups; } @@ -84,13 +114,17 @@ public List GetGroups(string? name = null) ///
/// Distinguished name of group /// The group, if found - public LdapGroup? GetGroup(string dn) + public static LdapGroup? GetGroup(string dn) { string filter = string.Format("(&(objectClass=group)(distinguishedName={0}))", dn); - return new LdapGroup( - new DirectorySearcher(GetRoot(true), filter, _groupProperties, SearchScope.Subtree) - .FindOne() - ); + var searchResults = SearchActiveDirectory(filter, Server.OU, ObjectType.Group); + LdapGroup? group = null; + if (searchResults.Entries.Count == 1) + { + group = new LdapGroup(searchResults.Entries[0]); + } + + return group; } /// @@ -101,34 +135,35 @@ public List GetGroups(string? name = null) /// canonical name to search for /// samAccountName to search for /// List of users - public List GetUsers(bool fromOu = false, string? name = null, string? cn = null, string? samAccountName = null) + public static List GetUsers(bool fromOu = false, string? name = null, string? cn = null, string? samAccountName = null) { string filter = "(objectClass=user)"; string additionalFilters = ""; - if(name != null) + if (name != null) { additionalFilters += string.Format("(displayName=*{0}*)", name); } - if(cn != null) + if (cn != null) { - additionalFilters += string.Format("(cn=*{0}*", cn); + additionalFilters += string.Format("(cn=*{0}*)", cn); } - if(samAccountName != null) + if (samAccountName != null) { - additionalFilters += string.Format("(samAccountName=*{0}*", samAccountName); + additionalFilters += string.Format("(samAccountName=*{0}*)", samAccountName); } - if(additionalFilters.Length > 0) + if (additionalFilters.Length > 0) { filter = string.Format("(&{0}{1})", filter, additionalFilters); } - SearchResultCollection results = new DirectorySearcher(GetRoot(fromOu), filter, _personProperties, SearchScope.Subtree) - { PageSize = 1000 } - .FindAll(); + + var searchResults = SearchActiveDirectory(filter, fromOu ? Server.OU : Server.AD3, ObjectType.Person); + List users = new(); - foreach(SearchResult result in results) + foreach (SearchResultEntry result in searchResults.Entries) { users.Add(new LdapUser(result)); } + return SortUsers(users); } @@ -138,13 +173,13 @@ public List GetUsers(bool fromOu = false, string? name = null, string? /// samAccountName of user /// If true, searches the SVM OU in ou.ad3.ucdavis.edu, otherwise, searches ucdUsers in ad3 /// - public LdapUser? GetUser(string samAccountName, bool fromOu = false) + public static LdapUser? GetUser(string samAccountName, bool fromOu = false) { - return new LdapUser( - new DirectorySearcher(GetRoot(fromOu), string.Format("(&(objectClass=user)(samAccountName={0}))", samAccountName), _personProperties, SearchScope.Subtree) - .FindOne() - ); - + var searchResults = SearchActiveDirectory( + string.Format("(&(objectClass=user)(samAccountName={0}))", samAccountName), + fromOu ? Server.OU : Server.AD3, + ObjectType.Person); + return searchResults.Entries.Count == 1 ? new LdapUser(searchResults.Entries[0]) : null; } /// @@ -152,23 +187,19 @@ public List GetUsers(bool fromOu = false, string? name = null, string? /// /// Distingushed name of the group /// List of members of the group - public List GetGroupMembership(string groupDn) + public static List GetGroupMembership(string groupDn) { List users = new(); string filter = string.Format("(&(objectClass=user)(memberOf={0}))", groupDn); - - //Need to get users from both AD3 and OU - SearchResultCollection ouResults = new DirectorySearcher(GetRoot(true), filter, _personProperties, SearchScope.Subtree) - .FindAll(); - foreach(SearchResult result in ouResults) + ////Need to get users from both AD3 and OU + var ouSearchResults = SearchActiveDirectory(filter, Server.OU, ObjectType.Person); + var ad3SearchResults = SearchActiveDirectory(filter, Server.AD3, ObjectType.Person); + + foreach (SearchResultEntry result in ouSearchResults.Entries) { users.Add(new LdapUser(result)); } - - SearchResultCollection ad3Results = new DirectorySearcher(GetRoot(false), filter, _personProperties, SearchScope.Subtree) - { PageSize = 1000 } - .FindAll(); - foreach (SearchResult result in ad3Results) + foreach (SearchResultEntry result in ad3SearchResults.Entries) { users.Add(new LdapUser(result)); } @@ -181,7 +212,7 @@ public List GetGroupMembership(string groupDn) /// /// The distinguished name of the user /// The distinguised name of the group - public void AddUserToGroup(string userDn, string groupDn) + public static void AddUserToGroup(string userDn, string groupDn) { string creds = HttpHelper.GetSetting("Credentials", "UCDavisLDAP") ?? ""; try @@ -190,7 +221,7 @@ public void AddUserToGroup(string userDn, string groupDn) using PrincipalContext ouPc = new(ContextType.Domain, "ou.ad3.ucdavis.edu", _username, creds); GroupPrincipal? group = GroupPrincipal.FindByIdentity(ouPc, IdentityType.DistinguishedName, groupDn); UserPrincipal? user = UserPrincipal.FindByIdentity(ad3Pc, IdentityType.DistinguishedName, userDn); - if(group != null && user != null) + if (group != null && user != null) { group.Members.Add(user); group.Save(); @@ -207,7 +238,7 @@ public void AddUserToGroup(string userDn, string groupDn) /// /// The distinguished name of the user /// The distinguised name of the group - public void RemoveUserFromGroup(string userDn, string groupDn) + public static void RemoveUserFromGroup(string userDn, string groupDn) { string creds = HttpHelper.GetSetting("Credentials", "UCDavisLDAP") ?? ""; try @@ -237,14 +268,35 @@ private static List SortUsers(List users) return users; } - //Get the root to start our ldap query - either the SVM OU in ou.ad3.ucdavis.edu for traditional security groups and SVM managed service accounts or - //the ucdUsers OU in ad3.ucdavis.edu for campus user accounts - private DirectoryEntry GetRoot(bool fromOu = false) + /// + /// Generic search function + /// + /// + /// + /// + /// + /// + private static SearchResponse SearchActiveDirectory(string searchFilter, Server server, ObjectType objectType) { - string start = fromOu ? _ouStart : _ad3Users; - string creds = HttpHelper.GetSetting("Credentials", "UCDavisLDAP") ?? ""; - return new DirectoryEntry(string.Format("LDAP://{0}", start), _username, creds, AuthenticationTypes.Secure); - } + var ldapIdentifier = server == Server.OU + ? new LdapDirectoryIdentifier(_ouServer, port) + : new LdapDirectoryIdentifier(_ad3Server, port); + var searchStart = server == Server.OU + ? _ouStart + : _ad3Users; + var props = objectType == ObjectType.Group + ? _groupProperties + : _personProperties; + var cred = HttpHelper.GetSetting("Credentials", "UCDavisLDAP") ?? ""; + using var lc = new LdapConnection(ldapIdentifier, new System.Net.NetworkCredential(_username, cred, "ou.ad3.ucdavis.edu")); + lc.SessionOptions.ProtocolVersion = 3; + lc.SessionOptions.SecureSocketLayer = true; + lc.SessionOptions.VerifyServerCertificate = (connection, certificate) => true; + lc.Bind(); + var searchRequest = new SearchRequest(searchStart, searchFilter, SearchScope.Subtree, props); + var response = (SearchResponse)lc.SendRequest(searchRequest); + return response; + } } } diff --git a/web/Classes/Utilities/LdapService.cs b/web/Classes/Utilities/LdapService.cs new file mode 100644 index 0000000..785b756 --- /dev/null +++ b/web/Classes/Utilities/LdapService.cs @@ -0,0 +1,176 @@ +using System.Runtime.Versioning; +using System.DirectoryServices.AccountManagement; +using System.DirectoryServices.Protocols; +using System.Reflection; +using Amazon.Runtime.Internal.Transform; +using Viper.Models.AAUD; +using Viper.Areas.Directory.Models; + +namespace Viper.Classes.Utilities +{ + [SupportedOSPlatform("windows")] + public class LdapService + { + private const string _ldapUsername = "UID=vetmed,OU=Special Users,DC=ucdavis,DC=edu"; + private const string _ldapServer = "ldap.ucdavis.edu"; + private const string _ldapStart = "OU=People,DC=ucdavis,DC=edu"; + private const int _ldapSSLPort = 636; + + private static readonly string[] personAttributes = + { + "givenName","sn","middlename","ou","mail","telephoneNumber","mobile","postalAddress", + "ucdStudentLevel","labeledUri","title","uid","ucdPersonPIDM","ucdPersonIAMID","employeeNumber", + "ucdStudentSID","ucdPersonUUID","eduPersonNickname","ucdPersonAffiliation","displayname" + }; + private static readonly string[] CFParams = + { + "accountexpires","adspath","badpasswordtime","badpwdcount","cn","codepage","company","countrycode","deliverandredirect","department","deptname","departmentnumber","Description","displayname","distinguishedname","dscorepropagationdata","edupersonaffiliation","edupersonprincipalname","employeenumber","extensionattribute10","extensionattribute11","extensionattribute12","extensionattribute13","extensionattribute14","extensionattribute15","extensionattribute5","extensionattribute6","extensionattribute7","extensionattribute8","extensionattribute9","gidnumber","givenname","instancetype","internetencoding","l","lastlogoff","lastlogon","lastlogontimestamp","legacyexchangedn","lockouttime","logoncount","mail","mailnickname","mapirecipient","memberof","mobile","msexcharchiveguid","msexcharchivename","msexcharchivestatus","msexchblockedsendershash","msexchcomanagedobjectsbl","msexchextensionattribute16","msexchextensionattribute17","msexchmailboxguid","msexchpoliciesexcluded","msexchrecipientdisplaytype","msexchrecipienttypedetails","msexchremoterecipienttype","msexchsafesendershash","msexchtextmessagingstate","msexchumdtmfmap","msexchuseraccountcontrol","msexchversion","msexchwhenmailboxcreated","name","objectcategory","objectclass","objectguid","objectsid","ou","pager","phone","physicaldeliveryofficename","postaladdress","postalcode","primarygroupid","proxyaddresses","pwdlastset","SamAccountName","samaccounttype","showinaddressbook","sn","st","street","streetaddress","targetaddress","telephonenumber","textencodedoraddress","title","ucdappointmentdepartmentcode","ucdappointmenttitlecode","ucdpersonaffiliation","ucdpersoniamid","ucdpersonnetid","ucdpersonpidm","ucdpersonppsid","ucdpersonuuid","ucdpublishitemflag","ucdstudentsid","uid","uidnumber","useraccountcontrol","username","userprincipalname","usnchanged","usncreated","whenchanged","whencreated" + }; + + private static SearchResponse SearchLdap(string searchFilter) + { + var ldapIdentifier = new LdapDirectoryIdentifier(_ldapServer, _ldapSSLPort); + var cred = HttpHelper.GetSetting("Credentials", "UCDavisDirectoryLDAP") ?? ""; + using var lc = new LdapConnection(ldapIdentifier, + new System.Net.NetworkCredential(_ldapUsername, cred), + AuthType.Basic); + lc.SessionOptions.ProtocolVersion = 3; + lc.SessionOptions.SecureSocketLayer = true; + lc.SessionOptions.VerifyServerCertificate = (connection, certificate) => true; + lc.Bind(); + + var searchRequest = new SearchRequest(_ldapStart, searchFilter, SearchScope.Subtree, personAttributes); + var response = (SearchResponse)lc.SendRequest(searchRequest); + return response; + } + + /// + /// Get users for display\ searching by name, cn, or samAccountName + /// + /// Searches all fields (phone number, SN, given name, UID, CN, mail) for this value + /// List of Users + public static List GetUsersContact(string search) + { + List users = new(); + string filter = string.Format("(|(telephoneNumber=*{0})(sn={0}*)(givenName={0}*)(uid={0}*)(cn={0})(mail={0}*))", search); + var results = SearchLdap(filter); + + foreach (SearchResultEntry entry in results.Entries) + { + users.Add(new LdapUserContact(entry)); + if (users.Count >= 100) + { + break; + } + } + return SortUsersContact(users); + } + + /// + /// Get users for display, optionally searching ou.ad3, searching by name, cn, or samAccountName + /// + /// Searches all fields (phone number, SN, given name, UID, CN, mail) for this value + /// Dictionary of Users, indexed by mothraID + public Dictionary GetUsersContactDictionary(string search) + { + Dictionary users = new(); + string filter = string.Format("(|(telephoneNumber=*{0})(sn={0}*)(givenName={0}*)(uid={0}*)(cn={0})(mail={0}*))", search); + var results = SearchLdap(filter); + foreach (SearchResultEntry entry in results.Entries) + { + var user = new LdapUserContact(entry); + if (user.UcdPersonUuid != null) + { + users.Add(user.UcdPersonUuid, user); + } + } + return users; + } + + /// + /// Look up User by search string + /// + /// Search string for looking up user + /// LdapUserContact + public LdapUserContact? GetUserContact(string search) + { + string filter = string.Format("(|(telephoneNumber=*{0})(sn={0}*)(givenName={0}*)(uid={0}*)(cn={0})(mail={0}*))", search); + var results = SearchLdap(filter); + + if (results.Entries.Count > 0) + { + return new LdapUserContact(results.Entries[0]); + } + return null; + } + + + /// + /// Look up User by its iamID + /// + /// iamID for looking up user + /// LdapUserContact + public LdapUserContact? GetUserByID(string? id) + { + if (id == null) return null; + string filter = string.Format("(ucdpersoniamid = {0})", id); + var results = SearchLdap(filter); + if (results.Entries.Count > 0) + { + return new LdapUserContact(results.Entries[0]); + } + return null; + } + + /// + /// Get dictionary of Users from a list of MothraIDs + /// + /// List of MothraIDs for looking up users + /// Dictionary of Users, indexed by mothraID + public Dictionary GetUsersByIDs(List ids) + { + string filter = "(|"; + foreach (string i in ids) { + filter += string.Format("(ucdpersonuuid = {0})", i); + } + filter += ")"; + var results = SearchLdap(filter); + var users = new Dictionary(); + foreach (SearchResultEntry entry in results.Entries) + { + var user = new LdapUserContact(entry); + if (user.UcdPersonUuid != null) + { + users.Add(user.UcdPersonUuid, user); + } + } + return users; + } + + /// + /// Gets a single user from ou or ad3 + /// + /// samAccountName of user + /// If true, searches the SVM OU in ou.ad3.ucdavis.edu, otherwise, searches ucdUsers in ad3 + /// + public LdapUserContact? GetUserBySamAccountName(string? samAccountName) + { + string filter = string.Format("(&(objectClass=user)(samAccountName={0}))", samAccountName); + var results = SearchLdap(filter); + if (results.Entries.Count > 0) + { + return new LdapUserContact(results.Entries[0]); + } + return null; + } + + //Sort users by description first, or sam account name + private static List SortUsersContact(List users) + { + users.Sort((a, b) => a.DisplayName == b.DisplayName + ? a.Sn.CompareTo(b.Sn) + : a.DisplayName.CompareTo(b.DisplayName)); + return users; + } + } +} \ No newline at end of file diff --git a/web/Program.cs b/web/Program.cs index 54f6d71..7bc6b98 100644 --- a/web/Program.cs +++ b/web/Program.cs @@ -216,7 +216,8 @@ .From("viper.vetmed.ucdavis.edu") .From("secure.vetmed.ucdavis.edu") .From("secure-test.vetmed.ucdavis.edu") - .From("*.vetmed.ucdavis.edu"); + .From("*.vetmed.ucdavis.edu") + .From("http://localhost"); csp.AllowPlugins .FromNowhere(); // Plugins not allowed diff --git a/web/Views/Shared/_VIPERLayout.cshtml b/web/Views/Shared/_VIPERLayout.cshtml index ad9bc98..1291018 100644 --- a/web/Views/Shared/_VIPERLayout.cshtml +++ b/web/Views/Shared/_VIPERLayout.cshtml @@ -203,7 +203,7 @@ auto-close="true"> {{viperErrorMessage}} diff --git a/web/nlog.config b/web/nlog.config index 8c7d23d..6c63edd 100644 --- a/web/nlog.config +++ b/web/nlog.config @@ -21,6 +21,10 @@ + + @@ -81,12 +85,19 @@ - + + + + + + + + diff --git a/web/wwwroot/css/site.css b/web/wwwroot/css/site.css index 5e3667c..aee8a62 100644 --- a/web/wwwroot/css/site.css +++ b/web/wwwroot/css/site.css @@ -233,4 +233,14 @@ body { font-size: 1rem; line-height: 1rem; margin: .0rem 0rem .5rem 0rem; +} + +div#directoryResults .q-avatar { + height: 111px !important; + width: 87px !important; +} + +header .q-avatar { + height: 40px !important; + width: 31px !important; } \ No newline at end of file