| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Collections.Generic; |
| | | 6 | | using System.Collections.ObjectModel; |
| | | 7 | | using System.Security.Claims; |
| | | 8 | | using System.Security.Principal; |
| | | 9 | | using CoreWCF.IdentityModel.Policy; |
| | | 10 | | using CoreWCF.Security; |
| | | 11 | | |
| | | 12 | | namespace CoreWCF.IdentityModel.Claims |
| | | 13 | | { |
| | | 14 | | public class WindowsClaimSet : ClaimSet, IIdentityInfo, IDisposable |
| | | 15 | | { |
| | | 16 | | internal const bool DefaultIncludeWindowsGroups = true; |
| | | 17 | | private readonly ClaimsIdentity _windowsIdentity; |
| | | 18 | | private readonly bool _includeWindowsGroups; |
| | | 19 | | private IList<Claim> _claims; |
| | | 20 | | private bool _disposed = false; |
| | | 21 | | private readonly string _authenticationType; |
| | | 22 | | GroupSidClaimCollection _groups; |
| | | 23 | | LdapSettings _ldapSettings; |
| | | 24 | | |
| | | 25 | | public WindowsClaimSet(WindowsIdentity windowsIdentity) |
| | 0 | 26 | | : this(windowsIdentity, DefaultIncludeWindowsGroups) |
| | | 27 | | { |
| | 0 | 28 | | } |
| | | 29 | | |
| | | 30 | | public WindowsClaimSet(WindowsIdentity windowsIdentity, bool includeWindowsGroups) |
| | 0 | 31 | | : this(windowsIdentity, includeWindowsGroups, DateTime.UtcNow.AddHours(10)) |
| | | 32 | | { |
| | 0 | 33 | | } |
| | | 34 | | |
| | | 35 | | public WindowsClaimSet(WindowsIdentity windowsIdentity, DateTime expirationTime) |
| | 0 | 36 | | : this(windowsIdentity, DefaultIncludeWindowsGroups, expirationTime) |
| | | 37 | | { |
| | 0 | 38 | | } |
| | | 39 | | |
| | | 40 | | public WindowsClaimSet(WindowsIdentity windowsIdentity, bool includeWindowsGroups, DateTime expirationTime) |
| | 0 | 41 | | : this(windowsIdentity, null, includeWindowsGroups, expirationTime, true) |
| | | 42 | | { |
| | 0 | 43 | | } |
| | | 44 | | |
| | | 45 | | public WindowsClaimSet(WindowsIdentity windowsIdentity, string authenticationType, bool includeWindowsGroups, Da |
| | 0 | 46 | | : this(windowsIdentity, authenticationType, includeWindowsGroups, expirationTime, true) |
| | | 47 | | { |
| | 0 | 48 | | } |
| | | 49 | | |
| | | 50 | | internal WindowsClaimSet(WindowsIdentity windowsIdentity, string authenticationType, bool includeWindowsGroups, |
| | 0 | 51 | | : this(windowsIdentity, authenticationType, includeWindowsGroups, DateTime.UtcNow.AddHours(10), clone) |
| | | 52 | | { |
| | 0 | 53 | | } |
| | | 54 | | |
| | | 55 | | internal WindowsClaimSet(WindowsIdentity windowsIdentity, string authenticationType, bool includeWindowsGroups, |
| | 0 | 56 | | : this(windowsIdentity, authenticationType, includeWindowsGroups, expirationTime, clone, null) |
| | | 57 | | { |
| | | 58 | | |
| | 0 | 59 | | } |
| | | 60 | | |
| | | 61 | | internal WindowsClaimSet(WindowsIdentity windowsIdentity, string authenticationType, bool includeWindowsGroups, |
| | 0 | 62 | | : this(authenticationType, includeWindowsGroups, expirationTime, clone, _fromClaims) |
| | | 63 | | { |
| | 0 | 64 | | if (windowsIdentity == null) |
| | | 65 | | { |
| | 0 | 66 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(windowsIdentity)); |
| | | 67 | | } |
| | | 68 | | |
| | 0 | 69 | | _windowsIdentity = clone ? SecurityUtils.CloneWindowsIdentityIfNecessary(windowsIdentity, authenticationType |
| | 0 | 70 | | } |
| | | 71 | | |
| | | 72 | | internal WindowsClaimSet(ClaimsIdentity claimsIdentity, string authenticationType, bool includeWindowsGroups, Da |
| | 1 | 73 | | : this(authenticationType, includeWindowsGroups, expirationTime, clone, _fromClaims) |
| | | 74 | | { |
| | 1 | 75 | | if (claimsIdentity == null) |
| | | 76 | | { |
| | 0 | 77 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(claimsIdentity)); |
| | | 78 | | } |
| | 1 | 79 | | _windowsIdentity = (clone && claimsIdentity is WindowsIdentity) ? SecurityUtils.CloneWindowsIdentityIfNecess |
| | 1 | 80 | | _ldapSettings = ldapSettings; |
| | 1 | 81 | | } |
| | | 82 | | |
| | | 83 | | internal WindowsClaimSet(ClaimsIdentity claimsIdentity, bool includeWindowsGroups, LdapSettings ldapSettings) |
| | 1 | 84 | | : this(claimsIdentity, null, includeWindowsGroups, DateTime.UtcNow.AddHours(10), false, null,ldapSettings) |
| | | 85 | | { |
| | 1 | 86 | | } |
| | | 87 | | |
| | 1 | 88 | | private WindowsClaimSet(string authenticationType, bool includeWindowsGroups, DateTime expirationTime, bool clon |
| | | 89 | | { |
| | 1 | 90 | | _includeWindowsGroups = includeWindowsGroups; |
| | 1 | 91 | | ExpirationTime = expirationTime; |
| | 1 | 92 | | _authenticationType = authenticationType; |
| | 1 | 93 | | if (_fromClaims != null && _fromClaims.Count > 0) |
| | | 94 | | { |
| | 0 | 95 | | List<Claim> allClaims = new List<Claim>(); |
| | 0 | 96 | | foreach (Claim claim in _fromClaims) |
| | | 97 | | { |
| | 0 | 98 | | allClaims.Add(claim); |
| | | 99 | | } |
| | 0 | 100 | | _claims = allClaims; |
| | | 101 | | } |
| | 1 | 102 | | } |
| | | 103 | | |
| | | 104 | | private WindowsClaimSet(WindowsClaimSet from) |
| | 0 | 105 | | : this(from.WindowsIdentity, from._authenticationType, from._includeWindowsGroups, from.ExpirationTime, true |
| | | 106 | | { |
| | 0 | 107 | | } |
| | | 108 | | |
| | | 109 | | public override Claim this[int index] |
| | | 110 | | { |
| | | 111 | | get |
| | | 112 | | { |
| | 0 | 113 | | ThrowIfDisposed(); |
| | 0 | 114 | | EnsureClaims(); |
| | 0 | 115 | | return _claims[index]; |
| | | 116 | | } |
| | | 117 | | } |
| | | 118 | | |
| | | 119 | | public override int Count |
| | | 120 | | { |
| | | 121 | | get |
| | | 122 | | { |
| | 0 | 123 | | ThrowIfDisposed(); |
| | 0 | 124 | | EnsureClaims(); |
| | 0 | 125 | | return _claims.Count; |
| | | 126 | | } |
| | | 127 | | } |
| | | 128 | | |
| | | 129 | | IIdentity IIdentityInfo.Identity |
| | | 130 | | { |
| | | 131 | | get |
| | | 132 | | { |
| | 1 | 133 | | ThrowIfDisposed(); |
| | 1 | 134 | | return _windowsIdentity; |
| | | 135 | | } |
| | | 136 | | } |
| | | 137 | | |
| | | 138 | | public ClaimsIdentity WindowsIdentity |
| | | 139 | | { |
| | | 140 | | get |
| | | 141 | | { |
| | 0 | 142 | | ThrowIfDisposed(); |
| | 0 | 143 | | return _windowsIdentity; |
| | | 144 | | } |
| | | 145 | | } |
| | | 146 | | |
| | | 147 | | public override ClaimSet Issuer |
| | | 148 | | { |
| | 0 | 149 | | get { return Windows; } |
| | | 150 | | } |
| | | 151 | | |
| | 0 | 152 | | public DateTime ExpirationTime { get; } |
| | | 153 | | |
| | | 154 | | GroupSidClaimCollection Groups |
| | | 155 | | { |
| | | 156 | | get |
| | | 157 | | { |
| | 0 | 158 | | if (this._groups == null) |
| | | 159 | | { |
| | 0 | 160 | | this._groups = new GroupSidClaimCollection(_windowsIdentity, _ldapSettings); |
| | | 161 | | } |
| | 0 | 162 | | return this._groups; |
| | | 163 | | } |
| | | 164 | | } |
| | | 165 | | |
| | | 166 | | internal WindowsClaimSet Clone() |
| | | 167 | | { |
| | 0 | 168 | | ThrowIfDisposed(); |
| | 0 | 169 | | return new WindowsClaimSet(this); |
| | | 170 | | } |
| | | 171 | | |
| | | 172 | | public void Dispose() |
| | | 173 | | { |
| | 0 | 174 | | if (!_disposed) |
| | | 175 | | { |
| | 0 | 176 | | _disposed = true; |
| | 0 | 177 | | if(_windowsIdentity is WindowsIdentity) |
| | 0 | 178 | | ((WindowsIdentity)_windowsIdentity).Dispose(); |
| | | 179 | | } |
| | 0 | 180 | | } |
| | | 181 | | |
| | | 182 | | private IList<Claim> InitializeClaimsCore() |
| | | 183 | | { |
| | 0 | 184 | | List<Claim> claims = new List<Claim>(); |
| | 0 | 185 | | if (_windowsIdentity is WindowsIdentity) |
| | | 186 | | { |
| | 0 | 187 | | WindowsIdentity _windowsInternalIdentity = (WindowsIdentity)_windowsIdentity; |
| | 0 | 188 | | if (_windowsInternalIdentity.AccessToken == null) |
| | | 189 | | { |
| | 0 | 190 | | return new List<Claim>(); |
| | | 191 | | } |
| | | 192 | | |
| | 0 | 193 | | claims.Add(new Claim(ClaimTypes.Sid, _windowsInternalIdentity.User, Rights.Identity)); |
| | 0 | 194 | | if (TryCreateWindowsSidClaim(_windowsInternalIdentity, out Claim claim)) |
| | | 195 | | { |
| | 0 | 196 | | claims.Add(claim); |
| | | 197 | | } |
| | 0 | 198 | | claims.Add(Claim.CreateNameClaim(_windowsIdentity.Name)); |
| | | 199 | | } |
| | | 200 | | else |
| | | 201 | | { |
| | 0 | 202 | | claims.Add(Claim.CreateNameClaim(_windowsIdentity.Name)); |
| | | 203 | | } |
| | | 204 | | |
| | 0 | 205 | | if (_includeWindowsGroups) |
| | | 206 | | { |
| | 0 | 207 | | claims.AddRange(Groups); |
| | | 208 | | } |
| | 0 | 209 | | return claims; |
| | | 210 | | } |
| | | 211 | | |
| | | 212 | | private void EnsureClaims() |
| | | 213 | | { |
| | 0 | 214 | | if (_claims != null) |
| | | 215 | | { |
| | 0 | 216 | | return; |
| | | 217 | | } |
| | | 218 | | |
| | 0 | 219 | | _claims = InitializeClaimsCore(); |
| | 0 | 220 | | } |
| | | 221 | | |
| | | 222 | | public void AddClaim(Claim claim) |
| | | 223 | | { |
| | 0 | 224 | | _claims.Add(claim); |
| | 0 | 225 | | } |
| | | 226 | | |
| | | 227 | | private void ThrowIfDisposed() |
| | | 228 | | { |
| | 1 | 229 | | if (_disposed) |
| | | 230 | | { |
| | 0 | 231 | | throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(GetType().FullName |
| | | 232 | | } |
| | 1 | 233 | | } |
| | | 234 | | |
| | | 235 | | private static bool SupportedClaimType(string claimType) |
| | | 236 | | { |
| | 0 | 237 | | return claimType == null || |
| | 0 | 238 | | ClaimTypes.Sid == claimType || |
| | 0 | 239 | | ClaimTypes.DenyOnlySid == claimType || |
| | 0 | 240 | | ClaimTypes.Role == claimType || |
| | 0 | 241 | | ClaimTypes.Name == claimType; |
| | | 242 | | } |
| | | 243 | | |
| | | 244 | | // Note: null string represents any. |
| | | 245 | | public override IEnumerable<Claim> FindClaims(string claimType, string right) |
| | | 246 | | { |
| | 0 | 247 | | ThrowIfDisposed(); |
| | 0 | 248 | | if (!SupportedClaimType(claimType) || !SupportedRight(right)) |
| | | 249 | | { |
| | 0 | 250 | | yield break; |
| | | 251 | | } |
| | 0 | 252 | | else if (_claims == null && _windowsIdentity is WindowsIdentity && (ClaimTypes.Sid == claimType || ClaimType |
| | | 253 | | { |
| | 0 | 254 | | if (ClaimTypes.Sid == claimType) |
| | | 255 | | { |
| | 0 | 256 | | if (right == null || Rights.Identity == right) |
| | | 257 | | { |
| | 0 | 258 | | yield return new Claim(ClaimTypes.Sid, ((WindowsIdentity)_windowsIdentity).User, Rights.Identity |
| | | 259 | | } |
| | | 260 | | } |
| | | 261 | | |
| | 0 | 262 | | if (right == null || Rights.PossessProperty == right) |
| | | 263 | | { |
| | 0 | 264 | | if (TryCreateWindowsSidClaim((WindowsIdentity)_windowsIdentity, out Claim sid)) |
| | | 265 | | { |
| | 0 | 266 | | if (claimType == sid.ClaimType) |
| | | 267 | | { |
| | 0 | 268 | | yield return sid; |
| | | 269 | | } |
| | | 270 | | } |
| | | 271 | | } |
| | | 272 | | |
| | 0 | 273 | | if (_includeWindowsGroups && (right == null || Rights.PossessProperty == right)) |
| | | 274 | | { |
| | 0 | 275 | | for (int i = 0; i < this.Groups.Count; ++i) |
| | | 276 | | { |
| | 0 | 277 | | Claim sid = this.Groups[i]; |
| | 0 | 278 | | if (claimType == sid.ClaimType) |
| | | 279 | | { |
| | 0 | 280 | | yield return sid; |
| | | 281 | | } |
| | | 282 | | } |
| | | 283 | | } |
| | | 284 | | } |
| | | 285 | | else |
| | | 286 | | { |
| | 0 | 287 | | EnsureClaims(); |
| | | 288 | | |
| | 0 | 289 | | bool anyClaimType = (claimType == null); |
| | 0 | 290 | | bool anyRight = (right == null); |
| | | 291 | | |
| | 0 | 292 | | for (int i = 0; i < _claims.Count; ++i) |
| | | 293 | | { |
| | 0 | 294 | | Claim claim = _claims[i]; |
| | 0 | 295 | | if ((claim != null) && |
| | 0 | 296 | | (anyClaimType || claimType == claim.ClaimType) && |
| | 0 | 297 | | (anyRight || right == claim.Right)) |
| | | 298 | | { |
| | 0 | 299 | | yield return claim; |
| | | 300 | | } |
| | | 301 | | } |
| | | 302 | | } |
| | 0 | 303 | | } |
| | | 304 | | |
| | | 305 | | public override IEnumerator<Claim> GetEnumerator() |
| | | 306 | | { |
| | 0 | 307 | | ThrowIfDisposed(); |
| | 0 | 308 | | EnsureClaims(); |
| | 0 | 309 | | return _claims.GetEnumerator(); |
| | | 310 | | } |
| | | 311 | | |
| | | 312 | | public override string ToString() |
| | | 313 | | { |
| | 0 | 314 | | return _disposed ? base.ToString() : SecurityUtils.ClaimSetToString(this); |
| | | 315 | | } |
| | | 316 | | |
| | | 317 | | public static bool TryCreateWindowsSidClaim(WindowsIdentity windowsIdentity, out Claim claim) |
| | | 318 | | { |
| | 0 | 319 | | if (windowsIdentity.User != null && windowsIdentity.User.IsAccountSid()) |
| | | 320 | | { |
| | 0 | 321 | | claim = Claim.CreateWindowsSidClaim(new SecurityIdentifier(windowsIdentity.User.Value)); |
| | 0 | 322 | | return true; |
| | | 323 | | } |
| | 0 | 324 | | claim = null; |
| | 0 | 325 | | return false; |
| | | 326 | | } |
| | | 327 | | |
| | | 328 | | class GroupSidClaimCollection : Collection<Claim> |
| | | 329 | | { |
| | 0 | 330 | | public GroupSidClaimCollection(ClaimsIdentity claimsIdentity, LdapSettings ldapSettings) |
| | | 331 | | { |
| | 0 | 332 | | if(claimsIdentity is WindowsIdentity) |
| | | 333 | | { |
| | 0 | 334 | | var windowsIdentity = (WindowsIdentity)claimsIdentity; |
| | 0 | 335 | | if (windowsIdentity.Token != IntPtr.Zero) |
| | | 336 | | { |
| | 0 | 337 | | foreach (var groupId in windowsIdentity.Groups) |
| | | 338 | | { |
| | 0 | 339 | | var group = groupId.Translate(typeof(NTAccount)); |
| | 0 | 340 | | string[] domainGroups = group.Value.Split(new char[] { '\\' }); |
| | 0 | 341 | | if (domainGroups.Length > 1) |
| | | 342 | | { |
| | 0 | 343 | | base.Add(new Claim(ClaimTypes.Role, domainGroups[1], Rights.Identity)); |
| | | 344 | | } |
| | | 345 | | else |
| | | 346 | | { |
| | 0 | 347 | | base.Add(new Claim(ClaimTypes.Role, group, Rights.Identity)); |
| | | 348 | | } |
| | | 349 | | } |
| | | 350 | | } |
| | | 351 | | } |
| | 0 | 352 | | else if(ldapSettings !=null) |
| | | 353 | | { |
| | 0 | 354 | | List<Claim> allClaims = LdapAdapter.RetrieveClaimsAsync(ldapSettings, claimsIdentity.Name).GetAwaite |
| | 0 | 355 | | foreach(Claim roleClaim in allClaims) |
| | | 356 | | { |
| | 0 | 357 | | base.Add(roleClaim); |
| | | 358 | | } |
| | | 359 | | } |
| | | 360 | | |
| | 0 | 361 | | } |
| | | 362 | | } |
| | | 363 | | } |
| | | 364 | | } |