1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 namespace System.ServiceModel.Security.Tokens 5 { 6 using System.Collections.Generic; 7 using System.Collections.ObjectModel; 8 using System.IdentityModel.Claims; 9 using System.IdentityModel.Policy; 10 using System.IO; 11 using System.Runtime; 12 using System.Runtime.Serialization; 13 using System.Security.Principal; 14 using System.ServiceModel; 15 using System.ServiceModel.Dispatcher; 16 using System.Xml; 17 18 struct SecurityContextCookieSerializer 19 { 20 const int SupportedPersistanceVersion = 1; 21 22 SecurityStateEncoder securityStateEncoder; 23 IList<Type> knownTypes; 24 SecurityContextCookieSerializerSystem.ServiceModel.Security.Tokens.SecurityContextCookieSerializer25 public SecurityContextCookieSerializer(SecurityStateEncoder securityStateEncoder, IList<Type> knownTypes) 26 { 27 if (securityStateEncoder == null) 28 { 29 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityStateEncoder"); 30 } 31 this.securityStateEncoder = securityStateEncoder; 32 this.knownTypes = knownTypes ?? new List<Type>(); 33 } 34 DeserializeContextSystem.ServiceModel.Security.Tokens.SecurityContextCookieSerializer35 SecurityContextSecurityToken DeserializeContext(byte[] serializedContext, byte[] cookieBlob, string id, XmlDictionaryReaderQuotas quotas) 36 { 37 SctClaimDictionary dictionary = SctClaimDictionary.Instance; 38 XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(serializedContext, 0, serializedContext.Length, dictionary, quotas, null, null); 39 int cookieVersion = -1; 40 UniqueId cookieContextId = null; 41 DateTime effectiveTime = SecurityUtils.MinUtcDateTime; 42 DateTime expiryTime = SecurityUtils.MaxUtcDateTime; 43 byte[] key = null; 44 string localId = null; 45 UniqueId keyGeneration = null; 46 DateTime keyEffectiveTime = SecurityUtils.MinUtcDateTime; 47 DateTime keyExpirationTime = SecurityUtils.MaxUtcDateTime; 48 List<ClaimSet> claimSets = null; 49 IList<IIdentity> identities = null; 50 bool isCookie = true; 51 52 reader.ReadFullStartElement(dictionary.SecurityContextSecurityToken, dictionary.EmptyString); 53 54 while (reader.IsStartElement()) 55 { 56 if (reader.IsStartElement(dictionary.Version, dictionary.EmptyString)) 57 { 58 cookieVersion = reader.ReadElementContentAsInt(); 59 } 60 else if (reader.IsStartElement(dictionary.ContextId, dictionary.EmptyString)) 61 { 62 cookieContextId = reader.ReadElementContentAsUniqueId(); 63 } 64 else if (reader.IsStartElement(dictionary.Id, dictionary.EmptyString)) 65 { 66 localId = reader.ReadElementContentAsString(); 67 } 68 else if (reader.IsStartElement(dictionary.EffectiveTime, dictionary.EmptyString)) 69 { 70 effectiveTime = new DateTime(XmlHelper.ReadElementContentAsInt64(reader), DateTimeKind.Utc); 71 } 72 else if (reader.IsStartElement(dictionary.ExpiryTime, dictionary.EmptyString)) 73 { 74 expiryTime = new DateTime(XmlHelper.ReadElementContentAsInt64(reader), DateTimeKind.Utc); 75 } 76 else if (reader.IsStartElement(dictionary.Key, dictionary.EmptyString)) 77 { 78 key = reader.ReadElementContentAsBase64(); 79 } 80 else if (reader.IsStartElement(dictionary.KeyGeneration, dictionary.EmptyString)) 81 { 82 keyGeneration = reader.ReadElementContentAsUniqueId(); 83 } 84 else if (reader.IsStartElement(dictionary.KeyEffectiveTime, dictionary.EmptyString)) 85 { 86 keyEffectiveTime = new DateTime(XmlHelper.ReadElementContentAsInt64(reader), DateTimeKind.Utc); 87 } 88 else if (reader.IsStartElement(dictionary.KeyExpiryTime, dictionary.EmptyString)) 89 { 90 keyExpirationTime = new DateTime(XmlHelper.ReadElementContentAsInt64(reader), DateTimeKind.Utc); 91 } 92 else if (reader.IsStartElement(dictionary.Identities, dictionary.EmptyString)) 93 { 94 identities = SctClaimSerializer.DeserializeIdentities(reader, dictionary, DataContractSerializerDefaults.CreateSerializer(typeof(IIdentity), this.knownTypes, int.MaxValue)); 95 } 96 else if (reader.IsStartElement(dictionary.ClaimSets, dictionary.EmptyString)) 97 { 98 reader.ReadStartElement(); 99 100 DataContractSerializer claimSetSerializer = DataContractSerializerDefaults.CreateSerializer(typeof(ClaimSet), this.knownTypes, int.MaxValue); 101 DataContractSerializer claimSerializer = DataContractSerializerDefaults.CreateSerializer(typeof(Claim), this.knownTypes, int.MaxValue); 102 claimSets = new List<ClaimSet>(1); 103 while (reader.IsStartElement()) 104 { 105 claimSets.Add(SctClaimSerializer.DeserializeClaimSet(reader, dictionary, claimSetSerializer, claimSerializer)); 106 } 107 108 reader.ReadEndElement(); 109 } 110 else if (reader.IsStartElement(dictionary.IsCookieMode, dictionary.EmptyString)) 111 { 112 isCookie = reader.ReadElementString() == "1" ? true : false; 113 } 114 else 115 { 116 OnInvalidCookieFailure(SR.GetString(SR.SctCookieXmlParseError)); 117 } 118 } 119 reader.ReadEndElement(); 120 if (cookieVersion != SupportedPersistanceVersion) 121 { 122 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SerializedTokenVersionUnsupported, cookieVersion))); 123 } 124 if (cookieContextId == null) 125 { 126 OnInvalidCookieFailure(SR.GetString(SR.SctCookieValueMissingOrIncorrect, "ContextId")); 127 } 128 if (key == null || key.Length == 0) 129 { 130 OnInvalidCookieFailure(SR.GetString(SR.SctCookieValueMissingOrIncorrect, "Key")); 131 } 132 if (localId != id) 133 { 134 OnInvalidCookieFailure(SR.GetString(SR.SctCookieValueMissingOrIncorrect, "Id")); 135 } 136 List<IAuthorizationPolicy> authorizationPolicies; 137 if (claimSets != null) 138 { 139 authorizationPolicies = new List<IAuthorizationPolicy>(1); 140 authorizationPolicies.Add(new SctUnconditionalPolicy(identities, claimSets, expiryTime)); 141 } 142 else 143 { 144 authorizationPolicies = null; 145 } 146 return new SecurityContextSecurityToken(cookieContextId, localId, key, effectiveTime, expiryTime, 147 authorizationPolicies != null ? authorizationPolicies.AsReadOnly() : null, isCookie, cookieBlob, keyGeneration, keyEffectiveTime, keyExpirationTime); 148 } 149 CreateCookieFromSecurityContextSystem.ServiceModel.Security.Tokens.SecurityContextCookieSerializer150 public byte[] CreateCookieFromSecurityContext(UniqueId contextId, string id, byte[] key, DateTime tokenEffectiveTime, 151 DateTime tokenExpirationTime, UniqueId keyGeneration, DateTime keyEffectiveTime, DateTime keyExpirationTime, 152 ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies) 153 { 154 if (contextId == null) 155 { 156 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contextId"); 157 } 158 159 if (key == null) 160 { 161 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("key"); 162 } 163 164 MemoryStream stream = new MemoryStream(); 165 XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, SctClaimDictionary.Instance, null); 166 167 SctClaimDictionary dictionary = SctClaimDictionary.Instance; 168 writer.WriteStartElement(dictionary.SecurityContextSecurityToken, dictionary.EmptyString); 169 writer.WriteStartElement(dictionary.Version, dictionary.EmptyString); 170 writer.WriteValue(SupportedPersistanceVersion); 171 writer.WriteEndElement(); 172 if (id != null) 173 writer.WriteElementString(dictionary.Id, dictionary.EmptyString, id); 174 XmlHelper.WriteElementStringAsUniqueId(writer, dictionary.ContextId, dictionary.EmptyString, contextId); 175 176 writer.WriteStartElement(dictionary.Key, dictionary.EmptyString); 177 writer.WriteBase64(key, 0, key.Length); 178 writer.WriteEndElement(); 179 180 if (keyGeneration != null) 181 { 182 XmlHelper.WriteElementStringAsUniqueId(writer, dictionary.KeyGeneration, dictionary.EmptyString, keyGeneration); 183 } 184 185 XmlHelper.WriteElementContentAsInt64(writer, dictionary.EffectiveTime, dictionary.EmptyString, tokenEffectiveTime.ToUniversalTime().Ticks); 186 XmlHelper.WriteElementContentAsInt64(writer, dictionary.ExpiryTime, dictionary.EmptyString, tokenExpirationTime.ToUniversalTime().Ticks); 187 XmlHelper.WriteElementContentAsInt64(writer, dictionary.KeyEffectiveTime, dictionary.EmptyString, keyEffectiveTime.ToUniversalTime().Ticks); 188 XmlHelper.WriteElementContentAsInt64(writer, dictionary.KeyExpiryTime, dictionary.EmptyString, keyExpirationTime.ToUniversalTime().Ticks); 189 190 AuthorizationContext authContext = null; 191 if (authorizationPolicies != null) 192 authContext = AuthorizationContext.CreateDefaultAuthorizationContext(authorizationPolicies); 193 194 if (authContext != null && authContext.ClaimSets.Count != 0) 195 { 196 DataContractSerializer identitySerializer = DataContractSerializerDefaults.CreateSerializer(typeof(IIdentity), this.knownTypes, int.MaxValue); 197 DataContractSerializer claimSetSerializer = DataContractSerializerDefaults.CreateSerializer(typeof(ClaimSet), this.knownTypes, int.MaxValue); 198 DataContractSerializer claimSerializer = DataContractSerializerDefaults.CreateSerializer(typeof(Claim), this.knownTypes, int.MaxValue); 199 SctClaimSerializer.SerializeIdentities(authContext, dictionary, writer, identitySerializer); 200 201 writer.WriteStartElement(dictionary.ClaimSets, dictionary.EmptyString); 202 for (int i = 0; i < authContext.ClaimSets.Count; i++) 203 { 204 SctClaimSerializer.SerializeClaimSet(authContext.ClaimSets[i], dictionary, writer, claimSetSerializer, claimSerializer); 205 } 206 writer.WriteEndElement(); 207 } 208 209 writer.WriteEndElement(); 210 writer.Flush(); 211 212 byte[] serializedContext = stream.ToArray(); 213 return this.securityStateEncoder.EncodeSecurityState(serializedContext); 214 } 215 216 CreateSecurityContextFromCookieSystem.ServiceModel.Security.Tokens.SecurityContextCookieSerializer217 public SecurityContextSecurityToken CreateSecurityContextFromCookie(byte[] encodedCookie, UniqueId contextId, UniqueId generation, string id, XmlDictionaryReaderQuotas quotas) 218 { 219 byte[] cookie = null; 220 221 try 222 { 223 cookie = this.securityStateEncoder.DecodeSecurityState(encodedCookie); 224 } 225 catch (Exception e) 226 { 227 if (Fx.IsFatal(e)) 228 { 229 throw; 230 } 231 OnInvalidCookieFailure(SR.GetString(SR.SctCookieBlobDecodeFailure), e); 232 } 233 SecurityContextSecurityToken sct = DeserializeContext(cookie, encodedCookie, id, quotas); 234 if (sct.ContextId != contextId) 235 { 236 OnInvalidCookieFailure(SR.GetString(SR.SctCookieValueMissingOrIncorrect, "ContextId")); 237 } 238 if (sct.KeyGeneration != generation) 239 { 240 OnInvalidCookieFailure(SR.GetString(SR.SctCookieValueMissingOrIncorrect, "KeyGeneration")); 241 } 242 243 return sct; 244 } 245 OnInvalidCookieFailureSystem.ServiceModel.Security.Tokens.SecurityContextCookieSerializer246 internal static void OnInvalidCookieFailure(string reason) 247 { 248 OnInvalidCookieFailure(reason, null); 249 } 250 OnInvalidCookieFailureSystem.ServiceModel.Security.Tokens.SecurityContextCookieSerializer251 internal static void OnInvalidCookieFailure(string reason, Exception e) 252 { 253 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.InvalidSecurityContextCookie, reason), e)); 254 } 255 256 class SctUnconditionalPolicy : IAuthorizationPolicy 257 { 258 SecurityUniqueId id = SecurityUniqueId.Create(); 259 IList<IIdentity> identities; 260 IList<ClaimSet> claimSets; 261 DateTime expirationTime; 262 SctUnconditionalPolicy(IList<IIdentity> identities, IList<ClaimSet> claimSets, DateTime expirationTime)263 public SctUnconditionalPolicy(IList<IIdentity> identities, IList<ClaimSet> claimSets, DateTime expirationTime) 264 { 265 this.identities = identities; 266 this.claimSets = claimSets; 267 this.expirationTime = expirationTime; 268 } 269 270 public string Id 271 { 272 get { return this.id.Value; } 273 } 274 275 public ClaimSet Issuer 276 { 277 get { return ClaimSet.System; } 278 } 279 Evaluate(EvaluationContext evaluationContext, ref object state)280 public bool Evaluate(EvaluationContext evaluationContext, ref object state) 281 { 282 for (int i = 0; i < this.claimSets.Count; ++i) 283 { 284 evaluationContext.AddClaimSet(this, this.claimSets[i]); 285 } 286 287 if (this.identities != null) 288 { 289 object obj; 290 if (!evaluationContext.Properties.TryGetValue(SecurityUtils.Identities, out obj)) 291 { 292 evaluationContext.Properties.Add(SecurityUtils.Identities, this.identities); 293 } 294 else 295 { 296 // null if other overrides the property with something else 297 List<IIdentity> dstIdentities = obj as List<IIdentity>; 298 if (dstIdentities != null) 299 { 300 dstIdentities.AddRange(this.identities); 301 } 302 } 303 } 304 evaluationContext.RecordExpirationTime(this.expirationTime); 305 return true; 306 } 307 } 308 } 309 } 310