1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IdentityModel.Policy;
using System.IdentityModel.Tokens;
using System.ServiceModel.Security.Tokens;
using SysClaim = System.IdentityModel.Claims.Claim;
using SystemAuthorizationContext = System.IdentityModel.Policy.AuthorizationContext;
namespace System.ServiceModel.Security
{
internal class SctClaimsHandler
{
SecurityTokenHandlerCollection _securityTokenHandlerCollection;
string _endpointId;
/// <summary>
/// Creates an instance of <see cref="SctClaimsHandler"/>
/// </summary>
public SctClaimsHandler(
SecurityTokenHandlerCollection securityTokenHandlerCollection,
string endpointId)
{
if ( securityTokenHandlerCollection == null )
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "securityTokenHandlerCollection" );
}
if ( endpointId == null )
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNullOrEmptyString( "endpointId" );
}
_securityTokenHandlerCollection = securityTokenHandlerCollection;
_endpointId = endpointId;
}
/// <summary>
/// Gets the Endpoint Id to which all <see cref="SecurityContextSecurityToken"/> should be scoped.
/// </summary>
public string EndpointId
{
get { return _endpointId; }
}
/// <summary>
/// Gets the <see cref="SecurityTokenHandlerCollection" /> used to validate the SCT.
/// </summary>
public SecurityTokenHandlerCollection SecurityTokenHandlerCollection
{
get { return _securityTokenHandlerCollection; }
}
/// <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();
}
bool ContainsEndpointAuthPolicy( ReadOnlyCollection<IAuthorizationPolicy> policies )
{
if ( policies == null )
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "policies" );
}
for ( int i = 0; i < policies.Count; ++i )
{
if ( policies[i] is EndpointAuthorizationPolicy )
{
return true;
}
}
return false;
}
/// <summary>
/// Gets the primary identity claim to create the SCTAuthorizationPolicy
/// </summary>
/// <param name="authContext">The authorization context</param>
/// <returns>The primary identity claim from the authorization context.</returns>
SysClaim GetPrimaryIdentityClaim( SystemAuthorizationContext authContext )
{
if ( authContext != null )
{
for ( int i = 0; i < authContext.ClaimSets.Count; ++i )
{
System.IdentityModel.Claims.ClaimSet claimSet = authContext.ClaimSets[i];
foreach ( System.IdentityModel.Claims.Claim claim in claimSet.FindClaims( null, System.IdentityModel.Claims.Rights.Identity ) )
{
return claim;
}
}
}
return null;
}
public void OnTokenIssued( SecurityToken issuedToken, EndpointAddress tokenRequestor )
{
SetPrincipalBootstrapTokensAndBindIdfxAuthPolicy( issuedToken as SecurityContextSecurityToken );
}
public void OnTokenRenewed( SecurityToken issuedToken, SecurityToken oldToken )
{
SetPrincipalBootstrapTokensAndBindIdfxAuthPolicy( issuedToken as SecurityContextSecurityToken );
}
}
}
|