mstilkerich / rcmcarddav

CardDAV plugin for RoundCube Webmailer
GNU General Public License v2.0
257 stars 81 forks source link

OAuth2 support (e.g. for Nextcloud) #319

Closed hakoerber closed 3 years ago

hakoerber commented 3 years ago

Hello!

First, thank you for this awesome plugin, I just set it up and it works like a charm.

As an improvement, in addition of using user/password, it might be a good idea to also support OAauth2 authorization bearer tokens. A library like this one might be helpful.

In the end, this would change the login configuration somewhat. There would be two inputs:

Additionally, there would need to be a redirect URL given to the user (e.g. https://roundcube.example.com/carddav/oauth2/redirect) that the user would need to put in to their OAuth2 provider beforehand. To take Nextcloud as an example, a configuration could look like this:

image

Using bearer tokens instead of an "active" authentication flow inside roundcube makes it much easier to implement.

Please not that this is merely a suggestion and it's absolutely valid to refuse that as out of scope/too little ROI.

Have a nice day!

Ref #111

mstilkerich commented 3 years ago

Hello Hannes,

I looked into this briefly a while ago because of #111. It seemed overly complicated to me, particularly the need for the admin to setup a relationship between the roundcube server and each CardDAV provider that OAuth should be used with. I looked at it in the context of google contacts, which is the only CardDAV provider I know who plan to exclusively support OAuth2 in the future (actually it should be discontinued by now, but they continued to support it because of COVID, or so they say :-)). I tried to setup an account with google, but failed to figure out what I need to do.

So in general I would be willing to support OAuth2 authentication, and having nextcloud as a server option would probably make things easier. I'll revisit the topic again after having finished the tasks for 4.1.

alerque commented 3 years ago

I've just bumped into a need for this too. The Nextcloud service I provide alongside Roundcube and others users an SSO system (Keycloak) to authenticate users. That system requires 2FA (for some users). This makes it nearly impossible to setup a default contact list in Roundcube that users the Nextcloud CardDAV server. The user's password simply doesn't cut the mustard.

It is possible to setup on a case by case basis using App passwords, but that's a lot of hastle to get everybody to setup. It would be greatly appreciated if there was a way to setup a bridge to the provider ahead of time that people could just use.

mstilkerich commented 3 years ago

@alerque In your setup, is roundcube / imap / smtp also part of the SSO (assuming roundcube 1.5)? I currently see two different types of setup:

1) Authentication with the auth server is done upon roundcube login. Roundcube requests the needed scopes for imap/smtp, but since it is configurable it could also request the needed scopes for carddav (I haven't looked into it in depth, but it appears to be part of the configuration). In this case, roundcube would take care of acquiring the auth token, including redirection to the login page. Rcmcarddav could use the token acquired by roundcube.

2) Authentication with the auth server is only done for purposes of carddav, roundcube itself uses tradional login. In this case, rcmcarddav would also have to take care of the part acquiring the token, and provide configuration to set up the pairing between roundcube and the auth service.

From my understanding, you have a setup like 1)?

Unfortunately, it is unlikely that I will be able to provide an implementation for this in the near future. I'm currently short on spare time, and this is a topic I lack practical experience with, therefore it will take a bit of reading on my part and getting a test environment set up. I imagine the implementation itself, particularly for use case 1), might not be that much in the end because roundcube 1.5 might include most of the needed work already.

mstilkerich commented 3 years ago

I have now a simple setup for 1) with keycloak and nextcloud and roundcube 1.5-beta. I tried with the "Social Login" nextcloud app (OpenID Connect) and with the "SSO & SAML authentication" app (SAML). With both I can use the keycloak server to login into nextcloud, but the tokens are not accepted on the DAV API (used for CardDAV).

Searching, including the issues reports of those plugin, I only find the advice to use app-generated passwords for DAV. It appears nextcloud on the DAV API currently only accepts bearer tokens when nextcloud itself servers as the auth server, but not with a third party auth service.

mstilkerich commented 3 years ago

