1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.IdentityModel
6 {
7     using System;
8     using System.IdentityModel.Tokens;
9     using System.Security.Claims;
10     using RST = System.IdentityModel.Protocols.WSTrust.RequestSecurityToken;
11     using RSTR = System.IdentityModel.Protocols.WSTrust.RequestSecurityTokenResponse;
12     using System.IdentityModel.Protocols.WSTrust;
13     using System.IdentityModel.Configuration;
14 
15     /// <summary>
16     /// Abstract class for building WS-Security token services.
17     /// </summary>
18     public abstract class SecurityTokenService
19     {
20         /// <summary>
21         /// This class is used to maintain request state across asynchronous calls
22         /// within the security token service.
23         /// </summary>
24         protected class FederatedAsyncState
25         {
26             RST _request;
27             ClaimsPrincipal _claimsPrincipal;
28             SecurityTokenHandler _securityTokenHandler;
29             IAsyncResult _result;
30 
31             /// <summary>
32             /// Copy constructor.
33             /// </summary>
34             /// <param name="federatedAsyncState">The input FederatedAsyncState instance.</param>
35             /// <exception cref="ArgumentNullException">The input 'FederatedAsyncState' is null.</exception>
FederatedAsyncState(FederatedAsyncState federatedAsyncState)36             public FederatedAsyncState(FederatedAsyncState federatedAsyncState)
37             {
38                 if (null == federatedAsyncState)
39                 {
40                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("FederatedAsyncState");
41                 }
42 
43                 _request = federatedAsyncState.Request;
44                 _claimsPrincipal = federatedAsyncState.ClaimsPrincipal;
45                 _securityTokenHandler = federatedAsyncState.SecurityTokenHandler;
46                 _result = federatedAsyncState.Result;
47             }
48 
49             /// <summary>
50             /// Constructs a FederatedAsyncState instance with token request, principal, and the async result.
51             /// </summary>
52             /// <param name="request">The token request instance.</param>
53             /// <param name="principal">The identity of the token requestor.</param>
54             /// <param name="result">The async result.</param>
55             /// <exception cref="ArgumentNullException">When the given request or async result is null.</exception>
FederatedAsyncState(RST request, ClaimsPrincipal principal, IAsyncResult result)56             public FederatedAsyncState(RST request, ClaimsPrincipal principal, IAsyncResult result)
57             {
58                 if (null == request)
59                 {
60                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
61                 }
62 
63                 if (null == result)
64                 {
65                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
66                 }
67 
68                 _request = request;
69                 _claimsPrincipal = principal;
70                 _result = result;
71             }
72 
73             /// <summary>
74             /// Gets the token request instance.
75             /// </summary>
76             public RST Request
77             {
78                 get
79                 {
80                     return _request;
81                 }
82             }
83 
84             /// <summary>
85             /// Gets the ClaimsPrincipal instance.
86             /// </summary>
87             public ClaimsPrincipal ClaimsPrincipal
88             {
89                 get
90                 {
91                     return _claimsPrincipal;
92                 }
93             }
94 
95             /// <summary>
96             /// Gets or sets the SecurityTokenHandler to be used during an async token-issuance call.
97             /// </summary>
98             public SecurityTokenHandler SecurityTokenHandler
99             {
100                 get { return _securityTokenHandler; }
101                 set { _securityTokenHandler = value; }
102             }
103 
104             /// <summary>
105             /// Gets the async result.
106             /// </summary>
107             public IAsyncResult Result
108             {
109                 get
110                 {
111                     return _result;
112                 }
113             }
114         }
115 
116         //
117         // STS settings
118         //
119         SecurityTokenServiceConfiguration _securityTokenServiceConfiguration;
120 
121         ClaimsPrincipal _principal;
122         RequestSecurityToken _request;
123         SecurityTokenDescriptor _tokenDescriptor;
124 
125         /// <summary>
126         /// Use this constructor to initialize scope provider and token issuer certificate.
127         /// </summary>
128         /// <param name="securityTokenServiceConfiguration">The SecurityTokenServiceConfiguration that will have the related settings for the STS.</param>
SecurityTokenService(SecurityTokenServiceConfiguration securityTokenServiceConfiguration)129         protected SecurityTokenService(SecurityTokenServiceConfiguration securityTokenServiceConfiguration)
130         {
131             if (securityTokenServiceConfiguration == null)
132             {
133                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenServiceConfiguration");
134             }
135 
136             _securityTokenServiceConfiguration = securityTokenServiceConfiguration;
137         }
138 
139         /// <summary>
140         /// Async Cancel.
141         /// </summary>
142         /// <param name="principal">The identity of the token requestor.</param>
143         /// <param name="request">The security token request which includes request message as well as other client
144         /// related information such as authorization context.</param>
145         /// <param name="callback">The async call back.</param>
146         /// <param name="state">The state object.</param>
147         /// <returns>The async result.</returns>
BeginCancel(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)148         public virtual IAsyncResult BeginCancel(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)
149         {
150             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, (request != null ? request.RequestType : "Cancel"))));
151         }
152 
153         /// <summary>
154         /// Begins async call for GetScope routine. Default implementation will throw a NotImplementedExcetion.
155         /// Refer MSDN articles on Using an AsyncCallback Delegate to End an Asynchronous Operation.
156         /// </summary>
157         /// <param name="principal">The identity of the token requestor.</param>
158         /// <param name="request">The request.</param>
159         /// <param name="callback">The callback to be invoked when the user Asynchronous operation completed.</param>
160         /// <param name="state">The state object.</param>
161         /// <returns>IAsyncResult. Represents the status of an asynchronous operation. This will be passed into
162         /// EndGetScope.</returns>
BeginGetScope(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)163         protected virtual IAsyncResult BeginGetScope(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)
164         {
165             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.ID2081)));
166         }
167 
168         /// <summary>
169         /// Begins the async call of the Issue request.
170         /// </summary>
171         /// <param name="principal">The <see cref="ClaimsPrincipal"/> to issue a token for.</param>
172         /// <param name="request">The security token request which includes request message as well as other client
173         /// related information such as authorization context.</param>
174         /// <param name="callback">The async call back.</param>
175         /// <param name="state">The state object.</param>
176         /// <returns>The async result.</returns>
BeginIssue(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)177         public virtual IAsyncResult BeginIssue(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)
178         {
179             if (request == null)
180             {
181                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
182             }
183             _principal = principal;
184             _request = request;
185 
186             //
187             // Step 1: Validate the rst: check if this STS is capable of handling this
188             // rst
189             //
190             ValidateRequest(request);
191 
192             //
193             //
194 
195 
196 
197             FederatedAsyncState asyncState = new FederatedAsyncState(request, principal, new TypedAsyncResult<RSTR>(callback, state));
198 
199             BeginGetScope(principal, request, OnGetScopeComplete, asyncState);
200 
201             return asyncState.Result;
202         }
203 
204         /// <summary>
205         /// Async Renew.
206         /// </summary>
207         /// <param name="principal">The <see cref="ClaimsPrincipal"/> to renew.</param>
208         /// <param name="request">The security token request which includes request message as well as other client
209         /// related information such as authorization context.</param>
210         /// <param name="callback">The async call back.</param>
211         /// <param name="state">The state object.</param>
212         /// <returns>The async result.</returns>
BeginRenew(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)213         public virtual IAsyncResult BeginRenew(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)
214         {
215             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, (request != null && request.RequestType != null ? request.RequestType : "Renew"))));
216         }
217 
218         /// <summary>
219         /// Async Validate.
220         /// </summary>
221         /// <param name="principal">The <see cref="ClaimsPrincipal"/> to validate.</param>
222         /// <param name="request">The security token request which includes request message as well as other client
223         /// related information such as authorization context.</param>
224         /// <param name="callback">The async call back.</param>
225         /// <param name="state">The state object.</param>
226         /// <returns>The async result.</returns>
BeginValidate(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)227         public virtual IAsyncResult BeginValidate(ClaimsPrincipal principal, RST request, AsyncCallback callback, object state)
228         {
229             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, (request != null && request.RequestType != null ? request.RequestType : "Validate"))));
230         }
231 
232         /// <summary>
233         /// Cancel.
234         /// </summary>
235         /// <param name="principal">The <see cref="ClaimsPrincipal"/> to cancel.</param>
236         /// <param name="request">The request.</param>
237         /// <returns>The response.</returns>
Cancel(ClaimsPrincipal principal, RST request)238         public virtual RSTR Cancel(ClaimsPrincipal principal, RST request)
239         {
240             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, (request != null && request.RequestType != null ? request.RequestType : "Cancel"))));
241         }
242 
243         /// <summary>
244         /// Creates an instance of a <see cref="SecurityTokenDescriptor"/>.
245         /// </summary>
246         /// <param name="request">The incoming token request.</param>
247         /// <param name="scope">The <see cref="Scope"/> object returned from <see cref="SecurityTokenService.GetScope"/>.</param>
248         /// <returns>The <see cref="SecurityTokenDescriptor"/>.</returns>
249         /// <remarks>Invoked during token issuance after <see cref="SecurityTokenService.GetScope"/>.</remarks>
CreateSecurityTokenDescriptor(RST request, Scope scope)250         protected virtual SecurityTokenDescriptor CreateSecurityTokenDescriptor(RST request, Scope scope)
251         {
252             if (request == null)
253             {
254                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
255             }
256 
257             if (scope == null)
258             {
259                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("scope");
260             }
261 
262             SecurityTokenDescriptor d = new SecurityTokenDescriptor();
263             d.AppliesToAddress = scope.AppliesToAddress;
264             d.ReplyToAddress = scope.ReplyToAddress;
265             d.SigningCredentials = scope.SigningCredentials;
266             if (null == d.SigningCredentials)
267             {
268                 d.SigningCredentials = this.SecurityTokenServiceConfiguration.SigningCredentials;
269             }
270 
271 
272 
273             //
274             // The encrypting credentials specified on the Scope object
275             // are invariant relative to a specific RP. Allowing the STS to
276             // cache the Scope for each RP.
277             // Our default implementation will generate the symmetric bulk
278             // encryption key on the fly.
279             //
280             if (scope.EncryptingCredentials != null &&
281                  scope.EncryptingCredentials.SecurityKey is AsymmetricSecurityKey
282                  )
283             {
284                 if ((request.EncryptionAlgorithm == null || request.EncryptionAlgorithm == SecurityAlgorithms.Aes256Encryption) &&
285                     (request.SecondaryParameters == null || request.SecondaryParameters.EncryptionAlgorithm == null || request.SecondaryParameters.EncryptionAlgorithm == SecurityAlgorithms.Aes256Encryption)
286                     )
287                 {
288                     d.EncryptingCredentials = new EncryptedKeyEncryptingCredentials(scope.EncryptingCredentials, 256, SecurityAlgorithms.Aes256Encryption);
289                 }
290             }
291 
292             return d;
293         }
294 
295         /// <summary>
296         /// Gets the STS's name.
297         /// </summary>
298         /// <returns>Returns the issuer name.</returns>
GetIssuerName()299         protected virtual string GetIssuerName()
300         {
301             return SecurityTokenServiceConfiguration.TokenIssuerName;
302         }
303 
304         /// <summary>
305         /// Checks the IssuerName for validity (non-null)
306         /// </summary>
GetValidIssuerName()307         private string GetValidIssuerName()
308         {
309             string issuerName = GetIssuerName();
310 
311             if (string.IsNullOrEmpty(issuerName))
312             {
313                 throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2083));
314             }
315 
316             return issuerName;
317         }
318 
319         /// <summary>
320         /// Gets the proof token.
321         /// </summary>
322         /// <param name="request">The incoming token request.</param>
323         /// <param name="scope">The scope instance encapsulating information about the relying party.</param>
324         /// <returns>The newly created proof decriptor that could be either asymmetric proof descriptor or symmetric proof descriptor or null in the bearer token case.</returns>
GetProofToken(RST request, Scope scope)325         protected virtual ProofDescriptor GetProofToken(RST request, Scope scope)
326         {
327             if (request == null)
328             {
329                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
330             }
331 
332             if (scope == null)
333             {
334                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("scope");
335             }
336 
337             EncryptingCredentials requestorWrappingCredentials = GetRequestorProofEncryptingCredentials(request);
338 
339             if (scope.EncryptingCredentials != null &&
340                   !(scope.EncryptingCredentials.SecurityKey is AsymmetricSecurityKey))
341             {
342                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
343                                     new SecurityTokenException(SR.GetString(SR.ID4179)));
344             }
345 
346             EncryptingCredentials targetWrappingCredentials = scope.EncryptingCredentials;
347 
348             //
349             // Generate the proof key
350             //
351             string keyType = (string.IsNullOrEmpty(request.KeyType)) ? KeyTypes.Symmetric : request.KeyType;
352             ProofDescriptor result = null;
353 
354             if (StringComparer.Ordinal.Equals(keyType, KeyTypes.Asymmetric))
355             {
356                 //
357                 // Asymmetric is only supported with UseKey
358                 //
359                 if (request.UseKey == null)
360                 {
361                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3091)));
362                 }
363 
364                 result = new AsymmetricProofDescriptor(request.UseKey.SecurityKeyIdentifier);
365             }
366             else if (StringComparer.Ordinal.Equals(keyType, KeyTypes.Symmetric))
367             {
368                 //
369                 // Only support PSHA1. Overwrite STS to support custom key algorithm
370                 //
371                 if (request.ComputedKeyAlgorithm != null && !StringComparer.Ordinal.Equals(request.ComputedKeyAlgorithm, ComputedKeyAlgorithms.Psha1))
372                 {
373                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new RequestFailedException(SR.GetString(SR.ID2011, request.ComputedKeyAlgorithm)));
374                 }
375                 //
376                 // We must wrap the symmetric key inside the security token
377                 //
378                 if (targetWrappingCredentials == null && scope.SymmetricKeyEncryptionRequired)
379                 {
380                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new RequestFailedException(SR.GetString(SR.ID4007)));
381                 }
382 
383                 //
384                 // We are encrypting the proof token or the server entropy using client's encrypting credential if present,
385                 // which will be used to encrypt the key during serialization.
386                 // Otherwise, we can only send back the key in plain text. However, the current implementation of
387                 // WSTrustServiceContract sets the rst.ProofEncryption = null by default. Therefore, the server entropy
388                 // or the proof token will be sent in plain text no matter the client's entropy is sent encrypted or unencrypted.
389                 //
390                 if (request.KeySizeInBits.HasValue)
391                 {
392                     if (request.Entropy != null)
393                     {
394                         result = new SymmetricProofDescriptor(request.KeySizeInBits.Value, targetWrappingCredentials, requestorWrappingCredentials,
395                                                                request.Entropy.GetKeyBytes(), request.EncryptWith);
396                     }
397                     else
398                     {
399                         result = new SymmetricProofDescriptor(request.KeySizeInBits.Value, targetWrappingCredentials,
400                                                                requestorWrappingCredentials, request.EncryptWith);
401                     }
402                 }
403                 else
404                 {
405                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new RequestFailedException(SR.GetString(SR.ID2059)));
406                 }
407             }
408             else if (StringComparer.Ordinal.Equals(keyType, KeyTypes.Bearer))
409             {
410                 //
411                 // Intentionally empty, no proofDescriptor
412                 //
413             }
414 
415             return result;
416         }
417 
418         /// <summary>
419         /// Get the Requestor's Proof encrypting credentials.
420         /// </summary>
421         /// <param name="request">RequestSecurityToken</param>
422         /// <returns>EncryptingCredentials</returns>
423         /// <exception cref="ArgumentNullException">Input argument 'request' is null.</exception>
GetRequestorProofEncryptingCredentials(RST request)424         protected virtual EncryptingCredentials GetRequestorProofEncryptingCredentials(RST request)
425         {
426             if (request == null)
427             {
428                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
429             }
430 
431             if (request.ProofEncryption == null)
432             {
433                 return null;
434             }
435 
436             X509SecurityToken x509SecurityToken = request.ProofEncryption.GetSecurityToken() as X509SecurityToken;
437             if (x509SecurityToken != null)
438             {
439                 return new X509EncryptingCredentials(x509SecurityToken);
440             }
441 
442             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new RequestFailedException(SR.GetString(SR.ID2084, request.ProofEncryption.GetSecurityToken())));
443         }
444 
445         /// <summary>
446         /// Gets the lifetime of the issued token.
447         /// Normally called with the lifetime that arrived in the RST.
448         /// The algorithm for calculating the token lifetime is:
449         /// requestLifeTime (in)            LifeTime (returned)
450         /// Created     Expires             Created             Expires
451         /// null        null                DateTime.UtcNow     DateTime.UtcNow + SecurityTokenServiceConfiguration.DefaultTokenLifetime
452         /// C           null                C                   C + SecurityTokenServiceConfiguration.DefaultTokenLifetime
453         /// null        E                   DateTime.UtcNow     E
454         /// C           E                   C                   E
455         /// </summary>
456         /// <param name="requestLifetime">The requestor's desired life time.</param>
GetTokenLifetime(Lifetime requestLifetime)457         protected virtual Lifetime GetTokenLifetime(Lifetime requestLifetime)
458         {
459             DateTime created;
460             DateTime expires;
461 
462             if (requestLifetime == null)
463             {
464                 created = DateTime.UtcNow;
465                 expires = DateTimeUtil.Add(created, _securityTokenServiceConfiguration.DefaultTokenLifetime);
466             }
467             else
468             {
469                 if (requestLifetime.Created.HasValue)
470                 {
471                     created = requestLifetime.Created.Value;
472                 }
473                 else
474                 {
475                     created = DateTime.UtcNow;
476                 }
477 
478                 if (requestLifetime.Expires.HasValue)
479                 {
480                     expires = requestLifetime.Expires.Value;
481                 }
482                 else
483                 {
484                     expires = DateTimeUtil.Add(created, _securityTokenServiceConfiguration.DefaultTokenLifetime);
485                 }
486             }
487 
488             VerifyComputedLifetime(created, expires);
489 
490             return new Lifetime(created, expires);
491         }
492 
VerifyComputedLifetime(DateTime created, DateTime expires)493         private void VerifyComputedLifetime(DateTime created, DateTime expires)
494         {
495 
496             DateTime utcNow = DateTime.UtcNow;
497 
498             // if expires in past, throw
499             if (DateTimeUtil.Add(DateTimeUtil.ToUniversalTime(expires), _securityTokenServiceConfiguration.MaxClockSkew) < utcNow)
500             {
501                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2075, created, expires, utcNow)));
502             }
503 
504             // if creation time specified is greater than one day in future, throw
505             if (DateTimeUtil.ToUniversalTime(created) > DateTimeUtil.Add(utcNow + TimeSpan.FromDays(1), _securityTokenServiceConfiguration.MaxClockSkew))
506             {
507                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2076, created, expires, utcNow)));
508             }
509 
510             // if expiration time is equal to or before creation time, throw.  This would be hard to make happen as the Lifetime class checks this condition in the constructor
511             if (expires <= created)
512             {
513                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2077, created, expires)));
514             }
515 
516             // if timespan is greater than allowed, throw
517             if ((expires - created) > _securityTokenServiceConfiguration.MaximumTokenLifetime)
518             {
519                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2078, created, expires, _securityTokenServiceConfiguration.MaximumTokenLifetime)));
520             }
521 
522             return;
523         }
524 
525         /// <summary>
526         /// Creates the RSTR and finally read the information from TokenDescriptor and apply
527         /// those to the RSTR.
528         /// </summary>
529         /// <param name="request">The RST from the request.</param>
530         /// <param name="tokenDescriptor">The token descriptor which contains the information for the issued token.</param>
531         /// <returns>The RSTR for the response, null if the token descriptor is null.</returns>
GetResponse(RST request, SecurityTokenDescriptor tokenDescriptor)532         protected virtual RSTR GetResponse(RST request, SecurityTokenDescriptor tokenDescriptor)
533         {
534             if (tokenDescriptor != null)
535             {
536                 RSTR rstr = new RSTR(request);
537                 tokenDescriptor.ApplyTo(rstr);
538 
539                 // Set the replyTo address of the relying party (if any) in the outgoing RSTR from the generated
540                 // token descriptor (STD)  based on the table below:
541                 //
542                 // RST.ReplyTo       STD.ReplyToAddress            RSTR.ReplyTo
543                 // ===========       ====================          ============
544                 // Set               Not Set                       Not Set
545                 // Set               Set                           Set to STD.ReplyToAddress
546                 // Not Set           Not Set                       Not Set
547                 // Not Set           Set                           Not Set
548                 //
549                 if (request.ReplyTo != null)
550                 {
551                     rstr.ReplyTo = tokenDescriptor.ReplyToAddress;
552                 }
553 
554                 //
555                 // Set the appliesTo address (if any) in the outgoing RSTR from the generated token descriptor.
556                 //
557                 if (!string.IsNullOrEmpty(tokenDescriptor.AppliesToAddress))
558                 {
559                     rstr.AppliesTo = new EndpointReference(tokenDescriptor.AppliesToAddress);
560                 }
561 
562                 return rstr;
563             }
564             else
565             {
566                 return null;
567             }
568         }
569 
570         /// <summary>
571         /// Async Cancel.
572         /// </summary>
573         /// <param name="result"></param>
574         /// <returns></returns>
EndCancel(IAsyncResult result)575         public virtual RSTR EndCancel(IAsyncResult result)
576         {
577             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, "Cancel")));
578         }
579 
580         /// <summary>
581         /// Ends the Async call to BeginGetScope. Default implementation will throw a NotImplementedException.
582         /// Refer MSDN articles on Using an AsyncCallback Delegate to End an Asynchronous Operation.
583         /// </summary>
584         /// <param name="result">Typed Async result which contains the result. This is the same instance of
585         /// IAsyncResult that was returned by the BeginGetScope method.</param>
586         /// <returns>The scope.</returns>
EndGetScope(IAsyncResult result)587         protected virtual Scope EndGetScope(IAsyncResult result)
588         {
589             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.ID2081)));
590         }
591 
592         /// <summary>
593         /// Ends the async call of Issue request. This would finally return the RequestSecurityTokenResponse.
594         /// </summary>
595         /// <param name="result">The async result returned from the BeginIssue method.</param>
596         /// <returns>The security token response.</returns>
EndIssue(IAsyncResult result)597         public virtual RSTR EndIssue(IAsyncResult result)
598         {
599             if (result == null)
600             {
601                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
602             }
603 
604             if (!(result is TypedAsyncResult<RSTR>))
605             {
606                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID2012, typeof(TypedAsyncResult<RSTR>), result.GetType())));
607             }
608 
609             return TypedAsyncResult<RSTR>.End(result);
610         }
611 
612         /// <summary>
613         /// Async Renew.
614         /// </summary>
615         /// <param name="result"></param>
616         /// <returns></returns>
EndRenew(IAsyncResult result)617         public virtual RSTR EndRenew(IAsyncResult result)
618         {
619             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, "Renew")));
620         }
621 
622         /// <summary>
623         /// Async Validate.
624         /// </summary>
625         /// <param name="result"></param>
626         /// <returns></returns>
EndValidate(IAsyncResult result)627         public virtual RSTR EndValidate(IAsyncResult result)
628         {
629             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, "Validate")));
630         }
631 
632         /// <summary>
633         /// Retrieves the relying party information. Override this method to provide a custom scope with
634         /// relying party related information.
635         /// </summary>
636         /// <param name="principal">The identity of the token requestor.</param>
637         /// <param name="request">The request message.</param>
638         /// <returns>A scope object based on the relying party related information.</returns>
GetScope(ClaimsPrincipal principal, RST request)639         protected abstract Scope GetScope(ClaimsPrincipal principal, RST request);
640 
641         /// <summary>
642         /// When overridden in a derived class, this method should return a collection of output subjects to be included in the issued token.
643         /// </summary>
644         /// <param name="principal">The ClaimsPrincipal that represents the identity of the requestor.</param>
645         /// <param name="request">The token request parameters that arrived in the call.</param>
646         /// <param name="scope">The scope information about the Relying Party.</param>
647         /// <returns>The ClaimsIdentity representing the collection of claims that will be placed in the issued security token.</returns>
GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope)648         protected abstract ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope);
649 
650         /// <summary>
651         /// Begins async call for GetOutputSubjects routine. Default implementation will throw a NotImplementedExcetion.
652         /// Refer MSDN articles on Using an AsyncCallback Delegate to End an Asynchronous Operation.
653         /// </summary>
654         /// <param name="principal">The authorization context that represents the identity of the requestor.</param>
655         /// <param name="request">The token request parameters that arrived in the call.</param>
656         /// <param name="scope">The scope information about the Relying Party.</param>
657         /// <param name="callback">The callback to be invoked when the user Asynchronous operation completed.</param>
658         /// <param name="state">The state object.</param>
659         /// <returns>IAsyncResult. Represents the status of an asynchronous operation. This will be passed into
660         /// EndGetOutputClaimsIdentity.</returns>
BeginGetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope, AsyncCallback callback, object state)661         protected virtual IAsyncResult BeginGetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope, AsyncCallback callback, object state)
662         {
663             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.ID2081)));
664         }
665 
666         /// <summary>
667         /// Ends the Async call to BeginGetOutputSubjects. Default implementation will throw a NotImplementedExcetion.
668         /// Refer MSDN articles on Using an AsyncCallback Delegate to End an Asynchronous Operation.
669         /// </summary>
670         /// <param name="result">Typed Async result which contains the result. This was the same IAsyncResult that
671         /// was returned by the BeginGetOutputClaimsIdentity.</param>
672         /// <returns>The claimsets collection that will be placed inside the issued token.</returns>
EndGetOutputClaimsIdentity(IAsyncResult result)673         protected virtual ClaimsIdentity EndGetOutputClaimsIdentity(IAsyncResult result)
674         {
675             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.ID2081)));
676         }
677 
678         /// <summary>
679         /// Issues a Security Token.
680         /// </summary>
681         /// <param name="principal">The identity of the token requestor.</param>
682         /// <param name="request">The request.</param>
683         /// <returns>The response.</returns>
Issue(ClaimsPrincipal principal, RST request)684         public virtual RSTR Issue(ClaimsPrincipal principal, RST request)
685         {
686             if (request == null)
687             {
688                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
689             }
690 
691             _principal = principal;
692             _request = request;
693 
694             // 1. Do request validation
695             ValidateRequest(request);
696 
697             // 2. Get the scope and populate into tokenDescriptor
698             Scope scope = GetScope(principal, request);
699             if (scope == null)
700             {
701                 throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2013));
702             }
703             this.Scope = scope;
704 
705 
706             // Create the security token descriptor now that we have a scope.
707             this.SecurityTokenDescriptor = CreateSecurityTokenDescriptor(request, scope);
708             if (this.SecurityTokenDescriptor == null)
709             {
710                 throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2003));
711             }
712 
713             if (this.SecurityTokenDescriptor.SigningCredentials == null)
714             {
715                 throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2079));
716             }
717 
718             //
719             // If TokenEncryptionRequired is set to true, then we must encrypt the token.
720             //
721             if (this.Scope.TokenEncryptionRequired && this.SecurityTokenDescriptor.EncryptingCredentials == null)
722             {
723                 throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4184));
724             }
725 
726             // 3. Get the token-handler
727             SecurityTokenHandler securityTokenHandler = GetSecurityTokenHandler(request.TokenType);
728             if (securityTokenHandler == null)
729             {
730                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID4010, request.TokenType)));
731             }
732 
733 
734             // 4. Get the issuer name and populate into tokenDescriptor
735             _tokenDescriptor.TokenIssuerName = GetValidIssuerName();
736 
737             // 5. Get the token lifetime and populate into tokenDescriptor
738             _tokenDescriptor.Lifetime = GetTokenLifetime(request.Lifetime);
739 
740             // 6. Get the proof token and populate into tokenDescriptor
741             _tokenDescriptor.Proof = GetProofToken(request, scope);
742 
743             // 7. Get the subjects and populate into tokenDescriptor
744             _tokenDescriptor.Subject = GetOutputClaimsIdentity(principal, request, scope);
745 
746             // use the securityTokenHandler from Step 3 to create and setup the issued token information on the tokenDescriptor
747             // (actual issued token, AttachedReference and UnattachedReference)
748             // TokenType is preserved from the request if possible
749             if (!string.IsNullOrEmpty(request.TokenType))
750             {
751                 _tokenDescriptor.TokenType = request.TokenType;
752             }
753             else
754             {
755                 string[] identifiers = securityTokenHandler.GetTokenTypeIdentifiers();
756                 if (identifiers == null || identifiers.Length == 0)
757                 {
758                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4264, request.TokenType)));
759                 }
760                 _tokenDescriptor.TokenType = identifiers[0];
761             }
762             _tokenDescriptor.Token = securityTokenHandler.CreateToken(_tokenDescriptor);
763             _tokenDescriptor.AttachedReference = securityTokenHandler.CreateSecurityTokenReference(_tokenDescriptor.Token, true);
764             _tokenDescriptor.UnattachedReference = securityTokenHandler.CreateSecurityTokenReference(_tokenDescriptor.Token, false);
765 
766             // 9. Create the RSTR
767             RSTR rstr = GetResponse(request, _tokenDescriptor);
768 
769             return rstr;
770         }
771 
772         /// <summary>
773         /// Gets an appropriate SecurityTokenHandler for issuing a security token.
774         /// </summary>
775         /// <param name="requestedTokenType">The requested TokenType.</param>
776         /// <returns>The SecurityTokenHandler to be used for creating the issued security token.</returns>
GetSecurityTokenHandler(string requestedTokenType)777         protected virtual SecurityTokenHandler GetSecurityTokenHandler(string requestedTokenType)
778         {
779             string tokenType = string.IsNullOrEmpty(requestedTokenType) ? _securityTokenServiceConfiguration.DefaultTokenType : requestedTokenType;
780 
781             SecurityTokenHandler securityTokenHandler = _securityTokenServiceConfiguration.SecurityTokenHandlers[tokenType];
782             return securityTokenHandler;
783         }
784 
785         /// <summary>
786         /// This routine processes the stored data about the target resource
787         /// for who the Issued token is for.
788         /// </summary>
789         /// <param name="result">The async result.</param>
790         /// <exception cref="ArgumentNullException">When the given async result is null.</exception>
OnGetScopeComplete(IAsyncResult result)791         void OnGetScopeComplete(IAsyncResult result)
792         {
793             if (null == result)
794             {
795                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
796             }
797 
798             FederatedAsyncState state = result.AsyncState as FederatedAsyncState;
799             if (state == null)
800             {
801                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID2001)));
802             }
803 
804             Exception unhandledException = null;
805             TypedAsyncResult<RSTR> typedResult = state.Result as TypedAsyncResult<RSTR>;
806             if (typedResult == null)
807             {
808                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID2004, typeof(TypedAsyncResult<RSTR>), state.Result.GetType())));
809             }
810 
811             RST request = state.Request;
812 
813             try
814             {
815                 //
816                 // 2. Retrieve the scope information
817                 //
818                 Scope scope = EndGetScope(result);
819                 if (scope == null)
820                 {
821                     throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2013));
822                 }
823                 this.Scope = scope;
824 
825                 //
826                 // Create a security token descriptor
827                 //
828                 this.SecurityTokenDescriptor = CreateSecurityTokenDescriptor(request, this.Scope);
829                 if (this.SecurityTokenDescriptor == null)
830                 {
831                     throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2003));
832                 }
833 
834                 if (this.SecurityTokenDescriptor.SigningCredentials == null)
835                 {
836                     throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2079));
837                 }
838 
839                 //
840                 // If TokenEncryptionRequired is set to true, then we must encrypt the token.
841                 //
842                 if (this.Scope.TokenEncryptionRequired && this.SecurityTokenDescriptor.EncryptingCredentials == null)
843                 {
844                     throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4184));
845                 }
846 
847                 //
848                 // Step 3: Retrieve the token handler to use for creating token and store it in the state
849                 //
850                 SecurityTokenHandler securityTokenHandler = GetSecurityTokenHandler(request == null ? null : request.TokenType);
851                 if (securityTokenHandler == null)
852                 {
853                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID4010, request == null ? String.Empty : request.TokenType)));
854                 }
855                 state.SecurityTokenHandler = securityTokenHandler;
856 
857                 //
858                 // Step 4: Logical issuer name
859                 //
860                 _tokenDescriptor.TokenIssuerName = GetValidIssuerName();
861 
862                 //
863                 // Step 5: Establish token lifetime
864                 //
865                 _tokenDescriptor.Lifetime = GetTokenLifetime(request == null ? null : request.Lifetime);
866 
867                 //
868                 // Step 6: Compute the proof key
869                 //
870                 _tokenDescriptor.Proof = GetProofToken(request, this.Scope);
871 
872                 //
873                 // Start the async call for generating the output subjects.
874                 //
875                 BeginGetOutputClaimsIdentity(state.ClaimsPrincipal, state.Request, scope, OnGetOutputClaimsIdentityComplete, state);
876             }
877 #pragma warning suppress 56500
878             catch (Exception e)
879             {
880                 if (System.Runtime.Fx.IsFatal(e))
881                     throw;
882 
883                 unhandledException = e;
884             }
885 
886             if (unhandledException != null)
887             {
888                 //
889                 // Complete the request in failure
890                 //
891                 typedResult.Complete(null, result.CompletedSynchronously, unhandledException);
892             }
893         }
894 
895         /// <summary>
896         /// The callback that is invoked on the completion of the BeginGetOutputSubjects call.
897         /// </summary>
898         /// <param name="result">The async result.</param>
899         /// <exception cref="ArgumentNullException">When the given async result is null.</exception>
OnGetOutputClaimsIdentityComplete(IAsyncResult result)900         void OnGetOutputClaimsIdentityComplete(IAsyncResult result)
901         {
902             if (null == result)
903             {
904                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
905             }
906 
907             FederatedAsyncState state = result.AsyncState as FederatedAsyncState;
908             if (state == null)
909             {
910                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID2001)));
911             }
912 
913             SecurityTokenHandler securityTokenHandler = state.SecurityTokenHandler;
914             if (securityTokenHandler == null)
915             {
916                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID2016)));
917             }
918 
919             Exception unhandledException = null;
920             RST request = state.Request;
921             RSTR response = null;
922 
923             TypedAsyncResult<RSTR> typedResult = state.Result as TypedAsyncResult<RSTR>;
924             if (typedResult == null)
925             {
926                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID2004, typeof(TypedAsyncResult<RSTR>), state.Result.GetType())));
927             }
928 
929             try
930             {
931                 //
932                 // get token descriptor
933                 //
934                 if (_tokenDescriptor == null)
935                 {
936                     throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID2003));
937                 }
938                 // Step 7: Retrieve the output claims to be included in the issued-token
939                 _tokenDescriptor.Subject = EndGetOutputClaimsIdentity(result);
940 
941                 //
942                 // Use the retrieved securityTokenHandler to create and setup the issued token information on the tokenDescriptor
943                 // (actual issued token, AttachedReference and UnattachedReference)
944                 // TokenType is preserved from the request if possible
945                 if (!string.IsNullOrEmpty(request.TokenType))
946                 {
947                     _tokenDescriptor.TokenType = request.TokenType;
948                 }
949                 else
950                 {
951                     string[] identifiers = securityTokenHandler.GetTokenTypeIdentifiers();
952                     if (identifiers == null || identifiers.Length == 0)
953                     {
954                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4264, request.TokenType)));
955                     }
956                     _tokenDescriptor.TokenType = identifiers[0];
957                 }
958                 _tokenDescriptor.Token = securityTokenHandler.CreateToken(_tokenDescriptor);
959                 _tokenDescriptor.AttachedReference = securityTokenHandler.CreateSecurityTokenReference(_tokenDescriptor.Token, true);
960                 _tokenDescriptor.UnattachedReference = securityTokenHandler.CreateSecurityTokenReference(_tokenDescriptor.Token, false);
961 
962                 // 9. Create the RSTR
963                 response = GetResponse(request, _tokenDescriptor);
964             }
965 #pragma warning suppress 56500
966             catch (Exception e)
967             {
968                 if (System.Runtime.Fx.IsFatal(e))
969                     throw;
970 
971                 unhandledException = e;
972             }
973 
974             typedResult.Complete(response, typedResult.CompletedSynchronously, unhandledException);
975         }
976 
977         /// <summary>
978         /// Gets the Owner configuration instance.
979         /// </summary>
980         public SecurityTokenServiceConfiguration SecurityTokenServiceConfiguration
981         {
982             get
983             {
984                 return _securityTokenServiceConfiguration;
985             }
986         }
987 
988         /// <summary>
989         /// Gets or sets the ClaimsPrincipal associated with the current instance.
990         /// </summary>
991         public ClaimsPrincipal Principal
992         {
993             get { return _principal; }
994             set { _principal = value; }
995         }
996 
997         /// <summary>
998         /// Gets or sets the RequestSecurityToken associated with the current instance.
999         /// </summary>
1000         public RequestSecurityToken Request
1001         {
1002             get { return _request; }
1003             set { _request = value; }
1004         }
1005 
1006         /// <summary>
1007         /// Gets or sets the Scope associated with the current instance.
1008         /// </summary>
1009         public Scope Scope
1010         {
1011             get;
1012             set;
1013         }
1014 
1015         /// <summary>
1016         /// Gets or sets the SecurityTokenDescriptor associated with the current instance.
1017         /// </summary>
1018         protected SecurityTokenDescriptor SecurityTokenDescriptor
1019         {
1020             get { return _tokenDescriptor; }
1021             set
1022             {
1023                 if (value == null)
1024                 {
1025                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
1026                 }
1027                 _tokenDescriptor = value;
1028             }
1029         }
1030 
1031         /// <summary>
1032         /// Renew.
1033         /// </summary>
1034         /// <param name="principal">The <see cref="ClaimsPrincipal"/> to renew.</param>
1035         /// <param name="request">The request.</param>
1036         /// <returns>The response.</returns>
Renew(ClaimsPrincipal principal, RST request)1037         public virtual RSTR Renew(ClaimsPrincipal principal, RST request)
1038         {
1039             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, (request != null && request.RequestType != null ? request.RequestType : "Renew"))));
1040         }
1041 
1042         /// <summary>
1043         /// Validate.
1044         /// </summary>
1045         /// <param name="principal">The <see cref="ClaimsPrincipal"/> to validate.</param>
1046         /// <param name="request">The request.</param>
1047         /// <returns>The response.</returns>
Validate(ClaimsPrincipal principal, RST request)1048         public virtual RSTR Validate(ClaimsPrincipal principal, RST request)
1049         {
1050             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID3141, (request != null && request.RequestType != null ? request.RequestType : "Validate"))));
1051         }
1052 
1053         /// <summary>
1054         /// Validates the RequestSecurityToken encapsulated by this SecurityTokenService instance.
1055         /// </summary>
ValidateRequest(RST request)1056         protected virtual void ValidateRequest(RST request)
1057         {
1058             // currently we only support RST/RSTR pattern
1059             if (request == null)
1060             {
1061                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2051)));
1062             }
1063 
1064             // STS only support Issue for now
1065             if (request.RequestType != null && request.RequestType != RequestTypes.Issue)
1066             {
1067                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2052)));
1068             }
1069 
1070             // key type must be one of the known types
1071             if (request.KeyType != null && !IsKnownType(request.KeyType))
1072             {
1073                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2053)));
1074             }
1075 
1076             // if key type is bearer key, we should fault if the KeySize element is present and its value is not equal to zero.
1077             if (StringComparer.Ordinal.Equals(request.KeyType, KeyTypes.Bearer) && request.KeySizeInBits.HasValue && (request.KeySizeInBits.Value != 0))
1078             {
1079                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2050)));
1080             }
1081 
1082             // token type must be supported for this STS
1083             if (GetSecurityTokenHandler(request.TokenType) == null)
1084             {
1085                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new UnsupportedTokenTypeBadRequestException(request.TokenType));
1086             }
1087 
1088             request.KeyType = (string.IsNullOrEmpty(request.KeyType)) ? KeyTypes.Symmetric : request.KeyType;
1089 
1090             if (StringComparer.Ordinal.Equals(request.KeyType, KeyTypes.Symmetric))
1091             {
1092                 //
1093                 // Check if the key size is within certain limit to prevent Dos attack
1094                 //
1095                 if (request.KeySizeInBits.HasValue)
1096                 {
1097                     if (request.KeySizeInBits.Value > _securityTokenServiceConfiguration.DefaultMaxSymmetricKeySizeInBits)
1098                     {
1099                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidRequestException(SR.GetString(SR.ID2056, request.KeySizeInBits.Value, _securityTokenServiceConfiguration.DefaultMaxSymmetricKeySizeInBits)));
1100                     }
1101                 }
1102                 else
1103                 {
1104                     request.KeySizeInBits = _securityTokenServiceConfiguration.DefaultSymmetricKeySizeInBits;
1105                 }
1106             }
1107         }
1108 
IsKnownType(string keyType)1109         static bool IsKnownType(string keyType)
1110         {
1111             return (StringComparer.Ordinal.Equals(keyType, KeyTypes.Symmetric)
1112                   || StringComparer.Ordinal.Equals(keyType, KeyTypes.Asymmetric)
1113                   || StringComparer.Ordinal.Equals(keyType, KeyTypes.Bearer));
1114         }
1115     }
1116 }
1117