/// <summary> /// The the purposes of this method are: /// 1. To enable layers above to get to the bootstrap tokens /// 2. To ensure an ClaimsPrincipal is inside the SCT authorization policies. This is needed so that /// a CustomPrincipal will be created and can be set. This is required as we set the principal permission mode to custom /// 3. To set the IAuthorizationPolicy collection on the SCT to be one of IDFx's Authpolicy. /// This allows SCT cookie and SCT cached to be treated the same, futher up the stack. /// /// 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. /// </summary> /// <param name="sct"></param> internal void SetPrincipalBootstrapTokensAndBindIdfxAuthPolicy(SecurityContextSecurityToken sct) { if (sct == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("sct"); } List <IAuthorizationPolicy> iaps = new List <IAuthorizationPolicy>(); // // The SecurityContextToken is cached first before the OnTokenIssued is called. So in the Session SCT // case the AuthorizationPolicies will have already been updated. So check the sct.AuthorizationPolicies // policy to see if the first is a AuthorizationPolicy. // if ((sct.AuthorizationPolicies != null) && (sct.AuthorizationPolicies.Count > 0) && (ContainsEndpointAuthPolicy(sct.AuthorizationPolicies))) { // We have already seen this sct and have fixed up the AuthorizationPolicy // collection. Just return. return; } // // Nego SCT just has a cookie, there are no IAuthorizationPolicy. In this case, // we want to add the EndpointAuthorizationPolicy alone to the SCT. // if ((sct.AuthorizationPolicies != null) && (sct.AuthorizationPolicies.Count > 0)) { // // Create a principal with known policies. // AuthorizationPolicy sctAp = IdentityModelServiceAuthorizationManager.TransformAuthorizationPolicies(sct.AuthorizationPolicies, _securityTokenHandlerCollection, false); // Replace the WCF authorization policies with our IDFx policies. // The principal is needed later on to set the custom principal by WCF runtime. iaps.Add(sctAp); // // Convert the claim from WCF unconditional policy to an SctAuthorizationPolicy. The SctAuthorizationPolicy simply // captures the primary identity claim from the WCF unconditional policy which IdFX will eventually throw away. // If we don't capture that claim, then in a token renewal scenario WCF will fail due to identities being different // for the issuedToken and the renewedToken. // SysClaim claim = GetPrimaryIdentityClaim(SystemAuthorizationContext.CreateDefaultAuthorizationContext(sct.AuthorizationPolicies)); SctAuthorizationPolicy sctAuthPolicy = new SctAuthorizationPolicy(claim); iaps.Add(sctAuthPolicy); } iaps.Add(new EndpointAuthorizationPolicy(_endpointId)); sct.AuthorizationPolicies = iaps.AsReadOnly(); }
/// <summary> /// Converts a given set of WCF IAuthorizationPolicy to WIF ClaimIdentities. /// </summary> /// <param name="authorizationPolicies">Set of AuthorizationPolicies to convert to IDFx.</param> /// <param name="securityTokenHandlerCollection">The SecurityTokenHandlerCollection to use.</param> /// <returns>ClaimsIdentityCollection</returns> static ReadOnlyCollection <ClaimsIdentity> ConvertToIDFxIdentities(IList <IAuthorizationPolicy> authorizationPolicies, SecurityTokenHandlerCollection securityTokenHandlerCollection) { if (authorizationPolicies == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("authorizationPolicies"); } if (securityTokenHandlerCollection == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenHandlerCollection"); } List <ClaimsIdentity> identities = new List <ClaimsIdentity>(); SecurityTokenSpecification kerberosTokenSpecification = null; SysAuthorizationContext kerberosAuthContext = null; if ((OperationContext.Current != null) && (OperationContext.Current.IncomingMessageProperties != null) && (OperationContext.Current.IncomingMessageProperties.Security != null)) { SecurityMessageProperty securityMessageProperty = OperationContext.Current.IncomingMessageProperties.Security; foreach (SecurityTokenSpecification tokenSpecification in new SecurityTokenSpecificationEnumerable(securityMessageProperty)) { if (tokenSpecification.SecurityToken is KerberosReceiverSecurityToken) { kerberosTokenSpecification = tokenSpecification; kerberosAuthContext = SysAuthorizationContext.CreateDefaultAuthorizationContext(kerberosTokenSpecification.SecurityTokenPolicies); break; } } } bool hasKerberosTokenPolicyMatched = false; foreach (IAuthorizationPolicy policy in authorizationPolicies) { bool authPolicyHandled = false; if ((kerberosTokenSpecification != null) && !hasKerberosTokenPolicyMatched) { if (kerberosTokenSpecification.SecurityTokenPolicies.Contains(policy)) { hasKerberosTokenPolicyMatched = true; } else { SysAuthorizationContext authContext = SysAuthorizationContext.CreateDefaultAuthorizationContext(new List <IAuthorizationPolicy>() { policy }); // Kerberos creates only one ClaimSet. So any more ClaimSet would mean that this is not a Policy created from Kerberos. if (authContext.ClaimSets.Count == 1) { bool allClaimsMatched = true; foreach (System.IdentityModel.Claims.Claim c in authContext.ClaimSets[0]) { if (!kerberosAuthContext.ClaimSets[0].ContainsClaim(c)) { allClaimsMatched = false; break; } } hasKerberosTokenPolicyMatched = allClaimsMatched; } } if (hasKerberosTokenPolicyMatched) { SecurityTokenHandler tokenHandler = securityTokenHandlerCollection[kerberosTokenSpecification.SecurityToken]; if ((tokenHandler != null) && tokenHandler.CanValidateToken) { identities.AddRange(tokenHandler.ValidateToken(kerberosTokenSpecification.SecurityToken)); authPolicyHandled = true; } } } if (!authPolicyHandled) { SysAuthorizationContext defaultAuthContext = SysAuthorizationContext.CreateDefaultAuthorizationContext(new List <IAuthorizationPolicy>() { policy }); // // Merge all ClaimSets to IClaimsIdentity. // identities.Add(ConvertToIDFxIdentity(defaultAuthContext.ClaimSets, securityTokenHandlerCollection.Configuration)); } } return(identities.AsReadOnly()); }
/// <summary> /// Returns true if the IAuthorizationPolicy could have been created from the given Transport token. /// The method can handle only X509SecurityToken and WindowsSecurityToken. /// </summary> /// <param name="transportToken">Client's Security Token provided at the transport layer.</param> /// <param name="tranportTokenIdentities">A collection of <see cref="ClaimsIdentity"/> to match.</param> /// <param name="authPolicy">IAuthorizationPolicy to check.</param> /// <returns>True if the IAuthorizationPolicy could have been created from the given Transpor token.</returns> static bool DoesPolicyMatchTransportToken( SecurityToken transportToken, IEnumerable <ClaimsIdentity> tranportTokenIdentities, IAuthorizationPolicy authPolicy ) { if (transportToken == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("transportToken"); } if (tranportTokenIdentities == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tranportTokenIdentities"); } if (authPolicy == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("authPolicy"); } ////////////////////////////////////////////////////////////////////////////////////////// // // There are 5 Client Authentication types at the transport layer. Each of these will // result either in a WindowsSecurityToken, X509SecurityToken or UserNameSecurityToken. // // ClientCredential Type || Transport Token Type // ------------------------------------------------------------------- // Basic -> UserNameSecurityToken (In Self-hosted case) // Basic -> WindowsSecurityToken (In Web-Hosted case) // NTLM -> WindowsSecurityToken // Negotiate -> WindowsSecurityToken // Windows -> WindowsSecurityToken // Certificate -> X509SecurityToken // ////////////////////////////////////////////////////////////////////////////////////////// X509SecurityToken x509SecurityToken = transportToken as X509SecurityToken; SysAuthorizationContext defaultAuthContext = SysAuthorizationContext.CreateDefaultAuthorizationContext(new List <IAuthorizationPolicy>() { authPolicy }); foreach (System.IdentityModel.Claims.ClaimSet claimset in defaultAuthContext.ClaimSets) { if (x509SecurityToken != null) { // Check if the claimset contains a claim that matches the X.509 certificate thumbprint. if (claimset.ContainsClaim(new System.IdentityModel.Claims.Claim( System.IdentityModel.Claims.ClaimTypes.Thumbprint, x509SecurityToken.Certificate.GetCertHash(), System.IdentityModel.Claims.Rights.PossessProperty))) { return(true); } } else { // For WindowsSecurityToken and UserNameSecurityToken check that IClaimsdentity.Name // matches the Name Claim in the ClaimSet. // In most cases, we will have only one Identity in the ClaimsIdentityCollection // generated from transport token. foreach (ClaimsIdentity transportTokenIdentity in tranportTokenIdentities) { if (claimset.ContainsClaim(new System.IdentityModel.Claims.Claim( System.IdentityModel.Claims.ClaimTypes.Name, transportTokenIdentity.Name, System.IdentityModel.Claims.Rights.PossessProperty), new ClaimStringValueComparer())) { return(true); } } } } return(false); }