Permalink
Browse files

! routing: AuthenticationFailedRejection now directly contains challe…

…nge headers to return, fixes #538

This has two consequences:
  * it's easier to implement a custom authenticators which can now
    supply the challenge headers directly instead of needing a detour
    through HttpAuthenticator.getChallengeHeaders
  * AuthenticationFailedRejection is now serializable
  • Loading branch information...
jrudolph committed Sep 27, 2013
1 parent b05dc16 commit 9c9b976e1c03e749860d047770eaf1ccd7d35a48
@@ -26,6 +26,7 @@ import AuthenticationFailedRejection._
class SecurityDirectivesSpec extends RoutingSpec {
val dontAuth = BasicAuth(UserPassAuthenticator[BasicUserContext](_ Future.successful(None)), "Realm")
+ val challenge = `WWW-Authenticate`(HttpChallenge("basic", "Realm"))
val doAuth = BasicAuth(UserPassAuthenticator[BasicUserContext] { userPassOption
Future.successful(Some(BasicUserContext(userPassOption.get.user)))
@@ -35,12 +36,12 @@ class SecurityDirectivesSpec extends RoutingSpec {
"reject requests without Authorization header with an AuthenticationFailedRejection" in {
Get() ~> {
authenticate(dontAuth) { echoComplete }
- } ~> check { rejection === AuthenticationFailedRejection(CredentialsMissing, dontAuth) }
+ } ~> check { rejection === AuthenticationFailedRejection(CredentialsMissing, List(challenge)) }
}
"reject unauthenticated requests with Authorization header with an AuthenticationFailedRejection" in {
Get() ~> Authorization(BasicHttpCredentials("Bob", "")) ~> {
authenticate(dontAuth) { echoComplete }
- } ~> check { rejection === AuthenticationFailedRejection(CredentialsRejected, dontAuth) }
+ } ~> check { rejection === AuthenticationFailedRejection(CredentialsRejected, List(challenge)) }
}
"reject requests with illegal Authorization header with 401" in {
Get() ~> RawHeader("Authorization", "bob alice") ~> handleRejections(RejectionHandler.Default) {
@@ -127,7 +127,7 @@ case class UnacceptedResponseEncodingRejection(supported: HttpEncoding) extends
* specified in the cause.
*/
case class AuthenticationFailedRejection(cause: AuthenticationFailedRejection.Cause,
- authenticator: HttpAuthenticator[_]) extends Rejection
+ challengeHeaders: List[HttpHeader]) extends Rejection
object AuthenticationFailedRejection {
/**
@@ -36,12 +36,12 @@ object RejectionHandler {
implicit val Default = apply {
case Nil complete(NotFound, "The requested resource could not be found.")
- case AuthenticationFailedRejection(cause, authenticator) :: _
+ case AuthenticationFailedRejection(cause, challengeHeaders) :: _
val rejectionMessage = cause match {
case CredentialsMissing "The resource requires authentication, which was not supplied with the request"
case CredentialsRejected "The supplied authentication is invalid"
}
- ctx ctx.complete(Unauthorized, authenticator.getChallengeHeaders(ctx.request), rejectionMessage)
+ ctx ctx.complete(Unauthorized, challengeHeaders, rejectionMessage)
case AuthorizationFailedRejection :: _
complete(Forbidden, "The supplied authentication is not authorized to access this resource")
@@ -37,7 +37,7 @@ trait HttpAuthenticator[U] extends ContextAuthenticator[U] {
case Some(userContext) Right(userContext)
case None
val cause = if (authHeader.isEmpty) CredentialsMissing else CredentialsRejected
- Left(AuthenticationFailedRejection(cause, this))
+ Left(AuthenticationFailedRejection(cause, getChallengeHeaders(ctx.request)))
}
}

0 comments on commit 9c9b976

Please sign in to comment.