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