-
Notifications
You must be signed in to change notification settings - Fork 599
Rationalize error handling #55
Comments
Proposal: Throw an exception and let the new ErrorHandler middleware deal with the failure. |
Regarding the exception logging, I updated the web.config to log the exceptions in a log file separate for Facebook, Twitter etc so that I can analyze and it works fine. This is a good option of using a ErrorHandler middleware. Also, can we have the configuration of the End Point URI's in the app.config so that it is not required to change dll's in the event of an end point change. |
@Tratcher good idea 🌴 That said, the fact that your new error middleware always returns 500 responses might not be appropriate in every case, specially when the exception has been directly caused by a malformed request. In such scenarios, returning a 400 response would be probably better. Of course, a special exception type allowing to set the status code would solve this kind of issue... but IIRC, you were not a huge fan of this approach. |
Developers are free to examine the exception and set their own status code. We just wanted the default to be 500. |
Sure. But currently, this responsibility is delegated to the end developer, not to the middleware writer. https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNet.Security.OAuth/OAuthAuthenticationHandler.cs#L102 |
ErrorHandler is just for unhandled exceptions. Components that want to return status codes can do so. We're discussing a custom status codes middleware that would provide friendly content to go with status codes. Here's one I prototyped a while ago: http://tratcher.azurewebsites.net/StatusCodes |
But AFAICT, you can't set the status code while throwing an exception given that ErrorHandler overrides it later. In my mind, a middleware should be able to set an appropriate status code to indicate that the requester made a bad request and throw an exception that could be caught in the middleware itself (using the |
You're conflating two forms of control flow that really shouldn't be mixed. What you're asking for is analogous to a method that both returns a error code and throws an exception. A status code should be returned if it's the definitive answer (even if it's a 400). An exception should be thrown when you have no way of producing a definitive answer. If your code path does not have direct access to set the status code then you should be catching specific kinds of exceptions and converting them to status codes in a local scope (e.g. within you middleware/framework) where you have the context to make the conversion. Once an exception escapes into the pipeline then there is no way to guarantee how it will be handled. |
Interesting explanation, even if I don't see why the two forms couldn't be mixed (and This is an easy way for a middleware to prepare a standard response (i.e an appropriate status code and a default message) while allowing the rest of the pipeline to change the way the message is finally handled (by using MVC and Razor or by redirecting the user agent to the login path for instance) without necessarily changing the status code associated with the exception. |
|
True, Here's a simple case to illustrate why a special exception could be convenient: In this code path, we want to make sure that the authorization request has been made using either GET or POST. If it's not the case, that's obviously a bad request and we want to inform the user with a 400 status code. Currently (and just like the OAuth2 server built in Katana does), we just return some HTML payload containing the error details. Using the approach I'm suggesting, I could throw an exception containing a 400 status code and a standard page/message explaining what happened while - potentially - allowing the end developer to catch this exception using your |
I think your example scenario is better addressed with the new custom status code middleware we've been considering. Your middleware sets a status code (e.g. 400), and may include content. The custom status code middleware can then choose to let that content pass through, wrap it, or replace it. There's no reason to use exceptions to control this flow. Exceptions are not for flow control, they are for uncontrolled failures. I don't know how many ways I can say it. When you thrown an exception you have no say in how it gets handled, that's entirely up to the caller. |
That's a valid point, even if I don't necessarily agree (while it's up to a caller to handle an exception, nothing prevents you from sharing custom data the caller could use to handle it). Anyway, if you plan to create the kind of middleware you're mentioning, I won't fight to get a special exception type 😄 |
If a handler throws, will the next handler be called? I think not. Given that we need sites to handle multiple providers for the same protocol, throwing may not be the right thing say if the signature fails, since the next handler using different signing key would succeed. |
@lodejard @Tratcher @HaoK some notes to consider:
|
Design recommendation:
|
Depending on the error detail we may need to squash the error into something more generic, e.g. crypto errors. Can someone draw up a list of the errors thrown for review? |
The ProtocolError redirect would only be for error messages the 3rd party sent to us, e.g. the user pressed cancel. These were already sent to us via a client side redirect, so the client had the chance to see them. Crypto errors would be exceptions handled by the ExceptionHandler middleware. |
I mean in reference to the the remove catch-all exception handling comment, and the as granular as possible recommendation |
I'll send out the PR for this today, but got sucked into a config rename :/ |
Closing this since we have the main changes/design in. Will use the other bugs to track resolving specific flows for each error condition. 409b502 |
The original batch of social auth middleware (Facebook, Twitter, etc.) all swallowed exceptions. The second round (WsFed, ODIC) notified you (AuthenticationFailedNotification) and threw them. These should be rationalized.
Also, consider getting rid of EnsureSuccessStatusCode and offering a more useful error reporting by trying to build an exception using the JSON error payload when content type=app/json.
The text was updated successfully, but these errors were encountered: