How to catch exception from UserNamePasswordValidator in WCF client application? - wcf

I've written simple WCF service using netTcpBinding and security mode="Message" and clientCredentialType="UserName". Everything works fine when I pass valid username and password, session is established the way I wanted.
However when the credentials are wrong exception is thrown though I can't catch it in my client application in try catch block.
Did anyone have the same problem ?
Here is my custom validator...
public class UserValidator : UserNamePasswordValidator
{
static int counter = 0;
public override void Validate(string userName, string password)
{
++counter;
Console.WriteLine(counter.ToString() + " " + DateTime.Now.ToShortTimeString());
if (userName != "test" || password != "test")
throw new FaultException("Bad username or password");
//throw new SecurityTokenException();
}
}

Why aren't you throwing the security token exception? That's what it's there for. At that point a message has not be sent and the channel has not be opened, so you can't get a fault back.

Do you have code that sets up the channel between the client and server? If so, is the channel failing to be created correctly - as with message security the client and server must perform the hadnshake, both providing their credentials to open a security channel. This must be established before any further communications will be enabled, and the fact that invalid credentials are passed will stop the channel being created I suspect.

Related

Microsoft.Xrm.Tooling.Connector.CrmServiceClient security token expires every 5 hrs, The user authentication failed error occurs

I am new to WCF, I have created the WCF service which connects and pulls the data from dynamic CRM. Everything works fine but after 5 hrs I am getting the below error, because of this error I see the exception The user authentication failed!. I understand security token gets expired and because of that I get the authentication error, after restarting the application pool everything seems to be good.
What would cause the security token expire? or how to reissue the token?
Microsoft.Xrm.Tooling.Connector.CrmServiceClient Warning: 4 : Claims Connection reset tripped SecurityToken is Not Null Start From is Valid True End At is Valid False Microsoft.Xrm.Tooling.Connector.CrmServiceClient Warning: 4 : Re-Authenticating due to expired token # 05/20/2021 04:12:23
I am using AuthType=IFD in the connection string and below is my coding, I am passing the connection string from the web.config file. I am using RequireNewInstance=True; in the config file as I have a two crm servers to connect.
<add name="crmconnectionstring" connectionString="Url=https://urlhere; AuthType=IFD; RequireNewInstance=True;Domain=testdomain; Username=testusername; Password=; " />
public OrganizationServiceProxy service_;
CrmServiceClient CrmServiceClient_= new
CrmServiceClient(ConfigurationManager.ConnectionStrings["crmconnectionstring"].ConnectionString);
if (!CrmServiceClient_.IsReady)
{
if (CrmServiceClient_.LastCrmException != null)
throw CrmServiceClient_.LastCrmException;
throw new InvalidOperationException(CrmServiceClient_.LastCrmError);
}
service_ = CrmServiceClient_.OrganizationServiceProxy;
Update 1:
I have tried to renew the token but still it does not work. I am desperately looking for the support.
public OrganizationServiceProxy service;
service = CrmServiceClient_.OrganizationServiceProxy;
if (null != this.service.SecurityTokenResponse &&
DateTime.UtcNow.AddMinutes(15) >= this.service.SecurityTokenResponse.Response.Lifetime.Expires)
{
try
{
this.service.Authenticate();
}
catch (CommunicationException)
{
if (null == this.service.SecurityTokenResponse ||
DateTime.UtcNow >= this.service.SecurityTokenResponse.Response.Lifetime.Expires)
{
throw;
}
}
}

Silverlight fault propagation and UserNamePasswordValidator

Scenario is a Silverlight client using Wcf service & custom authentication. To mitigate the 500/200 status code problem (avoid EndPointNotFound exception) I've applied the SilverLightFaultBehaviour. However, this does not work with UserNamePasswordValidator - When a FaultException is thrown from Validate(), it is not caught by the SilverLightFaultMessageInspector's implementation of BeforeSendReply.
So far, the only workaround I've found is using the alternative client stack instead ( WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);), but there are complications with using it which can no longer be ignored as a lot of our clients are on virtual machines, the silverlight client keeps crashing ( Silverlight 5 - Debugging npctrl.dll crash , http://communities.vmware.com/thread/394306?tstart=0 ).
My primary motivation is that I want to be able to distinguish a failed login from a connection error (the following code is from a client-side async callback method, and only works with the Client stack):
if (e.Error is MessageSecurityException)
{
this.HasLoginFailed.Value = Captions.Login_FailedLogin;
}
else
{
this.HasLoginFailed.Value = Captions.Login_FailedConnection;
}
Is there any other way of modifying the message sent when throwing a FaultException from UserNamePasswordValidator? Or any conceptually different way of doing custom authentication rather than what I am using which enables me to modify the message status or to keep it 200, or just to be able to distinguish a connection failure from bad credentials?
my server-side code for usernamepassword reg:
var serviceCredential = host.Description.Behaviors.Find<ServiceCredentials>();
serviceCredential.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
serviceCredential.UserNameAuthentication.CustomUserNamePasswordValidator =
new MyValidator();
When you throw a FaultException from MyValidator, it is wrapped as the InnerException of a MessageSecurityException, that's probably why you weren't able to catch it directly as a FaultException.
To add some information to the fault you are throwing, what you can do is adding a FaultCode:
throw new FaultException(
"Invalid user name or bad password.",
new FaultCode("BadUserNameOrPassword")
);
Then, catch the exception client-side and retrieve your FaultCode:
try { ... }
catch (MessageSecurityException e)
{
FaultException fault = (FaultException) e.InnerException;
String faultCode = fault.Code.Name;
// you can now display a meaningful error with the faultCode
}
I hope it will help!

