I have a WCF service configured with TransportWithMessageCredential
security. All the three implementations for IAuthorizationPolicy
, ServiceAuthenticationManager
and ServiceAuthorizationManager
are in place and effective.
serviceHost.Credentials.ServiceCertificate.SetCertificate("CN=localhost");
serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomValidator();
serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
serviceHost.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
serviceHost.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager();
serviceHost.Authentication.ServiceAuthenticationManager = new MyServiceAuthenticationManager();
serviceHost.Authorization.ExternalAuthorizationPolicies =
new System.Collections.ObjectModel.ReadOnlyCollection<System.IdentityModel.Policy.IAuthorizationPolicy>(
new MyAuthorizationPolicy[] { new MyAuthorizationPolicy() });
As I know, in the ServiceAuthorizationManager
inherited class, in CheckAccessCore
method, a return false
statement indicates an Access Denied. That's all good till I want the client side to know that he got an access denied exception where the service stops returning anything to the client and it seems the service thread hanged.
I tried all kinds of try catch
in the client side and even added a FaultContract
to the operation, but the problem resists.
All I can see are two error events in Diagnostics Tools.
What are missing from my implementations to get the service inform the user on access denied error?
Update
It's notable to say that I'm using RoutingService
and now I guess the real cause is that RoutingService
is somehow eating the exception but I don't know exactly where that happens. Even though I stepped into every possible method but I failed to find it.
Update 2
I have IErrorHandler
in place:
public class ServiceErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
//You can log th message if you want.
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
{
if (error is FaultException)
return;
FaultException faultException = new FaultException(error.Message);
MessageFault messageFault = faultException.CreateMessageFault();
msg = Message.CreateMessage(version, messageFault, faultException.Action);
}
}
But event with this the calling client wont' get the exception and the same 'unhandled exception' will appear in debug events.
The sole way that I can fail the calling client is by throwing an exception in BeforeSendReply
method of IDispatchMessageInspector
which I think isn't the way to go as I get a CommunicationException
on the client side instead of FaultException
:
public void BeforeSendReply(ref Message reply, object correlationState)
{
if (reply != null && reply.IsFault)
{
var messageFault = MessageFault.CreateFault(reply, Int32.MaxValue);
throw new FaultException("Access was denied", messageFault.Code);
}
}
WCF Tracing:
You should not expect a FaultException here but instead, a Communication Exception, in your case a SecurityAccessDeniedException. I would expect all the exceptions raised at this stage to be communication one as it is about communication issue, security ones are part of it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With