Thomas Levesque
Thomas Levesque

Reputation: 292555

How to send meaningful error to client from a custom authorization policy

I have implemented a custom IAuthorizationPolicy for a WCF service. It works fine, except than when the authorization fails, the client receives a meaningless error.

If I just return false from the Evaluate method, the client just receives this:

System.ServiceModel.FaultException: 'The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.'

If I throw a FaultException<MyCustomErrorDetails>, the client receives this:

System.ServiceModel.CommunicationException: 'An error occurred while receiving the HTTP response to http://localhost:9034/Service1.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.'

Which is even less helpful.

How can I return a meaningful error to the client, such as "authorization failed"?

Upvotes: 2

Views: 316

Answers (1)

Lennart Stoop
Lennart Stoop

Reputation: 1689

Enabling detailed error messages in a WCF service can be done through behavior configuration:

  <serviceBehaviors>
    <behavior>
      <serviceDebug includeExceptionDetailInFaults="true"/>      
    </behavior>
  </serviceBehaviors>

Typically you would create a type which holds the fault information, for example:

[DataContract]
public class SecurityFault
{
    private string operation;
    private string problemType;

    [DataMember]
    public string Operation
    {
        get { return operation; }
        set { operation = value; }
    }

    [DataMember]
    public string ProblemType
    {
        get { return problemType; }
        set { problemType = value; }
    }
}

In the service contract you would need to decorate the operations with the fault contract, like so:

[ServiceContract]
public interface IService
{
    [OperationContract]
    [FaultContract(typeof(SecurityFault))]
    int Divide(int number1, int number2);
}

In this case you would throw the exception in the authorization policy, for example:

public class AuthorizationAlwaysFails : IAuthorizationPolicy
{
    public ClaimSet Issuer => throw new NotImplementedException();

    public string Id => Guid.NewGuid().ToString();

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        var sf = new SecurityFault();
        sf.Operation = "Authorization";
        sf.ProblemType = "Authorization failed";
        throw new FaultException<SecurityFault>(sf);
    }
}

Client applications can then catch the exception as follows:

public class Program
{
    static void Main(string[] args)
    {
        var wcfClient = new MyService.ServiceClient();

        try
        {
            var result = wcfClient.Divide(10, 5);
            Console.WriteLine(result);
        }
        catch (FaultException<SecurityFault> securityFault)
        {
            Console.WriteLine(securityFault.Detail.Operation);
            Console.WriteLine(securityFault.Detail.ProblemType);
        }

        Console.ReadLine();
    }
}

Upvotes: 2

Related Questions