WCF ServiceAuthenticationManager Extensibility - c#

I want to implement my custom security to wcf,I want to use ServiceAuthenticationManager ,but I am confused how it can be block the message.I tried to throw exception but that time I cannot get my exception detail I got just "request error" in rest call and "The caller was not authenticated by the service" in soap calls but I cant get my custom error error message,What is the correct usage of ServiceAuthenticationManager,or where should I block message?
public class MyAuthenticationManager : ServiceAuthenticationManager
{
public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)
{
//throw new AuthenticationException("Credentials expired!");
throw new SecurityException("my custom message:Invalid authentication");
return base.Authenticate(authPolicy, listenUri,ref message);
}
}

Authentication/Authorization do not give custom messages. Any kind of indication why you are not authorized or authenticated are a way for an attacker to crack your security or gain information he is not entitled to.
For example saying "Your password is wrong" is an indication that the username exists. That is bad. An unauthorized request should never get such information as a response.
If you want to see what went wrong, write to a log that the server administrator can access. But don't send anything to the client. Ever.
So to summarize: no you cannot get a custom message out and that design is on purpose.

Related

C# EWS check if the user credentials are wrong or the service is just unreachable

I'm using the EWS (2.2.1.0) and i need to read emails with my application for automate some tasks.
I would like to show a warning message if the inserted credentials are wrong or, if the connection is missing, just display an error icon in the status bar.
I need to distinguish if the user credentials are wrong or just the connection is missing.
The problem is that the AutodiscoverUrl() method in both cases return the same AutodiscoverLocalException:
The Autodiscover service couldn't be located.
This is weird and make no sense.
My code as follow:
try
{
exService.TraceEnabled = true;
exService.Credentials = new WebCredentials(UserSettings.Email.EmailAddress, UserSettings.Email.EmailPassword);
exService.AutodiscoverUrl(UserSettings.Email.EmailAddress, (string redirectionUrl) => {
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
if (redirectionUri.Scheme == "https")
result = true;
return result;
});
}
catch(Exception ex)
{
Thread.Sleep(ApplicationSettings.General.WaitForNextConnectionRetry);
}
Can someone explain me how to check if the user credentials are wrong or the service is just unreachable?
Thanks in advance
Test Sample link: Get started with EWS Managed API client applications
I think there is no good way to distinguish the user credential or Uri. For me, I just to add "try catch" to detect the error. Also, I tested the sample code above and provide a wrong pwd. Then the error occurred in service.AutodiscoverUrl line. Please see the trace messsage:
Or maybe we can get the Trace message to detect it.

Subscription validation error handling

I am currently trying to handle the exception, when a subscription request can't be validated in time, using the Graph SDK. Unfortunately i am not really sure how to achieve this. The exception thrown when a subscription isn't validated in time is:
Microsoft.Graph.ServiceException: Code: InvalidRequest
Message: Subscription validation request failed. Must respond with 200 OK to
this request.
The HttpStatusCode in the ServiceException is "BadRequest" but just this isn't enough to distinguish the error from other common errors since i want to handle them differently. The ServiceException also contains an Error property with a string property called "Code", which contains "InvalidRequest" in my case. The GraphErrorCode enum in the Graph SDK contained this code so i used it with the "IsMatch" method in the ServiceException:
catch (ServiceException serviceException)
{
var invRequest = GraphErrorCode.InvalidRequest.ToString();
if(serviceException.StatusCode == HttpStatusCode.BadRequest)
{
if (serviceException.IsMatch(invRequest))
{
// do something
}
}
}
"InvalidRequest" is defined in the graph documentation as:
The request is malformed or incorrect.
Considering this i still think my ErrorHandling isn't enough to just catch this specific error.
What i want to know is:
Is using the "GraphErrorCode" enum even correct.
Is there a way to handle this specific error without just comparing the exception message ("Subscription validation request failed. Must respond with 200 OK to this request") with a hard coded string.
You're referencing an outdated library (by over 2 years). The correct SDK for this is the Microsoft Graph .NET Client Library. It includes an far more recent error code enumeration.
As for processing the error, the code is typically enough for handling exceptions. The message content is useful for debugging since it often includes more granular information (what exactly failed, which properties were invalid, etc.). My general rule of thumb is to use the code for handling errors but log both code and message properties for debugging.
The import piece to understand is that different endpoints may surface the same error code for different reasons. A BadRequest may mean something different when issuing a GET against a user resource than it does when issuing a POST to /events. Your handler should take into account both the action and the error.
Here is an example error returned when sending an invalid request (/v1.0/me/a):
{
"error": {
"code": "BadRequest",
"message": "Unsupported segment type. ODataQuery: users/48d31887-5fad-4d73-a9f5-3c356e68a038/a",
"innerError": {
"request-id": "fd4c8b27-26af-4b07-a5be-5efb139d1eb7",
"date": "2018-05-22T14:39:02"
}
}
}
If all I handled was the BadRequest, my handler would likely sufficient. I can handle the error and keep the user moving forward. In my log however I store both BadRequest and Unsupported segment type. ODataQuery: users/48d31887-5fad-4d73-a9f5-3c356e68a038/a so that I can properly file a bug in the code.
Another option might be to do some additional parsing. Lets say that /a doesn't always return an error. Maybe /a works fine for AAD accounts but not for MSA users (FTR, /a is entirely fictitious). If this were the case, I might also want to parse the message and see if the BadRequest included "Unsupported segment type" and handle it a bit differently than a BadRequest that didn't include that message.

Exception from MVC API to MVC site gives error

