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);
}
}
Related
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.
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.
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.
I've been working on some web services lately in c# asp.net (3.5).
My method is like so and returns a User object consisting of some basic user-related fields (name, age, i etc)..
[WebMethod, SoapHeader("AuthHeader")]
public user[] Employees(int count)
{
user[] myUsers = new user[count];
<logic here inc. checking if user is authorised>...
return myUsers;
}
If authorisation fails for the client consuming the web service id like to return an error within the web service, correctly formatted.
Whats the best practice way to achieve this? I guess simply pushing a Response.StatusCode or a Null return isnt good practice?
My current payload XML when auth'd looks like..
<ArrayOfUser>
<user>
<empid>57344</empid>
<firstname>Dave</firstname>
<surname>Johnson</surname>
</user>
<user>
<empid>17324</empid>
<firstname>Mike</firstname>
<surname>Doe</surname>
</user>
</ArrayOfUser>
If an error occurs should I be returning something like...?
<soap:error>
<errorcode>12345</errorcode>
<errorstring>Invalid username/password</errorstring>
</soap:error>
Or is there a better best practice way?
Second issue is, how would I structure my method so I could return such a XML structure? At present my "Employees" method is of type "User[]" so must return an array of type "User", but if theres been an error I want to return a different type to simulate an XML structure as above or even a simple string stating an error has occured.
How would I achieve this?
Any help would be great! Cheers!
Just have your method throw an exception - the .Net framework will convert that into a SOAP error message.
If you want more control over the SOAP error message returned then throw a SoapException
For error handling : You need a good exception handling framework to support your application. If you are using enterpriselibrary exception handling use the below line of code.
enter code here
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "Client Service Policy");
}
It again depends on what message you want to show it to the user. You can log the actual error message and throw customized message to the end user, you can do with the exception handling framework.
You can get more details on implementing exception handling framework.
http://www.devx.com/dotnet/Article/31463/1954
For returning xml : you can create the elements as shown below. Finally you can convert the xelement to string and you can use the string in your caller method (the string is nothing but XML)
enter code here
string[] directoriesList = Directory.GetDirectories(System.IO.Path.GetFullPat ("\\mynetworkpath")));
XElement foldersXML = new XElement("Folders");
foldersXML.Add(from directory in valueList select new XElement("Folders", new XAttribute("name", directory.Split('\\')[directory.Split('\\').Length - 1])));
I have a C# program that fetches XML from my server to display news, show update alerts, and control parts of the program behavior. What techniques do I have at my disposal to ensure the program is connected to a REAL server?
Ususally I use SOAP web services for similar tasks. To ensure only allowed clients can connect, I do use:
Ensure only HTTPS connections are allowed.
Have an API key (string) as an addition parameter to all web service methods.
By using the API key, the server can check a list of allowed API keys (e.g. stored in a database or simply a constant string) and reject non-allowed client requests with invalid API keys.
An example would be:
public class MyWebService :
WebService
{
[WebMethod]
public string GetXml(string apiKey)
{
if( isApiKeyValid(apiKey) )
{
var doc = new XmlDocument();
// TODO: generate XML document.
return doc.OuterXml;
}
else
{
throw new Exception("Invalid API key.");
}
}
}
The isApiKeyValid function would contain the logic to check whether the passed API key is valid or invalid.