cyrusimap / cyrus-imapd

Cyrus IMAP is an email, contacts and calendar server
http://cyrusimap.org
Other
534 stars 146 forks source link

JMAP Auth #3103

Open sstubbs opened 4 years ago

sstubbs commented 4 years ago

Hi,

Do you have any idea when JMAP auth will be added to cyrus? Currently I have to store passwords with a reversible encryption in another service that gets proxied through. This is not ideal for performance or security.

Thanks

ksmurchison commented 4 years ago

What specifically do you mean by JMAP Auth? RFC 8620 is explicitly silent on authentication. Cyrus supports several of these HTTP authentication schemes: https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml#authschemes

sstubbs commented 4 years ago

I see thanks for the reply. I saw that in the docs https://www.cyrusimap.org/imap/developer/jmap.html 'Cyrus does not yet implement JMAP authentication. Instead, it requires for each request the HTTP Basic Auth header set with the account’s username and password"

Currently I have a web app using cyrus and jmap. I need to store there credentials in a http-only secure cookie or in a session linked to a database. This is so I can append the headers to the requests sent to cyrus via jmap. They are AES encrypted/decrypted when needed. I know neither of these options are good from a security or performance I'm just trying to understand if cyrus has some sort of authentication/session where I can login once and save a session token of some sort and then work with that rather as I know storing credentials in any reversible manner is a bad idea.

sstubbs commented 4 years ago

This looks like what I was talking about https://github.com/apache/james-project/blob/30a99e381aac890c4b2efb4a8171c20ab6e06acf/server/protocols/jmap-rfc-8621/doc/specs/spec/jmap/session.mdown

remk commented 3 years ago

Is there a documentation page and/or an integration test demonstrating how to use Bearer authentication with JMAP ?

tobley commented 3 years ago

Is there a documentation page and/or an integration test demonstrating how to use Bearer authentication with JMAP ?

Can we get any hints on this maybe @rsto. I can't find any docs and I don't understand the source code.

rsto commented 3 years ago

There is no current support for Bearer authentication in Cyrus. Back when the JMAP spec draft included authentication, we had scaffolded a Bearer scheme based on that spec. We pulled the code out once authentication got excluded from JMAP. At Fastmail we didn't use it anyways, and we weren't happy with keeping basically unused auth code in the codebase. The remaining bearer code in httpd.c are leftovers from that previous attempt.

I can imagine adding support for Bearer, but for the reasons outlined above we might only support a minimal set of callouts to some installation-specific external service. Would that work for you?

tobley commented 3 years ago

Thank you very much for the clarification @rsto. Been a long time since my days of C programming so I assumed there was something magical happening with the code.

The problem I'm trying to solve is authenticating a JMAP websocket connection from a browser. Since headers can't be set with the browser WebSocket API, I was hoping the bearer authentication allowed for an access_token query parameter to be passed in the URI.

I can get around the issue by using a proxy to tranform the request, but I'm open to suggestions if there's a solution native to Cyrus for authenticating with JMAP WS using something other than headers.

Thanks again for the help.

rsto commented 3 years ago

Using a proxy definitely is the best option for the current state of the codebase. I will address the topic in this weeks developer meeting and get back to you.

ksmurchison commented 3 years ago

JMAP WebSocket connections are authenticated via the HTTP handshake request that initiates the WebSocket (see https://www.rfc-editor.org/rfc/rfc8887.html#name-authentication)

With the WebSocket client plugin for Chrome that I did my JMAP testing with while writing RFC 8887, I would first authenticate an HTTP request for the JMAP session object (which a client would need to discober the JMAP WebSocket endpoint), and then I would initiate the WebSocket connection and Chrome would automatically include an Authorization header in the handshake.

tobley commented 3 years ago

Great hint @ksmurchison... after some digging, I think I know what's going on and another possible workaround besides the websocket proxy.

In my case, Cyrus JMAP is just part of a larger web application with many services behind a reverse proxy. I use path-based routes to forward traffic to the appropriate service. Since authentication is under a different path /auth/session than the JMAP service at /jmap/, Firefox decided it was in my best interest to not preemptively include the existing Authorization header.

I haven't tested it yet, but I'm fairly certain it will pass the existing Authorization header if I rearrange the endpoints under a common parent path like /private/session and /private/jmap/.

It worries me though that specs like rcf7617 and rfc7616 say a client "MAY" preemptively include the Authorization header on subsequent requests after successful authentication to improve efficiency. That leaves me with an uneasy feeling that my app may not work in all browsers depending on how they implemented the specs.

I will go with the proxy solution to ensure it works for all clients. If someday Cyrus supports another option, I would gladly take it for a test drive.

Thanks

klinki commented 3 years ago

Hello,

I'm doing a small research on mail servers with JMAP support and I'm stuck on authentication.

Is there any documentation of what is currently supported as JMAP authentication mechanism in Cyrus? I'd like to use Bearer authentication or OAuth, if possible.

rsto commented 3 years ago

Cyrus supports Basic Auth for JMAP. For Bearer or OAuth you will currently have to write your own authentication service that rewrites the HTTP-Authorization header with basic auth credentials for Cyrus.

rsto commented 3 years ago

I guess you are the first actually trying to get a browser send directly to Cyrus. @ksmurchison I can confirm that Cyrus validates authentication before we detect the preflight request in meth_options. We could switch the order and first detect if an OPTIONS request is a CORS preflight and then decide if to authenticate. Alternatively, we might add a new option in imapd.conf with the default for the as-is behaviour? that was meant to go to https://github.com/cyrusimap/cyrus-imapd/issues/3568#issuecomment-884114356

klinki commented 3 years ago

@rsto So, if I understand it correctly, it would mean I would need some service which would translate OAuth / Bearer authentication into HTTP-Authorization.

It means instead of having 1 authentication service, I would have to run 2?

User --- (Bearer / OAuth token) ----> Auth service --- (HTTP Authorization credentials)---> Cyrus?

Also, is the same authentication used for CalDav / CarDav?

rsto commented 3 years ago

It means instead of having 1 authentication service, I would have to run 2? User --- (Bearer / OAuth token) ----> Auth service --- (HTTP Authorization credentials)---> Cyrus?

As it currently stands, yes. We discussed options how to make Bearer authentication work. But we have not decided, yet, sorry.

Also, is the same authentication used for CalDav / CarDav?

Yes.

rsto commented 3 years ago

Probably @ksmurchison knows some SASL trickery that might help here.