SctClaimsHandler.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.IdentityModel.Policy;
  7. using System.IdentityModel.Tokens;
  8. using System.ServiceModel.Security.Tokens;
  9. using SysClaim = System.IdentityModel.Claims.Claim;
  10. using SystemAuthorizationContext = System.IdentityModel.Policy.AuthorizationContext;
  11. namespace System.ServiceModel.Security
  12. {
  13. internal class SctClaimsHandler
  14. {
  15. SecurityTokenHandlerCollection _securityTokenHandlerCollection;
  16. string _endpointId;
  17. /// <summary>
  18. /// Creates an instance of <see cref="SctClaimsHandler"/>
  19. /// </summary>
  20. public SctClaimsHandler(
  21. SecurityTokenHandlerCollection securityTokenHandlerCollection,
  22. string endpointId)
  23. {
  24. if ( securityTokenHandlerCollection == null )
  25. {
  26. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "securityTokenHandlerCollection" );
  27. }
  28. if ( endpointId == null )
  29. {
  30. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNullOrEmptyString( "endpointId" );
  31. }
  32. _securityTokenHandlerCollection = securityTokenHandlerCollection;
  33. _endpointId = endpointId;
  34. }
  35. /// <summary>
  36. /// Gets the Endpoint Id to which all <see cref="SecurityContextSecurityToken"/> should be scoped.
  37. /// </summary>
  38. public string EndpointId
  39. {
  40. get { return _endpointId; }
  41. }
  42. /// <summary>
  43. /// Gets the <see cref="SecurityTokenHandlerCollection" /> used to validate the SCT.
  44. /// </summary>
  45. public SecurityTokenHandlerCollection SecurityTokenHandlerCollection
  46. {
  47. get { return _securityTokenHandlerCollection; }
  48. }
  49. /// <summary>
  50. /// The the purposes of this method are:
  51. /// 1. To enable layers above to get to the bootstrap tokens
  52. /// 2. To ensure an ClaimsPrincipal is inside the SCT authorization policies. This is needed so that
  53. /// a CustomPrincipal will be created and can be set. This is required as we set the principal permission mode to custom
  54. /// 3. To set the IAuthorizationPolicy collection on the SCT to be one of IDFx's Authpolicy.
  55. /// This allows SCT cookie and SCT cached to be treated the same, futher up the stack.
  56. ///
  57. /// This method is call AFTER the final SCT has been created and the bootstrap tokens are around. Itis not called during the SP/TLS nego bootstrap.
  58. /// </summary>
  59. /// <param name="sct"></param>
  60. internal void SetPrincipalBootstrapTokensAndBindIdfxAuthPolicy( SecurityContextSecurityToken sct )
  61. {
  62. if ( sct == null )
  63. {
  64. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "sct" );
  65. }
  66. List<IAuthorizationPolicy> iaps = new List<IAuthorizationPolicy>();
  67. //
  68. // The SecurityContextToken is cached first before the OnTokenIssued is called. So in the Session SCT
  69. // case the AuthorizationPolicies will have already been updated. So check the sct.AuthorizationPolicies
  70. // policy to see if the first is a AuthorizationPolicy.
  71. //
  72. if ( ( sct.AuthorizationPolicies != null ) &&
  73. ( sct.AuthorizationPolicies.Count > 0 ) &&
  74. ( ContainsEndpointAuthPolicy(sct.AuthorizationPolicies) ) )
  75. {
  76. // We have already seen this sct and have fixed up the AuthorizationPolicy
  77. // collection. Just return.
  78. return;
  79. }
  80. //
  81. // Nego SCT just has a cookie, there are no IAuthorizationPolicy. In this case,
  82. // we want to add the EndpointAuthorizationPolicy alone to the SCT.
  83. //
  84. if ( ( sct.AuthorizationPolicies != null ) &&
  85. ( sct.AuthorizationPolicies.Count > 0 ) )
  86. {
  87. //
  88. // Create a principal with known policies.
  89. //
  90. AuthorizationPolicy sctAp = IdentityModelServiceAuthorizationManager.TransformAuthorizationPolicies( sct.AuthorizationPolicies,
  91. _securityTokenHandlerCollection,
  92. false );
  93. // Replace the WCF authorization policies with our IDFx policies.
  94. // The principal is needed later on to set the custom principal by WCF runtime.
  95. iaps.Add( sctAp );
  96. //
  97. // Convert the claim from WCF unconditional policy to an SctAuthorizationPolicy. The SctAuthorizationPolicy simply
  98. // captures the primary identity claim from the WCF unconditional policy which IdFX will eventually throw away.
  99. // If we don't capture that claim, then in a token renewal scenario WCF will fail due to identities being different
  100. // for the issuedToken and the renewedToken.
  101. //
  102. SysClaim claim = GetPrimaryIdentityClaim( SystemAuthorizationContext.CreateDefaultAuthorizationContext( sct.AuthorizationPolicies ) );
  103. SctAuthorizationPolicy sctAuthPolicy = new SctAuthorizationPolicy( claim );
  104. iaps.Add( sctAuthPolicy );
  105. }
  106. iaps.Add( new EndpointAuthorizationPolicy( _endpointId ) );
  107. sct.AuthorizationPolicies = iaps.AsReadOnly();
  108. }
  109. bool ContainsEndpointAuthPolicy( ReadOnlyCollection<IAuthorizationPolicy> policies )
  110. {
  111. if ( policies == null )
  112. {
  113. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "policies" );
  114. }
  115. for ( int i = 0; i < policies.Count; ++i )
  116. {
  117. if ( policies[i] is EndpointAuthorizationPolicy )
  118. {
  119. return true;
  120. }
  121. }
  122. return false;
  123. }
  124. /// <summary>
  125. /// Gets the primary identity claim to create the SCTAuthorizationPolicy
  126. /// </summary>
  127. /// <param name="authContext">The authorization context</param>
  128. /// <returns>The primary identity claim from the authorization context.</returns>
  129. SysClaim GetPrimaryIdentityClaim( SystemAuthorizationContext authContext )
  130. {
  131. if ( authContext != null )
  132. {
  133. for ( int i = 0; i < authContext.ClaimSets.Count; ++i )
  134. {
  135. System.IdentityModel.Claims.ClaimSet claimSet = authContext.ClaimSets[i];
  136. foreach ( System.IdentityModel.Claims.Claim claim in claimSet.FindClaims( null, System.IdentityModel.Claims.Rights.Identity ) )
  137. {
  138. return claim;
  139. }
  140. }
  141. }
  142. return null;
  143. }
  144. public void OnTokenIssued( SecurityToken issuedToken, EndpointAddress tokenRequestor )
  145. {
  146. SetPrincipalBootstrapTokensAndBindIdfxAuthPolicy( issuedToken as SecurityContextSecurityToken );
  147. }
  148. public void OnTokenRenewed( SecurityToken issuedToken, SecurityToken oldToken )
  149. {
  150. SetPrincipalBootstrapTokensAndBindIdfxAuthPolicy( issuedToken as SecurityContextSecurityToken );
  151. }
  152. }
  153. }