File: System\ServiceModel\Dispatcher\AuthorizationBehavior.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.ServiceModel.Dispatcher
{
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.IdentityModel.Policy;
    using System.Runtime;
    using System.Runtime.CompilerServices;
    using System.ServiceModel;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Diagnostics.Application;
    using System.ServiceModel.Security;
 
    sealed class AuthorizationBehavior
    {
        static ServiceAuthorizationManager DefaultServiceAuthorizationManager = new ServiceAuthorizationManager();
 
        ReadOnlyCollection<IAuthorizationPolicy> externalAuthorizationPolicies;
        ServiceAuthorizationManager serviceAuthorizationManager;
        AuditLogLocation auditLogLocation;
        bool suppressAuditFailure;
        AuditLevel serviceAuthorizationAuditLevel;
 
        AuthorizationBehavior() { }
 
        public void Authorize(ref MessageRpc rpc)
        {
 
            if (TD.DispatchMessageBeforeAuthorizationIsEnabled())
            {
                TD.DispatchMessageBeforeAuthorization(rpc.EventTraceActivity);
            }
 
            SecurityMessageProperty security = SecurityMessageProperty.GetOrCreate(rpc.Request);
            security.ExternalAuthorizationPolicies = this.externalAuthorizationPolicies;
 
            ServiceAuthorizationManager serviceAuthorizationManager = this.serviceAuthorizationManager ?? DefaultServiceAuthorizationManager;
            bool outputTiming = DS.AuthorizationIsEnabled();
            Stopwatch sw = null;
            if (outputTiming)
            {
                sw = Stopwatch.StartNew();
            }
 
            try
            {
                if (!serviceAuthorizationManager.CheckAccess(rpc.OperationContext, ref rpc.Request))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateAccessDeniedFaultException());
                }
 
                if (outputTiming)
                {
                    DS.Authorization(this.serviceAuthorizationManager.GetType(), true, sw.Elapsed);
                }
            }
            catch (Exception ex)
            {
                if (Fx.IsFatal(ex))
                {
                    throw;
                }
 
                if (outputTiming)
                {
                    DS.Authorization(this.serviceAuthorizationManager.GetType(), false, sw.Elapsed);
                }
 
                if (PerformanceCounters.PerformanceCountersEnabled)
                {
                    PerformanceCounters.AuthorizationFailed(rpc.Operation.Name);
                }
 
                if (AuditLevel.Failure == (this.serviceAuthorizationAuditLevel & AuditLevel.Failure))
                {
                    try
                    {
                        string primaryIdentity;
                        string authContextId = null;
                        AuthorizationContext authContext = security.ServiceSecurityContext.AuthorizationContext;
                        if (authContext != null)
                        {
                            primaryIdentity = SecurityUtils.GetIdentityNamesFromContext(authContext);
                            authContextId = authContext.Id;
                        }
                        else
                        {
                            primaryIdentity = SecurityUtils.AnonymousIdentity.Name;
                            authContextId = "<null>";
                        }
 
                        SecurityAuditHelper.WriteServiceAuthorizationFailureEvent(this.auditLogLocation,
                            this.suppressAuditFailure, rpc.Request, rpc.Request.Headers.To, rpc.Request.Headers.Action,
                            primaryIdentity, authContextId,
                            serviceAuthorizationManager == DefaultServiceAuthorizationManager ? "<default>" : serviceAuthorizationManager.GetType().Name,
                            ex);
                    }
#pragma warning suppress 56500
                    catch (Exception auditException)
                    {
                        if (Fx.IsFatal(auditException))
                            throw;
 
                        DiagnosticUtility.TraceHandledException(auditException, TraceEventType.Error);
                    }
                }
                throw;
            }
 
            if (AuditLevel.Success == (this.serviceAuthorizationAuditLevel & AuditLevel.Success))
            {
                string primaryIdentity;
                string authContextId;
                AuthorizationContext authContext = security.ServiceSecurityContext.AuthorizationContext;
                if (authContext != null)
                {
                    primaryIdentity = SecurityUtils.GetIdentityNamesFromContext(authContext);
                    authContextId = authContext.Id;
                }
                else
                {
                    primaryIdentity = SecurityUtils.AnonymousIdentity.Name;
                    authContextId = "<null>";
                }
 
                SecurityAuditHelper.WriteServiceAuthorizationSuccessEvent(this.auditLogLocation,
                    this.suppressAuditFailure, rpc.Request, rpc.Request.Headers.To, rpc.Request.Headers.Action,
                    primaryIdentity, authContextId,
                    serviceAuthorizationManager == DefaultServiceAuthorizationManager ? "<default>" : serviceAuthorizationManager.GetType().Name);
            }
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)]
        static AuthorizationBehavior CreateAuthorizationBehavior(DispatchRuntime dispatch)
        {
            AuthorizationBehavior behavior = new AuthorizationBehavior();
            behavior.externalAuthorizationPolicies = dispatch.ExternalAuthorizationPolicies;
            behavior.serviceAuthorizationManager = dispatch.ServiceAuthorizationManager;
            behavior.auditLogLocation = dispatch.SecurityAuditLogLocation;
            behavior.suppressAuditFailure = dispatch.SuppressAuditFailure;
            behavior.serviceAuthorizationAuditLevel = dispatch.ServiceAuthorizationAuditLevel;
            return behavior;
        }
 
        public static AuthorizationBehavior TryCreate(DispatchRuntime dispatch)
        {
            if (dispatch == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("dispatch"));
 
            if (!dispatch.RequiresAuthorization)
                return null;
 
            return CreateAuthorizationBehavior(dispatch);
        }
 
        internal static Exception CreateAccessDeniedFaultException()
        {
            // always use default version?
            SecurityVersion wss = SecurityVersion.Default;
            FaultCode faultCode = FaultCode.CreateSenderFaultCode(wss.FailedAuthenticationFaultCode.Value, wss.HeaderNamespace.Value);
            FaultReason faultReason = new FaultReason(SR.GetString(SR.AccessDenied), CultureInfo.CurrentCulture);
            return new FaultException(faultReason, faultCode);
        }
    }
}