By developing some error handling code inside my Unity application in order to take custom actions when a request to Facebook fails (as forcing a local user logout or requesting a new permission) I saw some inconsistencies between the Facebook Graph API (Handling error codes) documentation and the results I am receiving for failed requests.
When trying to post a score (Scores API) without granting write permissions to my application, the request assigned callback receives a FBResult containing:
result.Error == "403 Forbidden"
instead of something related to:
result.Error == {
"error": {
"message": "API Permission Denied",
"type": "",
"code": 10 ,
"error_subcode": 467
}
}
When looking to the FB sample friendsmash-unity they only ignore errors as presented in the next code snippet:
void APICallback(FBResult result)
{
Util.Log("APICallback");
if (result.Error != null)
{
Util.LogError(result.Error);
// Let's just try again
FB.API("/me?fields=id,first_name,friends.limit(100).fields(first_name,id)", Facebook.HttpMethod.GET, APICallback);
return;
}
Is Facebook using different patterns between the Graph API and the
Scores API for handling errors?
Do I need to implement both JSON error and HTTP error parsers?
What are the best practices for handling Facebook errors inside a
Unity application?
1) There are some limitations to Unity's WWW class that unfortunately doesn't let us give back more meaningful errors. They are in the process of fixing it so in the future, result.Error would give back an error message and result.Text would be populated with more meaningful details on the error when that happens. The Scores API and Graph API should be using the same pattern. Though there are still some inconsistencies in how the error comes back. If you do find something like that, please let us know in our bug reporting tool: https://developers.facebook.com/bugs
2) To safely guard yourself, I would say yes. It'll be a good practice to ensure your game is robust.
3) The pattern we try to follow with the Graph API is that it shouldn't return an error code unless something goes wrong. Then it should return an HTTP error code and result.Error should be populated. So the best way is to check if something is in result.Error and handle it from there. If you find something that's not the case, please let us know.
Related
My ASP.NET Core 3.0 in a particular configuration/deployment logs:
[INF] CORS policy execution failed.
[INF] Request origin https://bla.com does not have permission to access the resource.
How can I log at that point the resource that was requested for debugging ?
(note this question is not about the actual issue or solving it)
(note that I am not after globally increasing the log level etc)
Well, that middleware is locked down pretty badly, and I haven't found any sensible way to hook into it.
If you want to replace the CorsMiddleware, you can't just create a decorator that calls Invoke() on the middleware, because you'll have no idea what happened.
Another solution might be to replace the CorsService:ICorsService registration in the service collection with a decorator, and then check the CorsResult after delegating the call to EvaluatePolicy(). That way you could emit an additional log message close to where the original message is emitted.
But there is another possible solution, both very simple and very crude: To check what happened in the request. Albeit that is a bit farther away from the original logged message.
The code below is a delegate added to the pipeline (in Startup/Configure, before .UseCors()) that checks if the request was a preflight request (the same way CorsService does), and if it was successful, i.e. the AccessControlAllowOrigin header is present. If it wasn't successful, it logs a message with the same EventId and source as the CorsService.
app.Use(async (ctx, next) =>
{
await next();
var wasPreflightRequest = HttpMethods.IsOptions(ctx.Request.Method)
&& ctx.Request.Headers.ContainsKey(CorsConstants.AccessControlRequestMethod);
var isCorsHeaderReturned = ctx.Response.Headers.ContainsKey(HeaderNames.AccessControlAllowOrigin);
if (wasPreflightRequest && !isCorsHeaderReturned)
{
ctx.RequestServices.GetRequiredService<ILoggerFactory>()
.CreateLogger<CorsService>()
.LogInformation(new EventId(5, "PolicyFailure"),
$"CORS preflight failed at resource: {ctx.Request.Path}.");
}
});
Based on my testing it seems to work. ¯\_(ツ)_/¯
It might not be what you were looking for, but who knows, maybe it will be useful for someone.
(Obviously a good way to deal with these things is to use a structured logging solution, like Serilog, and add enrichers to capture additional request information, or add stuff manually to a diagnostic context. But setting that up is quite a bit more involved.)
I'm creating a rest API, using ASP.net Core and bit-framework
We want to allow the clients to be able to delete just the resources that they have created themselves
Questions:
In case a client asks to delete a resource which is created by another client,
what is the best exception to raise in the API?
What is the most correct HTTP status code to return?
All the exception implemented in Bit.Owin.Exceptions namespace are:\
BadRequestException
ResourceNotFoundException
AppException
DomainLogicException
should I stick to this list of exceptions in my API? Is this list of exceptions going to be including more exceptions to cover more scenarios?
I think one of these status codes must be returned, but which one suites better our condition?:
403 Forbidden
405 Not Allowed
409 Resource Conflict
I'm not familiar with the framework you are using. But let me give you my 2 cents. From the API consumer point of view, the 403 status code seems to be a quite reasonable choice for the situation described in your question:
6.5.3. 403 Forbidden
The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it. A server that wishes to make public why the request has been forbidden can describe that reason in the response payload (if any). [...]
Alternatively, if you intend to hide the existence of a resource, throw an exception that maps to 404:
An origin server that wishes to "hide" the current existence of a forbidden target resource MAY instead respond with a status code of 404 (Not Found).
Based on #cassiomolin's answer, you can create your own exception type based on following docs:
https://docs.bit-framework.com/introduction/web-api#exception-handling
add exception type to bit framework known exceptions
public class CanNotDeleteOtherClientResourceException : Exception, IKnownException, IHttpStatusCodeAwareException
{
public CanNotDeleteOtherClientResourceException(string message)
: base(message)
{
}
public HttpStatusCode StatusCode { get; set; } = HttpStatusCode.Forbidden;
}
I'm trying to implement an extra authentication layer with the purpose of authenticating the user only if he has a certain status.
If the status is different, I want to show a custom login error (Your account has been suspended) and not authenticate the user at all, similar to what happens if the credentials are wrong, but with a different error message.
So far I've tried two options:
I've added a check within a listener that checks for an "InteractiveLoginEvent". Here I can check the user status and set a flash error message but I don't see what's the proper way to redirect back to the login page, since this event has no response method, other than using a header() call which I definitely want to avoid.
I implemented a custom voter, set the "access_decision_manager" startegy to "unanimous" and returned "ACCESS_DENIED" if the status is not allowing the user to authenticate. So far so good, the user cannot access the resources but I see he still gets authenticated. And I definitely don't want that.
I'm not for sure if I'm missing something or if I'm going in the wrong direction.
Since symfony 2 makes a clear difference between authentication and authorization seems that option 2) is related to authorization, so option 1) is more suitable.
So among the "InteractiveLoginEvent" listener I just added the proper check for the user status and by throwing the following exception I managed to implement my functionality as needed:
throw new AuthenticationException('suspend error message');
So the listener looks something like this:
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
if ($this->securityContext->isGranted('ROLE_CUSTOMROLE')) {
$user = $this->securityContext->getToken()->getUser();
// ... check for the user status here
throw new AuthenticationException('Your account has been suspended!');
}
}
my head is spinning cause of the following issue. I'm accessing my webservice (running on my localhost:4434) with AngularJS and if something goes wrong, the webservice sends a response 400 containing a json body which contains a message that tells you what exactly went wrong.
Problem is I cannot access the message on the client? It is almost as if it never reaches the client?? (This isn't the case, I've confirmed that it reaches the client already) This is the angular code that I use on the client site.
$scope.create = function() {
$http.post('http://localhost:4434/scrapetastic/foo', $scope.bar).
success(function(data, status, headers, config) {
console.log("Call to log: "+status);
console.log("Call to log: "+data);
}).
error(function(data, status) {
console.log("Error|Data:"+data);
console.log(status);
});
}
If I submit malformed data a corresponding error response is generated but as I said ... somehow I cannot access the message that is contained in the response body. This is what I get:
I've tried all sorts of things but am seriously stuck now...perhaps someone has an idea on how to access the payload of the response or at least what to do next? I'm also dealing with CORS perhaps it has something to do with that.
Thanks!
I'm going to take a wild guess here and say that your problem is an XSS issue.
Not only do you not have the data variable, but as far as I can tell from your screenshot, status == 0.
Your screenshot also says Origin: http://localhost, which makes this request considered XSS (since the port is different). That would explain why status is 0.
Edit: You can use jsonp to get around the issue.
Using WCF in a RESTful way seems great. I’m a big fan of the big guns like simplicity and flexibility, but I also love the way the Urls end up looking. What can I say, I’m a programmer.
The simple API for retrieving and editing resources is matched by an almost equally simple set of possible error responses, and I can’t help feeling that to keep to a “pure” RESTful approach I may be cutting my nose off to spite by face, or more specifically, the nose of my web service consumers. I could be wrong, but there doesn’t seem to be very many Http error codes that I can use, and no ways to pass back a custom error message.
To clarify, I am talking about proper exceptional errors and not expected errors. I want to actually communicate a problem to the user to help them identify what they need to do to correct it.
Possible options I am considering...
Just use the Http error codes – This seem like it would be too restrictive in what I am able to express, and won’t allow me to supply a custom message. Please(!) correct me if I am wrong.
Always return Http Success but return custom error objects – Obviously the most flexible but certainly not the most RESTful.
I would really appreciate it if anyone could share some real world experience of this particular problem.
Update
Thanks for the suggestion of using the StatusDescription property of the OutgoingWebResponseContext object. It seemed at first to be something that I could use.
I have come to the conclusion that my second option above is not for me. I want to stick to the what Http can give me.
I am having problems getting it to work, however. Regardless of the value I supply for this property, it doesn’t get returned in the response.
My service method looks like this
public MyType GetMyTypes(string criteria)
{
try
{
return GetMyTypes();
}
catch (Exception ex)
{
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = HttpStatusCode.Forbidden;
response.StatusDescription = "A Big fat error occurred";
return null;
}
}
And here is the raw response message. There is no mention of the custom message...
HTTP/1.1 403 Forbidden
Server: ASP.NET Development Server/9.0.0.0
Date: Wed, 07 Jan 2009 14:01:20 GMT
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Length: 0
Connection: Close
It's not as if I just need to access the correct property on the client. The information is simply not being sent across the link.
What does this StatusDescription property actually do?
Update
I never did find out how to set the StatusDescription property. I ended up not including any error message at all, and going solely with the Http status codes. I have chosen to expose both Soap and Restful endpoints for my services, and so clients can choose which they prefer to use – the simple Restful messages or the relatively richer Soap messages.
With .net 4, throw a WebFaultException<T>(T errorDetail, HttpResponseCodecode)
Here you set your response type to another object type, which makes sense, and also you set the ResponseCode that you want.
The errorDetail must be serializable
http://blogs.msdn.com/b/endpoint/archive/2010/01/21/error-handling-in-wcf-webhttp-services-with-webfaultexception.aspx
Send the proper response code and you can supply the custom error message in the body of the response.
I add the error code both as above (in the status description) and in the body of the returned page in my REST services as:
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = HttpStatusCode.Unauthorized;
response.StatusDescription = "You are not authorized.";
HttpContext.Current.Response.Write("You are not authorized.");
return null;
See this thread for a similar question.
In a nutshell I believe you can set the HTTP status code (to one of the error codes), and provide your custom message in the StatusDescription property:
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = System.Net.HttpStatusCode.Forbidden;
response.StatusDescription = "Custom";
I don't know much about the prevalence of this technique in the real world unfortunately.
This may be a defect. As of 9/22/2011, the issue is under review by the product team:
http://connect.microsoft.com/VisualStudio/feedback/details/690162/wcf-rest-custom-outgoingwebresponsecontext-statusdescription-not-returned-in-response