/// <summary> /// Parse a PermittedLogonTimes byte array into a LogonTimes object. /// </summary> /// <param name="times">Byte array of UTC logon times.</param> /// <returns>A LogonTimes object of the given permitted times.</returns> public static LogonTimes PermittedLogonTimes(byte[] times) { if (times == null) return null;//All? var logonTimes = new LogonTimes(); //Each day gets 3 bytes of hour flags, make sure the array is long enough to loop through all of them. Array.Resize<byte>(ref times, 3 * 7); for (var i = 0; i < 3 * 7; i += 3) { byte[] bytes = { times[i + 0], times[i + 1], times[i + 2], 0 };//Aggregate all of the hour flags. if (!BitConverter.IsLittleEndian)//Make sure they bytes are in the proper order to make into one large set of flags. Array.Reverse(bytes); var bits = BitConverter.ToInt32(bytes, 0);//Convert the 3 bytes of flags into one set of flags. if (bits == 0)//nothing on this day continue; //0, 3, 6, 9, 12, 15, 18, 21 var day = (DayOfWeek)(i / 3); for (var j = 0; j < 24; j++) { if ((bits & 1 << j) > 0) logonTimes.Add(day, LogonTimeUnit.Hours, (uint)j); } } return logonTimes; }
/// <summary> /// Parse a PermittedLogonTimes byte array into a LogonTimes object. /// </summary> /// <param name="times">Byte array of UTC logon times.</param> /// <returns>A LogonTimes object of the given permitted times.</returns> public static LogonTimes PermittedLogonTimes(byte[] times) { if (times == null) { return(null);//All? } var logonTimes = new LogonTimes(); //Each day gets 3 bytes of hour flags, make sure the array is long enough to loop through all of them. Array.Resize <byte>(ref times, 3 * 7); for (var i = 0; i < 3 * 7; i += 3) { byte[] bytes = { times[i + 0], times[i + 1], times[i + 2], 0 }; //Aggregate all of the hour flags. if (!BitConverter.IsLittleEndian) //Make sure they bytes are in the proper order to make into one large set of flags. { Array.Reverse(bytes); } var bits = BitConverter.ToInt32(bytes, 0); //Convert the 3 bytes of flags into one set of flags. if (bits == 0) //nothing on this day { continue; } //0, 3, 6, 9, 12, 15, 18, 21 var day = (DayOfWeek)(i / 3); for (var j = 0; j < 24; j++) { if ((bits & 1 << j) > 0) { logonTimes.Add(day, LogonTimeUnit.Hours, (int)(uint)j); } } } return(logonTimes); }
internal static IList <Claim> GetClaims(this UserPrincipal user, IList <string> claimTypes, SerializationFormat serializationFormat = SerializationFormat.Json) { claimTypes = claimTypes ?? new List <string>(); if (user == null) { throw new ArgumentNullException("user"); } if (user.Guid.HasValue == false) { throw new MissingFieldException(Resource.MissingUserPrincipalGuid); } if (user.Sid == null) { throw new MissingFieldException(Resource.MissingUserPrincipalSid); } var claims = new List <Claim>(); //Generate here from the SameAccountName instead of passing it through? //claims.Add(new Claim(ClaimTypes.Name, user.Name, ClaimValueTypes.String)); //This is required for ASP.NET Identity, it should be a value unique to each user. https://technet.microsoft.com/en-us/library/cc961625.aspx SID can change "sometimes", Guid should never change. claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Guid.Value.ToString(), ClaimValueTypes.String)); claims.Add(new Claim(ClaimTypes.PrimarySid, user.Sid.Value, ClaimValueTypes.Sid)); claims.Add(new Claim(ClaimTypesAD.Guid, user.Guid.Value.ToString(), ClaimValueTypes.String)); var securityGroups = user.GetAuthorizationGroups().Cast <GroupPrincipal>(); claims = claims.Union(securityGroups.Select(_ => { //TODO: Need a better way to get netbios domain from DistinguishedName var domain = Owin.Security.ActiveDirectoryLDAP.DomainCredentialConfig.DomainCredentials.FirstOrDefault(d => _ != null && !String.IsNullOrEmpty(_.DistinguishedName) && _.DistinguishedName.EndsWith(d.Container, StringComparison.OrdinalIgnoreCase)); if (domain != null) { return(new Claim(ClaimsIdentity.DefaultRoleClaimType, String.Format(CultureInfo.InvariantCulture, @"{0}\{1}", domain.NetBIOS, _.SamAccountName), ClaimValueTypes.String)); } return(null); }).Where(_ => _ != null)).ToList();//will these always be security groups? //Is the first group the primary group? It seems so in testing but I'm not sure if that can be relied on. //var primaryGroup = securityGroups.FirstOrDefault(); //if (primaryGroup != null) // claims.Add(new Claim(ClaimTypes.PrimaryGroupSid, primaryGroup.Sid.Value, ClaimValueTypes.Sid)); if (claimTypes.Contains(ClaimTypes.GroupSid) && securityGroups.Any()) { claims.AddRange(securityGroups.Select(_ => new Claim(ClaimTypes.GroupSid, _.Sid.Value, ClaimValueTypes.Sid)));// Union? } if (claimTypes.Contains(ClaimTypesAD.BadLogonCount)) { claims.Add(new Claim(ClaimTypesAD.BadLogonCount, user.BadLogonCount.ToString(CultureInfo.InvariantCulture), ClaimValueTypes.Integer32));//can this be set via a webapp? part of ValidateCredentials? } if (claimTypes.Contains(ClaimTypesAD.Enabled) /* && user.Enabled.HasValue*/) { claims.Add(new Claim(ClaimTypesAD.Enabled, (user.Enabled ?? false).ToString(), ClaimValueTypes.Boolean));//default? is a null value considered disabled? } if (claimTypes.Contains(ClaimTypesAD.LockedOut)) { claims.Add(new Claim(ClaimTypesAD.LockedOut, user.IsAccountLockedOut().ToString(), ClaimValueTypes.Boolean)); } if (claimTypes.Contains(ClaimTypesAD.SmartcardLogonRequired)) { claims.Add(new Claim(ClaimTypesAD.SmartcardLogonRequired, user.SmartcardLogonRequired.ToString(), ClaimValueTypes.Boolean));//Deny? How could we handle this. } if (claimTypes.Contains(ClaimTypesAD.Description) && !String.IsNullOrEmpty(user.Description)) { claims.Add(new Claim(ClaimTypesAD.Description, user.Description, ClaimValueTypes.String));//job title? } if (claimTypes.Contains(ClaimTypesAD.DisplayName) && !String.IsNullOrEmpty(user.DisplayName)) { claims.Add(new Claim(ClaimTypesAD.DisplayName, user.DisplayName, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.DistinguishedName) && !String.IsNullOrEmpty(user.DistinguishedName)) { claims.Add(new Claim(ClaimTypesAD.DistinguishedName, user.DistinguishedName, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypes.Email) && !String.IsNullOrEmpty(user.EmailAddress)) { claims.Add(new Claim(ClaimTypes.Email, user.EmailAddress, ClaimValueTypes.Email)); } if (claimTypes.Contains(ClaimTypesAD.EmployeeId) && !String.IsNullOrEmpty(user.EmployeeId)) { claims.Add(new Claim(ClaimTypesAD.EmployeeId, user.EmployeeId, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypes.GivenName) && !String.IsNullOrEmpty(user.GivenName)) { claims.Add(new Claim(ClaimTypes.GivenName, user.GivenName, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.HomeDirectory) && !String.IsNullOrEmpty(user.HomeDirectory)) { claims.Add(new Claim(ClaimTypesAD.HomeDirectory, user.HomeDirectory, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.HomeDrive) && !String.IsNullOrEmpty(user.HomeDrive)) { claims.Add(new Claim(ClaimTypesAD.HomeDrive, user.HomeDrive, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.MiddleName) && !String.IsNullOrEmpty(user.MiddleName)) { claims.Add(new Claim(ClaimTypesAD.MiddleName, user.MiddleName, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.SamAccountName) && !String.IsNullOrEmpty(user.SamAccountName)) { claims.Add(new Claim(ClaimTypesAD.SamAccountName, user.SamAccountName, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypes.Surname) && !String.IsNullOrEmpty(user.Surname)) { claims.Add(new Claim(ClaimTypes.Surname, user.Surname, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.UserPrincipalName) && !String.IsNullOrEmpty(user.UserPrincipalName)) { claims.Add(new Claim(ClaimTypesAD.UserPrincipalName, user.UserPrincipalName, ClaimValueTypes.String)); } if (claimTypes.Contains(ClaimTypesAD.VoicePhone) && !String.IsNullOrEmpty(user.VoiceTelephoneNumber)) { claims.Add(new Claim(ClaimTypesAD.VoicePhone, user.VoiceTelephoneNumber, ClaimValueTypes.String));//WorkPhone? Format? e.g. https://en.wikipedia.org/wiki/E.123 or https://en.wikipedia.org/wiki/Microsoft_telephone_number_format } if (claimTypes.Contains(ClaimTypesAD.AccountExpiration) && user.AccountExpirationDate.HasValue) { claims.Add(new Claim(ClaimTypesAD.AccountExpiration, user.AccountExpirationDate.RoundTripString(), ClaimValueTypes.DateTime));//ClaimTypes.Expiration? } if (claimTypes.Contains(ClaimTypesAD.AccountLockout) && user.AccountLockoutTime.HasValue) { claims.Add(new Claim(ClaimTypesAD.AccountLockout, user.AccountLockoutTime.RoundTripString(), ClaimValueTypes.DateTime)); } if (claimTypes.Contains(ClaimTypesAD.LastBadPassword) && user.LastBadPasswordAttempt.HasValue) { claims.Add(new Claim(ClaimTypesAD.LastBadPassword, user.LastBadPasswordAttempt.RoundTripString(), ClaimValueTypes.DateTime)); } if (claimTypes.Contains(ClaimTypesAD.LastLogon) && user.LastLogon.HasValue) { claims.Add(new Claim(ClaimTypesAD.LastLogon, user.LastLogon.RoundTripString(), ClaimValueTypes.DateTime)); } if (claimTypes.Contains(ClaimTypesAD.LastPasswordSet) && user.LastPasswordSet.HasValue) { claims.Add(new Claim(ClaimTypesAD.LastPasswordSet, user.LastPasswordSet.RoundTripString(), ClaimValueTypes.DateTime)); } if (claimTypes.Contains(ClaimTypesAD.PermittedLogonTimes) && user.PermittedLogonTimes != null) { claims.Add(LogonTimes.PermittedLogonTimes(user.PermittedLogonTimes).ToClaim(serializationFormat));//TODO: series of claims instead of serialized? } return(claims); }