Skip to content
This repository has been archived by the owner on Sep 12, 2021. It is now read-only.

Simplifies the exception and status code handling #302

Merged
merged 1 commit into from
Mar 11, 2015
Merged

Simplifies the exception and status code handling #302

merged 1 commit into from
Mar 11, 2015

Conversation

akkie
Copy link
Contributor

@akkie akkie commented Mar 4, 2015

This pull request simplifies the handling of the exceptions and the fallback methods to show the appropriate status codes. Previously it was confusing that the notAuthenticated method handles the 401 Unauthorized status code and the notAuthorized method handles the 403 Forbidden result. Now this is completely unified:

There are now three types of exceptions:
UnauthorizedException -> handles the 401 Unauthorized status code
ForbiddenException -> handles the 403 Forbidden status code
AuthenticationException -> handles errors in the authentication flow

The notAuthenticated fallback handler was renamed to onUnauthorized and the notAuthorized fallback handler was renamed to handleForbidden.

The credential based providers will now throw an UnauthorizedException if the password doesn't match or if the user couldn't be found.

The exceptions do not log the errors anymore. Instead the exception handler will log an info for the UnauthorizedException and the ForbiddenException. The AuthenticationException will not be handled by the exception handler. This should be handled by the user or by the global onError handler.

Any suggestion would be highly appreciated. Especially from @rfranco or @igorbernstein.

@igorbernstein
Copy link
Contributor

Thanks for pinging me on this, but I won't have a chance to look at it until Friday morning. If you can wait that long I'll gladly review this.

@akkie
Copy link
Contributor Author

akkie commented Mar 4, 2015

@igorbernstein Sure, I can wait!

*
* @param msg The exception message.
*/
def this(msg: String) = this(msg, null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use default constructor param

class ForbiddenException(msg:String, cause:Throwable = null)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! Thanks!

@rfranco
Copy link
Contributor

rfranco commented Mar 4, 2015

@akkie looks very good.

@igorbernstein
Copy link
Contributor

I'm looking through this now, a couple of early thoughts (I'll try to solidify tomorrow):

  • Naming difference between of ForbiddenException and AccessDeniedEvent is a bit weird.
  • Logging.rst still references AccessDeniedException.
  • Unless I'm mistaken, AuthenticationException is used as a facade for any errors associated with misconfiguration or external service outages. Unfortunately I don't think there's any sane way to distinguish between those 2 causes, so they have stay lumped together. So, if the scope has to be so broad, why not make SilhouetteException a class and use it in place of AuthenticationException to make it clear how generic the errors are.
  • I still think that the exceptions that result from unauthenticated or unauthorized users trying to access resources behind a SecuredAction, should be of a different type then those resulting from a user trying to register, login or connect to a 3rd party. A forbidden exception caused by a user canceling an oauth flow feels very different from a logged in user who doesn't have permissions to access a resource.

@akkie
Copy link
Contributor Author

akkie commented Mar 6, 2015

I'm not really sure if the terms Unauthorized and Forbidden are the correct terms in conjunction with Silhouette. Sure that are the right terms for the HTTP response codes, but in the sense of an authentication and authorization framework I think they have the wrong meaning.

In Silhouette a user is not-authenticated and not-authorized. It is bad that the terms not authorized and Unauthorized conflicts here for two different meanings. But I think we should still use the terms not-authenticated and not-authorized. It's also not a must to return the Unauthorized and Forbidden response codes in the fallback handlers. It's also possible to return 3** status codes to redirect to another page.

So my proposal would be to rename the methods to onNotAuthenticated and onNotAuthorized. The exceptions should be also renamed to NotAuthenticatedException and NotAuthorizedException.

Any thoughts?

@akkie
Copy link
Contributor Author

akkie commented Mar 6, 2015

@igorbernstein Thanks for your comment. I will not update the doc anymore, because I've moved the documentation to http://silhouette.readme.io. I'll remove the current doc and the current page with the next release.

The problem with the SilhouetteException is that it's a marker trait to catch all Silhouette related exceptions. So if we remove AuthenticationException and make SilhouetteException a class then we cannot only catch the mentioned misconfiguration or external service outage errors, because we get the not-authenticated and not-authorized exceptions too.

To your last point. We could introduce different types of exceptions for the different cases. But at the end all the different types will handle the two fallback methods. So I'm not sure how this could improve the lib. Could you please provide an example? Anyway the register and login actions are not part of the core. So a user could implement custom exceptions if needed.

@igorbernstein
Copy link
Contributor

re: NotAuthenticated/NotAuthorized
I completely agree, NotAuthenticated & NotAuthorized make way more sense for SecuredAction. And it would be nice if the events & default handlers followed in suit:

