1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 5 namespace System.ServiceModel.Security.Tokens 6 { 7 using System; 8 using System.Collections.Generic; 9 using System.Collections.ObjectModel; 10 using System.Globalization; 11 using System.IdentityModel.Policy; 12 using System.IdentityModel.Tokens; 13 using System.Xml; 14 15 public class SecurityContextSecurityToken : SecurityToken, TimeBoundedCache.IExpirableItem, IDisposable 16 { 17 byte[] cookieBlob; 18 UniqueId contextId = null; 19 UniqueId keyGeneration = null; 20 DateTime keyEffectiveTime; 21 DateTime keyExpirationTime; 22 DateTime tokenEffectiveTime; 23 DateTime tokenExpirationTime; 24 bool isCookieMode = false; 25 byte[] key; 26 string keyString; 27 ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies; 28 ReadOnlyCollection<SecurityKey> securityKeys; 29 string id; 30 SecurityMessageProperty bootstrapMessageProperty; 31 bool disposed = false; 32 SecurityContextSecurityToken(UniqueId contextId, byte[] key, DateTime validFrom, DateTime validTo)33 public SecurityContextSecurityToken(UniqueId contextId, byte[] key, DateTime validFrom, DateTime validTo) 34 : this(contextId, SecurityUtils.GenerateId(), key, validFrom, validTo) 35 { } 36 SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo)37 public SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo) 38 : this(contextId, id, key, validFrom, validTo, null) 39 { } 40 SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies)41 public SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies) 42 : base() 43 { 44 this.id = id; 45 this.Initialize(contextId, key, validFrom, validTo, authorizationPolicies, false, null, validFrom, validTo); 46 } 47 SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies)48 public SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies) 49 : base() 50 { 51 this.id = id; 52 this.Initialize(contextId, key, validFrom, validTo, authorizationPolicies, false, keyGeneration, keyEffectiveTime, keyExpirationTime); 53 } 54 SecurityContextSecurityToken(SecurityContextSecurityToken sourceToken, string id)55 internal SecurityContextSecurityToken(SecurityContextSecurityToken sourceToken, string id) 56 : this(sourceToken, id, sourceToken.key, sourceToken.keyGeneration, sourceToken.keyEffectiveTime, sourceToken.keyExpirationTime, sourceToken.AuthorizationPolicies) 57 { 58 } 59 SecurityContextSecurityToken(SecurityContextSecurityToken sourceToken, string id, byte[] key, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies)60 internal SecurityContextSecurityToken(SecurityContextSecurityToken sourceToken, string id, byte[] key, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies) 61 : base() 62 { 63 this.id = id; 64 this.Initialize(sourceToken.contextId, key, sourceToken.ValidFrom, sourceToken.ValidTo, authorizationPolicies, sourceToken.isCookieMode, keyGeneration, keyEffectiveTime, keyExpirationTime); 65 this.cookieBlob = sourceToken.cookieBlob; 66 this.bootstrapMessageProperty = (sourceToken.bootstrapMessageProperty == null) ? null : (SecurityMessageProperty)sourceToken.BootstrapMessageProperty.CreateCopy(); 67 } 68 SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode, byte[] cookieBlob)69 internal SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode, byte[] cookieBlob) 70 : this(contextId, id, key, validFrom, validTo, authorizationPolicies, isCookieMode, cookieBlob, null, validFrom, validTo) 71 { 72 } 73 SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode, byte[] cookieBlob, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime)74 internal SecurityContextSecurityToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode, byte[] cookieBlob, 75 UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime) 76 : base() 77 { 78 this.id = id; 79 this.Initialize(contextId, key, validFrom, validTo, authorizationPolicies, isCookieMode, keyGeneration, keyEffectiveTime, keyExpirationTime); 80 this.cookieBlob = cookieBlob; 81 } 82 SecurityContextSecurityToken(SecurityContextSecurityToken from)83 SecurityContextSecurityToken(SecurityContextSecurityToken from) 84 { 85 ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies = System.IdentityModel.SecurityUtils.CloneAuthorizationPoliciesIfNecessary(from.authorizationPolicies); 86 this.id = from.id; 87 this.Initialize(from.contextId, from.key, from.tokenEffectiveTime, from.tokenExpirationTime, authorizationPolicies, from.isCookieMode, from.keyGeneration, from.keyEffectiveTime, from.keyExpirationTime); 88 this.cookieBlob = from.cookieBlob; 89 this.bootstrapMessageProperty = (from.bootstrapMessageProperty == null) ? null : (SecurityMessageProperty)from.BootstrapMessageProperty.CreateCopy(); 90 } 91 92 /// <summary> 93 /// Gets or Sets the SecurityMessageProperty extracted from 94 /// the Bootstrap message. This will contain the original tokens 95 /// that the client used to Authenticate with the service. By 96 /// default, this is turned off. To turn this feature on, add a custom 97 /// ServiceCredentialsSecurityTokenManager and override 98 /// CreateSecurityTokenManager. Create the SecurityContextToken Authenticator by calling 99 /// ServiceCredentialsSecurityTokenManager.CreateSecureConversationTokenAuthenticator 100 /// with 'preserveBootstrapTokens' parameter to true. 101 /// If there are any UserNameSecurityToken in the bootstrap message, the password in 102 /// these tokens will be removed. When 'Cookie' mode SCT is enabled the BootstrapMessageProperty 103 /// is not preserved in the Cookie. To preserve the bootstrap tokens in the CookieMode case 104 /// write a custom Serializer and serialize the property as part of the cookie. 105 /// </summary> 106 public SecurityMessageProperty BootstrapMessageProperty 107 { 108 get 109 { 110 return this.bootstrapMessageProperty; 111 } 112 set 113 { 114 this.bootstrapMessageProperty = value; 115 } 116 } 117 118 public override string Id 119 { 120 get { return this.id; } 121 } 122 123 public UniqueId ContextId 124 { 125 get 126 { 127 return this.contextId; 128 } 129 } 130 131 public UniqueId KeyGeneration 132 { 133 get 134 { 135 return this.keyGeneration; 136 } 137 } 138 139 public DateTime KeyEffectiveTime 140 { 141 get 142 { 143 return this.keyEffectiveTime; 144 } 145 } 146 147 public DateTime KeyExpirationTime 148 { 149 get 150 { 151 return this.keyExpirationTime; 152 } 153 } 154 155 public ReadOnlyCollection<IAuthorizationPolicy> AuthorizationPolicies 156 { 157 get 158 { 159 ThrowIfDisposed(); 160 return this.authorizationPolicies; 161 } 162 163 internal set 164 { 165 this.authorizationPolicies = value; 166 } 167 } 168 169 public override ReadOnlyCollection<SecurityKey> SecurityKeys 170 { 171 get 172 { 173 return this.securityKeys; 174 } 175 } 176 177 public override DateTime ValidFrom 178 { 179 get { return this.tokenEffectiveTime; } 180 } 181 182 public override DateTime ValidTo 183 { 184 get { return this.tokenExpirationTime; } 185 } 186 187 internal byte[] CookieBlob 188 { 189 get 190 { 191 return this.cookieBlob; 192 } 193 } 194 195 /// <summary> 196 /// This is set by the issuer when creating the SCT to be sent in the RSTR 197 /// The SecurityContextTokenManager examines this property to determine how to write 198 /// out the SCT 199 /// This field is set to true when the issuer reads in a cookie mode SCT 200 /// </summary> 201 public bool IsCookieMode 202 { 203 get 204 { 205 return this.isCookieMode; 206 } 207 } 208 209 DateTime TimeBoundedCache.IExpirableItem.ExpirationTime 210 { 211 get 212 { 213 return this.ValidTo; 214 } 215 } 216 GetBase64KeyString()217 internal string GetBase64KeyString() 218 { 219 if (this.keyString == null) 220 { 221 this.keyString = Convert.ToBase64String(this.key); 222 } 223 return this.keyString; 224 } 225 GetKeyBytes()226 internal byte[] GetKeyBytes() 227 { 228 byte[] retval = new byte[this.key.Length]; 229 Buffer.BlockCopy(this.key, 0, retval, 0, this.key.Length); 230 return retval; 231 } 232 ToString()233 public override string ToString() 234 { 235 return String.Format(CultureInfo.CurrentCulture, "SecurityContextSecurityToken(Identifier='{0}', KeyGeneration='{1}')", this.contextId, this.keyGeneration); 236 } 237 Initialize(UniqueId contextId, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime)238 void Initialize(UniqueId contextId, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode, 239 UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime) 240 { 241 if (contextId == null) 242 { 243 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextId"); 244 } 245 246 if (key == null || key.Length == 0) 247 { 248 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("key"); 249 } 250 251 DateTime tokenEffectiveTimeUtc = validFrom.ToUniversalTime(); 252 DateTime tokenExpirationTimeUtc = validTo.ToUniversalTime(); 253 if (tokenEffectiveTimeUtc > tokenExpirationTimeUtc) 254 { 255 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("validFrom", SR.GetString(SR.EffectiveGreaterThanExpiration)); 256 } 257 this.tokenEffectiveTime = tokenEffectiveTimeUtc; 258 this.tokenExpirationTime = tokenExpirationTimeUtc; 259 260 this.keyEffectiveTime = keyEffectiveTime.ToUniversalTime(); 261 this.keyExpirationTime = keyExpirationTime.ToUniversalTime(); 262 if (this.keyEffectiveTime > this.keyExpirationTime) 263 { 264 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("keyEffectiveTime", SR.GetString(SR.EffectiveGreaterThanExpiration)); 265 } 266 if ((this.keyEffectiveTime < tokenEffectiveTimeUtc) || (this.keyExpirationTime > tokenExpirationTimeUtc)) 267 { 268 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.KeyLifetimeNotWithinTokenLifetime)); 269 } 270 271 this.key = new byte[key.Length]; 272 Buffer.BlockCopy(key, 0, this.key, 0, key.Length); 273 this.contextId = contextId; 274 this.keyGeneration = keyGeneration; 275 this.authorizationPolicies = authorizationPolicies ?? EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance; 276 List<SecurityKey> temp = new List<SecurityKey>(1); 277 temp.Add(new InMemorySymmetricSecurityKey(this.key, false)); 278 this.securityKeys = temp.AsReadOnly(); 279 this.isCookieMode = isCookieMode; 280 } 281 CanCreateKeyIdentifierClause()282 public override bool CanCreateKeyIdentifierClause<T>() 283 { 284 if (typeof(T) == typeof(SecurityContextKeyIdentifierClause)) 285 return true; 286 287 return base.CanCreateKeyIdentifierClause<T>(); 288 } 289 CreateKeyIdentifierClause()290 public override T CreateKeyIdentifierClause<T>() 291 { 292 if (typeof(T) == typeof(SecurityContextKeyIdentifierClause)) 293 return new SecurityContextKeyIdentifierClause(this.contextId, this.keyGeneration) as T; 294 295 return base.CreateKeyIdentifierClause<T>(); 296 } 297 MatchesKeyIdentifierClause(SecurityKeyIdentifierClause keyIdentifierClause)298 public override bool MatchesKeyIdentifierClause(SecurityKeyIdentifierClause keyIdentifierClause) 299 { 300 SecurityContextKeyIdentifierClause sctKeyIdentifierClause = keyIdentifierClause as SecurityContextKeyIdentifierClause; 301 if (sctKeyIdentifierClause != null) 302 return sctKeyIdentifierClause.Matches(this.contextId, this.keyGeneration); 303 304 return base.MatchesKeyIdentifierClause(keyIdentifierClause); 305 } 306 CreateCookieSecurityContextToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, SecurityStateEncoder securityStateEncoder)307 public static SecurityContextSecurityToken CreateCookieSecurityContextToken(UniqueId contextId, string id, byte[] key, 308 DateTime validFrom, DateTime validTo, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, SecurityStateEncoder securityStateEncoder) 309 { 310 return CreateCookieSecurityContextToken(contextId, id, key, validFrom, validTo, null, validFrom, validTo, authorizationPolicies, securityStateEncoder); 311 } 312 313 CreateCookieSecurityContextToken(UniqueId contextId, string id, byte[] key, DateTime validFrom, DateTime validTo, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, SecurityStateEncoder securityStateEncoder)314 public static SecurityContextSecurityToken CreateCookieSecurityContextToken(UniqueId contextId, string id, byte[] key, 315 DateTime validFrom, DateTime validTo, UniqueId keyGeneration, DateTime keyEffectiveTime, 316 DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, SecurityStateEncoder securityStateEncoder) 317 { 318 SecurityContextCookieSerializer cookieSerializer = new SecurityContextCookieSerializer(securityStateEncoder, null); 319 byte[] cookieBlob = cookieSerializer.CreateCookieFromSecurityContext(contextId, id, key, validFrom, validTo, keyGeneration, 320 keyEffectiveTime, keyExpirationTime, authorizationPolicies); 321 322 return new SecurityContextSecurityToken(contextId, id, key, validFrom, validTo, 323 authorizationPolicies, true, cookieBlob, keyGeneration, keyEffectiveTime, keyExpirationTime); 324 } 325 Clone()326 internal SecurityContextSecurityToken Clone() 327 { 328 ThrowIfDisposed(); 329 return new SecurityContextSecurityToken(this); 330 } 331 Dispose()332 public void Dispose() 333 { 334 if (!this.disposed) 335 { 336 this.disposed = true; 337 System.IdentityModel.SecurityUtils.DisposeAuthorizationPoliciesIfNecessary(this.authorizationPolicies); 338 if (this.bootstrapMessageProperty != null) 339 { 340 this.bootstrapMessageProperty.Dispose(); 341 } 342 } 343 } 344 ThrowIfDisposed()345 void ThrowIfDisposed() 346 { 347 if (this.disposed) 348 { 349 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(this.GetType().FullName)); 350 } 351 } 352 } 353 } 354