1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IdentityModel.Diagnostics;
using System.IdentityModel.Policy;
using System.Security.Claims;
using System.Security.Principal;
using SysClaimSet = System.IdentityModel.Claims.ClaimSet;
namespace System.IdentityModel.Tokens
{
/// <summary>
/// Defines an AuthorizationPolicy that carries the IDFx Claims. When IDFx is enabled
/// a new set of Security Token Authenticators are added to the system. These Authenticators
/// will generate the new Claims defined in System.Security.Claims.
/// </summary>
internal class AuthorizationPolicy : IAuthorizationPolicy
{
#pragma warning disable 1591
public const string ClaimsPrincipalKey = "ClaimsPrincipal"; // This key must be different from "Principal". "Principal" is reserved for Custom mode.
public const string IdentitiesKey = "Identities";
#pragma warning restore 1591
List<ClaimsIdentity> _identityCollection = new List<ClaimsIdentity>();
//
// Add an issuer to specify that this is a IDFx issued AuthorizationPolicy.
//
SysClaimSet _issuer = SysClaimSet.System;
string _id = UniqueId.CreateUniqueId();
/// <summary>
/// Initializes an instance of <see cref="AuthorizationPolicy"/>
/// </summary>
public AuthorizationPolicy()
{
}
/// <summary>
/// Initializes an instance of <see cref="AuthorizationPolicy"/>
/// </summary>
/// <param name="identity">ClaimsIdentity for the AuthorizationPolicy.</param>
/// <exception cref="ArgumentNullException">One of the input argument is null.</exception>
public AuthorizationPolicy(ClaimsIdentity identity)
{
if (identity == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identity");
}
_identityCollection.Add(identity);
}
/// <summary>
/// Initializes an instance of <see cref="AuthorizationPolicy"/>
/// </summary>
/// <param name="identityCollection">Collection of identities.</param>
public AuthorizationPolicy(IEnumerable<ClaimsIdentity> identityCollection)
{
if (identityCollection == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identityCollection");
}
List<ClaimsIdentity> collection = new List<ClaimsIdentity>();
foreach (ClaimsIdentity identity in identityCollection)
{
collection.Add(identity);
}
_identityCollection = collection;
}
/// <summary>
/// Gets a ClaimsIdentity collection.
/// </summary>
public ReadOnlyCollection<ClaimsIdentity> IdentityCollection
{
get
{
return _identityCollection.AsReadOnly();
}
}
#region IAuthorizationPolicy Members
/// <summary>
/// Evaluates the current Policy. This is provided for backward compatibility
/// of WCF Claims model. We always return true without affecting the EvaluationContext.
/// </summary>
/// <param name="evaluationContext">The current EvaluationContext.</param>
/// <param name="state">The reference state object.</param>
/// <returns>True if the Policy was successfully applied.</returns>
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
if (null == evaluationContext || null == evaluationContext.Properties)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("evaluationContext");
}
if (0 == _identityCollection.Count)
{
//
// Nothing to do here.
//
return true;
}
//
// Locate or create the ClaimsPrincipal
//
object principalObj = null;
if (!evaluationContext.Properties.TryGetValue(ClaimsPrincipalKey, out principalObj))
{
ClaimsPrincipal principalToAdd = CreateClaimsPrincipalFromIdentities(_identityCollection);
evaluationContext.Properties.Add(ClaimsPrincipalKey, principalToAdd);
if (DiagnosticUtility.ShouldTrace(TraceEventType.Information))
{
TraceUtility.TraceEvent(
TraceEventType.Information,
TraceCode.Diagnostics,
SR.GetString(SR.TraceSetPrincipalOnEvaluationContext),
new ClaimsPrincipalTraceRecord(principalToAdd),
null,
null);
}
}
else
{
ClaimsPrincipal principal = principalObj as ClaimsPrincipal;
if (null != principal && null != principal.Identities)
{
principal.AddIdentities(_identityCollection);
}
else
{
//
// Someone stomped on our ClaimsPrincipal property key in the properties collection
// Just trace this for now.
//
if (DiagnosticUtility.ShouldTrace(TraceEventType.Error))
{
TraceUtility.TraceString(
TraceEventType.Error,
SR.GetString(SR.ID8004,
ClaimsPrincipalKey));
}
}
}
//
// Locate or create evaluationContext.Properties[ "Identities" ] with identities
//
object identitiesObj = null;
if (!evaluationContext.Properties.TryGetValue(IdentitiesKey, out identitiesObj))
{
List<ClaimsIdentity> identities = new List<ClaimsIdentity>();
foreach (ClaimsIdentity ici in _identityCollection)
{
identities.Add(ici);
}
evaluationContext.Properties.Add(IdentitiesKey, identities);
}
else
{
List<ClaimsIdentity> identities;
identities = identitiesObj as List<ClaimsIdentity>;
foreach (ClaimsIdentity ici in _identityCollection)
{
identities.Add(ici);
}
}
return true;
}
private static ClaimsPrincipal CreateClaimsPrincipalFromIdentities(IEnumerable<ClaimsIdentity> identities)
{
ClaimsIdentity selectedClaimsIdentity = SelectPrimaryIdentity(identities);
if (selectedClaimsIdentity == null)
{
//return an anonymous identity
return new ClaimsPrincipal(new ClaimsIdentity());
}
ClaimsPrincipal principal = CreateFromIdentity(selectedClaimsIdentity);
// Add the remaining identities.
foreach (ClaimsIdentity identity in identities)
{
if (identity != selectedClaimsIdentity)
{
principal.AddIdentity(identity);
}
}
return principal;
}
/// <summary>
/// Creates the appropriate implementation of an IClaimsPrincipal base on the
/// type of the specified IIdentity (e.g. WindowsClaimsPrincipal for a WindowsIdentity).
/// Note the appropriate IClaimsIdentity is generated based on the specified IIdentity
/// as well.
/// </summary>
/// <param name="identity">An implementation of IIdentity</param>
/// <returns>A claims-based principal.</returns>
private static ClaimsPrincipal CreateFromIdentity(IIdentity identity)
{
if (null == identity)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identity");
}
WindowsIdentity wci = identity as WindowsIdentity;
if (null != wci)
{
return new WindowsPrincipal(wci);
}
WindowsIdentity wi = identity as WindowsIdentity;
if (null != wi)
{
return new WindowsPrincipal(wi);
}
ClaimsIdentity ici = identity as ClaimsIdentity;
if (null != ici)
{
return new ClaimsPrincipal(ici);
}
return new ClaimsPrincipal(new ClaimsIdentity(identity));
}
/// <summary>
/// This method iterates through the collection of ClaimsIdentities
/// and determines which identity must be used as the primary one.
/// </summary>
/// <remarks>
/// If the identities collection contains a WindowsClaimsIdentity, it is the most preferred.
/// If the identities collection contains an RsaClaimsIdentity, it is the least preferred.
/// </remarks>
private static ClaimsIdentity SelectPrimaryIdentity(IEnumerable<ClaimsIdentity> identities)
{
if (identities == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("identities");
}
//
// Loop through the identities to determine the primary identity.
//
ClaimsIdentity selectedClaimsIdentity = null;
foreach (ClaimsIdentity identity in identities)
{
if (identity is WindowsIdentity)
{
//
// If there is a WindowsIdentity, return that.
//
selectedClaimsIdentity = identity;
break;
}
else if (identity.FindFirst(ClaimTypes.Rsa) != null)
{
//this is a RSA identity
//it is the least preffered identity
if (selectedClaimsIdentity == null)
{
selectedClaimsIdentity = identity;
}
continue;
}
else if (selectedClaimsIdentity == null)
{
//
// If no primary identity has been selected yet, choose the current identity.
//
selectedClaimsIdentity = identity;
}
}
return selectedClaimsIdentity;
}
/// <summary>
/// Gets the Issuer Claimset. This will return a DefaultClaimSet with just one claim
/// whose ClaimType is http://schemas.microsoft.com/claims/identityclaim.
/// </summary>
public SysClaimSet Issuer
{
get
{
return _issuer;
}
}
#endregion
#region IAuthorizationComponent Members
/// <summary>
/// Returns an Id for the ClaimsPrincipal.
/// </summary>
public string Id
{
get
{
return _id;
}
}
#endregion
}
}
|