NotAuthenticatedException => NotAuthenticatedEvent => handleNotAuthenticated
NotAuthorizedException => NotAuthorizedEvent => handleNotAuthorized

But I still think the providers should have a separate exception for when the user types in a wrong password or cancels an oauth flow. Maybe AuthenticationFailedException? I don't think this exception would be related to the two fallback methods. This exception should to be handled locally in the developer's implementation of the CredentialsAuthController & SocialAuthController. It makes sense to have global handleNotAuthenticated/handleNotAuthorized handlers since SecuredActions will be all over the codebase. But the developer will generally have one CredentialsAuthController & one SocialAuthController. Using the same exception type for both usecase feels a bit misleading.

re: SilhouetteException as a class
I'm not sure when you would want to catch configuration errors. I can see wanting to catch service outage errors, but as I mentioned earlier, I don't think its possible to distinguish between configuration & service outage problems. Furthermore, the service outage problems would be extremely rare...the service would have to die after the oauth redirect but before fetching the access token.

@igorbernstein
Copy link
Contributor

It might even make sense to have the credential provider throw an InvalidPasswordException and the oauth providers throw a OAuthCanceledException

@akkie
Copy link
Contributor Author

akkie commented Mar 7, 2015

Thanks for the input. I work on an update to this pull request and I'll see if I can address this issues.

@akkie
Copy link
Contributor Author

akkie commented Mar 8, 2015

I've updated the pull request and the documentation. Every feedback is highly appreciated.

@igorbernstein
Copy link
Contributor

👍👍
I haven't taken a deep dive into this iteration of the PR but from what I've seen, I like it

You might want to reorder the exceptions in the docs and pull NotAuthenticatedException & NotAuthorizedException towards the top because they'll be the most common.

I'll have some time on tuesday to read through the full commit and give more feedback then.

@akkie
Copy link
Contributor Author

akkie commented Mar 10, 2015

@igorbernstein Thanks. I had the same thought regarding the order of exceptions. I'll change this. Looking forward for the full review.

@rfranco
Copy link
Contributor

rfranco commented Mar 10, 2015

@akkie What do you think about use I18N for exception message? it give flexibility to customize the message
https://www.playframework.com/documentation/2.3.x/ScalaI18N

@igorbernstein
Copy link
Contributor

I'm not sure I would ever want to bubble exception messages to the user...it has the potential to leak too much info. Also, there is some value in keeping the exception messages consistent so that developers have an easier time googling for similar issues that other developers might've solved & blogged about.

What messages were you thinking needed translations?

edit: fix grammar & add explanation why I wouldn't want to bubble exception messages (sorry brain is still asleep)

@rfranco
Copy link
Contributor

rfranco commented Mar 10, 2015

@igorbernstein the ideia is not to buble or translatie the exception message to the user otherwise i'd like to be possible to customize the message. One way to do that is use Play Message.

Likely we use log to do some bigdata stuff so it's nice if we could customize the exception message because it goes to the log.

That is only one idea to remove hardcode message.

@akkie
Copy link
Contributor Author

akkie commented Mar 10, 2015

Play message is made for front-end and not for back-end translation. The problem is that if you would translate the exception messages, you must pass two language objects around. The one for the front-end and one for the back-end. Otherwise you log the messages in the language of the user.

@akkie
Copy link
Contributor Author

akkie commented Mar 10, 2015

I would like to merge the commit. Any objections?

@igorbernstein
Copy link
Contributor

I'm looking it over now...a couple of notes:

  • I think the outdated docs should be dropped
  • AccessDeniedException is easy to confuse with NotAuthorizedException, maybe AuthenticationAborted might be a better name?

Other than that, it looks good to me

@akkie
Copy link
Contributor Author

akkie commented Mar 10, 2015

I have choosen the name AccessDeniedException because the providers return an access denied error, so I think we should also use this name. It's also a ProviderException and it's documented in this way. I'll remove the old doc with the next pull request before the next release.

@igorbernstein
Copy link
Contributor

Sounds good

On Tue, Mar 10, 2015 at 5:24 PM, Christian Kaps notifications@github.com
wrote:

I have choosen the name AccessDeniedException because the providers return an access denied error, so I think we should also use this name. It's also a ProviderException and it's documented in this way. I'll remove the old doc with the next pull request before the next release.

Reply to this email directly or view it on GitHub:
#302 (comment)

@rfranco
Copy link
Contributor

rfranco commented Mar 11, 2015

LGTG 👍

akkie added a commit that referenced this pull request Mar 11, 2015
Simplifies the exception and status code handling
@akkie akkie merged commit 758fa27 into mohiva:master Mar 11, 2015
@akkie akkie deleted the status-code-handling branch September 20, 2015 10:01
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
3 participants