[ 
https://issues.apache.org/jira/browse/JAMES-3522?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17307684#comment-17307684
 ] 

Benoit Tellier commented on JAMES-3522:
---------------------------------------

https://jmap.io/server.html#401-unauthorized

```
As per the HTTP spec, the response MUST have a WWW-Authenticate header listing 
the available authentication schemes.
```

I still believe this deserves more visibility...

Oups. Missed it.


> Allow authentication discovery on top of JMAP
> ---------------------------------------------
>
>                 Key: JAMES-3522
>                 URL: https://issues.apache.org/jira/browse/JAMES-3522
>             Project: James Server
>          Issue Type: New Feature
>          Components: JMAP
>            Reporter: Benoit Tellier
>            Assignee: Antoine Duprat
>            Priority: Major
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> Authentication discovery is a major interoperability concern on top of JMAP.
> As a third-party client, I have no prior knowledge of the authentication 
> schemes supported by the JMAP server. As a client, I need a way to discover 
> supported authentication scheme (to ease end user configuration options).
> Luckily, RFC-2617 (https://tools.ietf.org/html/rfc2617#section-3.2.1) about 
> HTTP authentication introduce such a mechanism through `WWW-Authenticate` 
> header. A failed 401 authentication would result in this header being 
> positioned, allowing discovery for the client of the supported authentication 
> mechanisms. The client can then set up the authentication mechanism it 
> supports and prefer, without requiring user input.
> https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate 
> further  
> RFC-7235 updates RFC-2617 (https://tools.ietf.org/html/rfc7235#section-4.1)
> {code:java}
>    A server generating a 401 (Unauthorized) response MUST send a
>    WWW-Authenticate header field containing at least one challenge. 
> {code}
> So far James JMAP implementation only sends a 401 without setting 
> WWW-Authenticate header field - and is thus not best practice compliant.
> We should infer the WWW-Authenticate from the AuthenticationStrategy James 
> relies on. Ideally, the Authenticator class should aggregate supported 
> challenges into a single header line. JMAP RFC-8620 endpoints should then add 
> the WWW-Authenticate headers upon 401 errors.
> Here is an example of multi-challenge WWW-Authenticate header (RFC-7235):
> {code:java}
> WWW-Authenticate: Newauth realm="apps", type=1,  title="Login to \"apps\"", 
> Basic realm="simple"
> {code}
> Please note that this header also can be used, if desired, to give hints 
> toward why auth failed... Example 
> (https://tools.ietf.org/html/rfc6750#section-3): 
> {code:java}
>      HTTP/1.1 401 Unauthorized
>      WWW-Authenticate: Bearer realm="example",
>                        error="invalid_token",
>                        error_description="The access token expired"
> {code}
> A full list of standard auth shemes is available here: 
> http://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
> Sadly, RFC-8620 do not mention the existence of RFC-7235 nor the existence of 
> WWW-Authenticate header. I think we should start a thread about this topic 
> within the IETF work-group. Maybe we should mandate "Basic" auth as a 
> pre-requisite to ensure inter-operability. I propose myself to start this 
> thread.
> h4. Proposed code changes
> As one might wish to customize authentication methods (eg: support OpenID 
> connect or other custom auth mechanisms) we need to dynamicaly generate the 
> WWW-Authenticate header for JMAP.
> First let's have a POJO representing an authentication challenge:
> {code:scala}
> trait AuthenticationScheme {
>     val value: String
> }
> trait AuthenticationChallenge {
>    val scheme: AuthenticationScheme
>    val parameters: Map[String, String]
> }
> {code}
> Note that I propose to not strong type parameters (all defined in RFC-2617) 
> for simplicity...
> Here is what basic authentication authentication challenge would look like:
> {code:scala}
> case object BasicAuthenticationScheme extends AuthenticationScheme {
>     val value: String = "Basic"
> }
> case object BasicAuthenticationChallenge extends AuthenticationChallenge {
>    val scheme: AuthenticationScheme = BasicAuthenticationScheme
>    val parameters: Map[String, String] = Map("realm" -> "simple")
> }
> {code}
> Then we can advertise AuthenticationChallenges as part of 
> AuthenticationStrategy:
> {code:java}
> public interface AuthenticationStrategy {
>     // reminder: allow authentication
>     Mono<MailboxSession> createMailboxSession(HttpServerRequest httpRequest);
>     AuthenticationChallenges getChallenge();
>     /* omitted as unrelevant here */
> }
> {code}
> All existing authentication strategies will need to be updated accordingly...
> Then the Authenticator class would aggregate AuthenticationChallenges into an 
> AuthenticateHeader, attached to the UnauthorizedException (why => it allows 
> authentication strategies to individually give hints on why auth failed, if 
> desired...):
> {code:java}
> case class AuthenticateHeader(challenges: Seq[ AuthenticationChallenge]) {
>    def headerValue: String = ???
> }
> case class UnauthorizedException(message: String, authenticateHeader: 
> AuthenticateHeader) extends RuntimeException
> {code}
> We then can adapt all JMAPRoutes to position `WWW-Authenticate` header upon 
> 401 - and adapt corresponding tests.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to