I have created an MVC (4) Web API which works fine. It has a simple login-method that throws an exception when the user cannot be found.
Besides the API I created a simple website that calls the API by HttpClient:
public T ExecutePost<T>(string apiUrl, IEnumerable<KeyValuePair<string, string>> postData) {
HttpContent content = null;
if (postData != null)
content = new FormUrlEncodedContent(postData);
var a = _client.PostAsync(apiUrl, content).ContinueWith(httpResponseMessage =>
JsonConvert.DeserializeObject<T>(httpResponseMessage.Result.Content.ReadAsStringAsync().Result)
);
return a.Result;
}
You can call this method as
ExecutePost<User>("url_to_controller_action_api", list_with_keys_and_values_to_post)
When this method calls the API with the postData-fiels username and password (both are correct and known by the system) an object called User will be returned... Works like a charm.
When I call this method with the wrong username and/or password, the API throws an exception (User not found), but the method ExecutePost throws an exception aswell and the web page shows a nice, yellow-isch, red-letter page with errors that the normal user does not understand. The reason is easy: The data sent back from the API is not the same as the data that can be put in the object User.
So, what I would like to do is deserialize the exception, from the API, in an object called Error and return that to the controller of the MVC website, so I can put the error "User not found" on the page with the correct design of the site.
What is the best way to do this? Try-catch in all actions? Doesn't feel right to me... So suggestions are more than welcome.
Most things I found were API-side stuff, but I want to fetch and handle the exception on the site-side.
Thanks in advance
On your Web API when you detect an invalid login, make sure that an HttpResponseException gets thrown with a status code of 401 (HttpStatusCode.Unauthorized).
//login failed:
var resp = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("Invalid Username or password")
};
throw new HttpResponseException(resp);
In your calling code, you can then first check if httpResponseMessage.StatusCode==HttpStatusCode.OK before you attempt to deserialise the response into a User.
var a = _client.PostAsync(apiUrl, content).ContinueWith(httpResponseMessage => {
if (httpResponseMessage.Status!=HttpStatus.OK)
{
string ErrorMessage = httpResponseMessage.Result.Content.ReadAsStringAsync();
//and whatever you want to do with that error message here
}
else
{
try
{
var user = JsonConvert.DeserializeObject<T>(httpResponseMessage.Result.Content.ReadAsStringAsync().Result);
}
catch(Exception ex)
{
//honest to goodness unrecoverable failure on the webapi.
//all you can do here is fail gracefully to the caller.
}
}//endif (Status OK)
}//end anonymous function
);
If it's not a 200 then you can execute a second check to see if it's a 401 (and have some specific handling for invalid login) or a more general 500 (something went wrong on the server), etc, and get the actual error message of the exception ("Invalid Username or password") to send back to the client:
var errorMessage = httpResponseMessage.Content.ReadAsStringAsync().Result;
Finally, even if it is 200 then you should still try...catch the deserialisation operation so you can gracefully handle any issues with the returned data, if for whatever reason the data can't be turned into a User object.

Dynamics CRM 2011 - Determine the type of Authentication Issue

I presume this is by design (and hence might be a silly question) however is there any way to determine the authentication issue generated when connecting to Dynamics CRM.
I am creating a third party application which connects and I would like to say "Invalid Password" rather than "Authentication Failure". The following is what I have.
namespace MyCRM
{
public class MyCRMClass
{
public static void ConnectToCRM()
{
Uri serverURI = new Uri('https://myorganisation.api.crm5.dynamics.com/XrmServices/2011/Organization.svc');
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = 'Username';
clientCredentials.UserName.Password = 'Password';
OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(serverURI, null, clientCredentials, null);
serviceProxy.EnableProxyTypes();
try
{
Guid UserId = ((WhoAmIResponse)serviceProxy.Execute(new WhoAmIRequest())).UserId;
}
catch (Exception ex)
{
// Throws Authentication Issue
}
}
}
}
By calling the WhoAMIRequest I can get an Authentication error however I really want to know what error so I can assist staff with fixing their own issue.
Am I right in suggesting that this is not possible using the CRM webservices?
You'll never be able to get error information like you're requesting from the client side. You could theoretically turn on trace logging on the server, but that would be a bad idea for a whole slew of reasons.
Generally saying the password is invalid is a security issue because it allows hackers to know that the account is valid and if they could just figure out the password, they're in.

Throwing a XML Web Service Exception for invalid username / password

I've created a web service and am using a Soap header for authentication, as described here:
http://aspalliance.com/805
I've adapted it, so that in every method, it calls a seperate "authenticate" method, which searches username and password in the db, and returns true or false.
My question is, within this method, if it returns false (ie, the user isn't validated) how should i throw an exception, that filters back to the consumer application?
First of all, you'd do better to add a Login operation that takes your username/password header as input, authenticates the user, then returns an authorization token of some kind in a return SOAP Header. This header should then be supplied as in input header in all subsequent operations.
Second, you should throw a SOAPException. This will translate more or less directly into a SOAP Fault. A SOAP Fault is the appropriate way to indicate an error with a web service operation for the same reason that Exceptions are better than return status in a normal method - you don't have to check the return status at the point of the call.
Finally, were you aware that Microsoft has declared ASMX web services to be "legacy" code, and that they are no longer fixing bugs in it? It's time to move to WCF.
i have used soap exceptions for login fails:
[WebMethod]
[SoapHeader("authentication")]
public User Authenticate()
{
try
{
authentication.Roles = new string[] { UserRoles.Users };
ConfigureAuthentication();
Service<ISecurity>.Interface.Authenticate();
Guid userId = Service<ISecurity>.Interface.GetUserId(authentication.UserName);
return Service<IObjectRetriever>.Interface.Retrieve<User>(userId);
}
catch (Exception ex)
{
WriteException(ex);
throw new SoapException(ex.Message, new XmlQualifiedName(SoapException.ServerFaultCode.Name), ex);
}
}

Categories

Resources