Openning Async WCF Service with wrong Username-Password hangs

I have a WCF service that implements the 'Custom-Username-Password-Validator'.
The service itself checks the username+password against a local file,
and if there is no match - it throws a FaultException with a message.
.
When I use the service synchronously it works fine.
When I go to work with it ASYNC, I have a problem.
If I pass the wrong 'Username+Password' credentials - and open the client,
instead of returning immediatly from the service going into my 'Channel_Faulted()' method,
the client thread simply waits until the Timeout triggers,
and then I get a 'TimeoutException'.
try
{
client = new MyServiceClient("WSDualHttpBinding_IMyervice");
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "bad password";
client.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted);
client.Open(); // This hangs for 01:00:00 minute
// Doesn't reach here
client.DoSomethingCompleted += new EventHandler<DoSomethingEventArgs(client_DoSomethingCompleted);
client.DoSomethingAsync(param);
}
catch (Exception ex)
{
// Enters here with a 'TimeoutException' exception
}
why does the client not trigger the 'Faulted' method I have ?
Why does it wait for a response from the service even though the service through a 'FaultException' during the 'Validate' method of the 'CustomUserNameValidator' ?
Sure, the code you are using appears to be missing 3 lines after your code line:
client.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted);
But again, I'm taking a shot in the dark since I've not made use of this option yet.
var local = client.ChannelFactory.CreateChannel();
((IClientChannel)local).Faulted += ChannelFaulted;
local.Open();
Better yet, the open method doesn't appear to be necessary according to the sample provide here: ChannelFactory
I personally have not used the ChannelFactory.Faulted event handler however, here is a post for your consideration: creating-wcf-channelfactory

CustomValidator works with username = "test" and password="test", but nothing else

I am testing out the CustomUserNamePassword Validator for WCF and so far it only works if I validate the username test and the password test. If I use something else, such as test1 for the username and test1 for the password, it throws the FaultException. Here is the code the validator:
public override void Validate(string userName, string password)
{
if (userName != "test" || password != "test")
throw new FaultException("Username and Password Failed");
}
I am using a Console App to connect to an IIS Hosted Service and I am calling instantiating the credentials like this:
client.ClientCredentials.UserName.UserName = "test";
client.ClientCredentials.UserName.Password = "test";
The above works, but if I hard code the validator to something like test1 and test1 and then do:
client.ClientCredentials.UserName.UserName = "test1";
client.ClientCredentials.UserName.Password = "test1";
The above fails even if I have:
public override void Validate(string userName, string password)
{
if (userName != "test1" || password != "test1")
throw new FaultException("Username and Password Failed");
}
I am building the app.config and the ProxyCode with svcutil. Could that have anything to do with it? I did regenerate the code.
I figured out what the problem was. I have 3 solutions (A WCF Service Library, A WCF Website that uses the service library, and a Console App that had code generated from the WCF Service Website url wsdl). I was updating the WCF Service Library, and the Console app, but I was not updating the reference for the website. Once I did this, it all worked fine.
Thanks for the help.
[updated answer, I had misunderstood the question]
Is the server side being redeployed? You can try updating the application, or trying to attach a debugger to the server side to see if you have the correct code being run.

Getting details of the call to a WCF service in custom UserNamePasswordValidator

I have a WCF service setup with my own UserNamePasswordValidator. When authentication fails in the Validate(string userName, string password) method I want to write the details to a log as well as throwing a FaultException.
I want to store details of the particular service method that was being called and the parameters that were passed in as well as the username.
How do I access these details from inside the Validate method?
Example code below:
public class ColesUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (CheckCredentials(userName, password))
{
return;
}
else
{
// do something here to get details of the call to the service and send them to a log file
throw new FaultException("Unknown Username or Incorrect Password");
}
}
It is not possible. Validation runs in different thread and it doesn't have access to WCF contexts. Also no WCF context contains information about service method which was called. Incomming message only contains information about SOAP Action which was requested.
If you want to make some logging implement IErrorHandler. Throw SecurityTokenException from custom validator and handle this expection in ProvideFault of IErrorHandler - create FaultException. In HandleFault of IErrorHandler you can implement logging. For logging you can check if OperationContext.Current is not null (yes it can be if exception is thrown before message processing) and access information about current operation call.