Owncloud looks a bit better, but also does not work (owncloud/openidconnect#158)

mstilkerich commented 3 years ago

Note for future reference: Roundcube master contains new plugin hooks to gain access to the token: https://github.com/roundcube/roundcubemail/commit/9d94acb60e0ce4e76632dc134f402c43c2ae375e

alerque commented 3 years ago

Thanks for the attention on this @mstilkerich. As you surmise, I'm heading towards something like 1, but in transition and this is a blocker.

I started out with a system with RC 1.4.x in the mix and am gradually migrating everything to an SSO system using Keycloak. Dovecot the backend already authenticates against it, as does Nextcloud where the contacts are stored. On the frontend RC is (by proxy) using the same password database, but it is not yet actually using the SSO itself.

I have updated RC to a 1.5.x Git HEAD build and that's running pretty well, but I haven't switched it over to oauth yet. As I was looking into it all users loosing automatic access to their contacts is going to be a rough transition. I'll by trying to hold off until we can get this worked out.

By the way I am currently using Nextcloud's SAML (user_saml) login but am also able to get it working with OpenID connect. Honestly though I don't think that should matter because if RC is going to talk directly to the iDP (Keycloak in my case) it needs to get it's authentication tokens from there.

Right not the manual way to set this up (and already required for my users that have 2FA authentication enabled so their password is not enough info to login to Nextcloud) is to use a NC app password.

Now that I think about this more I'm not even sure who needs to add features to make this possible. Does the NC app password system need automating? Can Keycloak be used to pass out tokens that give DAV access? I don't even know.

mstilkerich commented 3 years ago

Now that I think about this more I'm not even sure who needs to add features to make this possible. Does the NC app password system need automating? Can Keycloak be used to pass out tokens that give DAV access? I don't even know.

In the end, all participating servers (auth server, resource servers, client application) needs to implement their part. I will go ahead to have an rcmcarddav release supporting its part in combination with the upcoming roundcube 1.5, but then still nextcloud DAV backend will remain as an open issue to make it happen for your setup.

By the way I am currently using Nextcloud's SAML (user_saml) login but am also able to get it working with OpenID connect. Honestly though I don't think that should matter because if RC is going to talk directly to the iDP (Keycloak in my case) it needs to get it's authentication tokens from there.

SAML vs. OIDC does not matter theoretically, but since it is different nextcloud apps providing the two it might make a difference concerning the support for bearer authentication at the DAV interface. In the same way, it might make a difference which of the multiple available apps for OIDC integration you use. However, at this point my experiences give little hope - none of the apps I tried with nextcloud (SAML, Social Login, OpenID Connect App) enable the use of bearer authentication at the DAV API, i.e. they allow you to log into the web interface only, but for CardDAV you would have to resort to app-specific passwords.

Owncloud gives a bit more hope, as I could see in the traffic that after providing a bearer token it actually talks to keycloak to check the validity of the token and retrieve the user info. However, in the end it does not accept the token for the relevant URIs, so it also does not work. I opened an issue (owncloud/openidconnect#158), lets see if I get feedback on this.

Then there is using nextcloud itself as the OAuth provider. In this case, the DAV API would probably work (although I did not try). The problem with this is that its purely an oauth provider, but it provides no mechanisms for external resource servers to check token validity and retrieve user information for token (that's the part added by SAML or OpenID). Therefore, it's not a solution for use with roundcube because we could not use the tokens issued by nextcloud to authenticate against the imap/smtp server.

So in the end I resorted to try Google as a one hand provider of email, contact and openid services. With this setup, I can get a working SSO solution with roundcube including carddav addressbook. Google does not advertise bearer authentication in the WWW-Authenticate header but accepts a token if provided one. I opened an issue with Google, but given my past experience with issues against the CardDAV API it appears they have little interest in that API and chances are it will be ignored. So I'll add (another) special handling for Google to carddavclient lib to make it work. Anyway, that's the best test setup I could come up with so far. If anyone can provide hints on a combination of working self-hosted components, please let me know.

mstilkerich commented 3 years ago

An implementation for use case 1 in combination with roundcube 1.5 is now available in the oauth branch. Note that it also needs the dev-master version of mstilkerich/carddavclient. The composer file is updated accordingly, but composer update needs to be run unless rcmcarddav is also update via composer.

Tested with Google. https://github.com/mstilkerich/rcmcarddav/commit/590e3e12456b576638cd2f3450a393b36fdf0b17

mstilkerich commented 3 years ago

Nextcloud may be possible soon, too. pulsejet/nextcloud-oidc-login#99 enables use of the OAUTH also in nextcloud's WebDAV backend when using the oidc_login app. The PR still needs to be merged though.

It would require a workaround in carddavclient since Nextcloud does not advertise Bearer authentication in the WWW-Authenticate header, unless this can/will be fixed in the oidc_login app. With that workaround, I could successfully set up an environment with keycloak as the auth service, roundcube as the client application and nextcloud as the resource server for contacts (plus dovecot for imap), all using the OAUTH token acquired during roundcube login.

The OAUTH2 feature is now merged to the master of rcmcarddav. I plan to release a small 4.2.0 update with this feature when roundcube 1.5 is released.

mstilkerich commented 3 years ago

Released 4.2.0 with support for OAuth for the use case 1 above. I‘m still not sure if use case 2 is a meaningful use case. If someone has a need for this, please open a new issue and describe the use case. It would require a rework of the UI to allow redirection from the oauth server back to the carddav settings pane, so it is not something I can easily add at this point. It might be simpler after the UI rework for 5.0.

alerque commented 3 years ago

I guess now I have to dive back in and try to figure out how to setup Keycloak to pass out permissions to Roundcube to let it login to Nextcloud. Fun (... or not depending on how this goes)! Thanks for the release.

mstilkerich commented 3 years ago

A setup with nextcloud using https://github.com/pulsejet/nextcloud-oidc-login/pull/99 for OIDC integration worked for me. I tried many (maybe all :-)) of the OIDC / SAML apps, none offers auth using the token acquired from the auth server except the above one with the pull request that specifically adds this. Apart from that, it was pretty straightforward to setup.

alerque commented 3 years ago

Thanks for the tip @mstilkerich. I have recently had to migrate from user-saml to user-oidc and have previously tried the oidc-login you link and found it came up short. The new-ish work on the user-oidc plugin finally made it a viable replacement for SAML. I guess I'll have to keep an eye on when/if the PR you linked gets merged. That would be a differentiating feature for sure. Honestly I'd like to see it in the semi-official user-oidc plugin though. The OIDC landscape is so confusing!