//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IdentityModel.Policy;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Claims;
namespace System.ServiceModel.Security
{
///
/// Wraps a X509SecurityTokenHandler. Delegates the token authentication call the inner tokenAuthenticator.
/// Wraps the returned ClaimsIdentities into an AuthorizationPolicy that supports IAuthorizationPolicy
///
internal class WrappedX509SecurityTokenAuthenticator : X509SecurityTokenAuthenticator
{
X509SecurityTokenHandler _wrappedX509SecurityTokenHandler;
ExceptionMapper _exceptionMapper;
///
/// Initializes an instance of
///
/// X509SecurityTokenHandler to wrap.
/// Converts token validation exceptions to SOAP faults.
public WrappedX509SecurityTokenAuthenticator(
X509SecurityTokenHandler wrappedX509SecurityTokenHandler,
ExceptionMapper exceptionMapper )
: base( X509CertificateValidator.None, GetMapToWindowsSetting( wrappedX509SecurityTokenHandler ), true )
{
if ( wrappedX509SecurityTokenHandler == null )
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "wrappedX509SecurityTokenHandler" );
}
if ( exceptionMapper == null )
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "exceptionMapper" );
}
_wrappedX509SecurityTokenHandler = wrappedX509SecurityTokenHandler;
_exceptionMapper = exceptionMapper;
}
///
/// Validates the token using the wrapped token handler and generates IAuthorizationPolicy
/// wrapping the returned ClaimsIdentities.
///
/// Token to be validated.
/// Read-only collection of IAuthorizationPolicy
protected override ReadOnlyCollection ValidateTokenCore( SecurityToken token )
{
ReadOnlyCollection identities = null;
try
{
identities = _wrappedX509SecurityTokenHandler.ValidateToken(token);
}
catch ( Exception ex )
{
if ( !_exceptionMapper.HandleSecurityTokenProcessingException( ex ) )
{
throw;
}
}
// tlsnego will dispose of the x509, when we write out the bootstrap we will get a dispose error.
bool shouldSaveBootstrapContext = SecurityTokenHandlerConfiguration.DefaultSaveBootstrapContext;
if ( _wrappedX509SecurityTokenHandler.Configuration != null )
{
shouldSaveBootstrapContext = _wrappedX509SecurityTokenHandler.Configuration.SaveBootstrapContext;
}
if ( shouldSaveBootstrapContext )
{
X509SecurityToken x509Token = token as X509SecurityToken;
SecurityToken tokenToCache;
if ( x509Token != null )
{
tokenToCache = new X509SecurityToken( x509Token.Certificate );
}
else
{
tokenToCache = token;
}
BootstrapContext bootstrapContext = new BootstrapContext(tokenToCache, _wrappedX509SecurityTokenHandler);
foreach (ClaimsIdentity identity in identities)
{
identity.BootstrapContext = bootstrapContext;
}
}
List policies = new List(1);
policies.Add(new AuthorizationPolicy(identities));
return policies.AsReadOnly();
}
static bool GetMapToWindowsSetting( X509SecurityTokenHandler securityTokenHandler )
{
if ( securityTokenHandler == null )
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "securityTokenHandler" );
}
return securityTokenHandler.MapToWindows;
}
}
}