Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebDAV access using OIDC bearer token #99

Merged
merged 6 commits into from Sep 23, 2021

Conversation

sirkrypt0
Copy link
Collaborator

@sirkrypt0 sirkrypt0 commented Apr 25, 2021

This PR adds the ability to allow WebDAV access using an OIDC bearer token. This can be useful when using rclone WebDAV with OIDC to synchronize a users files from Nextcloud.

To avoid too much load on the OIDC provider, this PR also adds caching of the JWKs as well as the discovered OIDC configuration for a configurable amount of time.

I suggest reviewing this PR by going through the commits. I tried to make each commit a logical unit of change to aid in the review.

Testing

You can use the following script to test this functionality. To pass the tokens audience check in the OpenIDConnectClient.php, you will need to configure an audience mapper in Keycloak to ensure that your client is included in the aud property of the JWT. A hardcoded audience mapper is sufficient here. Basically follow the following steps:

  1. Go to Client Scopes
  2. Add new client scope, call it nextcloud.
  3. Under Mappers create a new mapper of type Audience and ensure that Included Client Audience contains your Nextcloud client ID. Click Save.
  4. Finally, go to Client > your-nextcloud-client > Client Scopes and add the new nextcloud scope.
#!/bin/bash

KC_BASE="<keycloak-base>" # e.g. http://localhost:8080/auth
KC_REALM="<your-keycloak-realm>"
KC_USERNAME="<keycloak-username>"
KC_PASSWORD="<keycloak-password>"
KC_CLIENT="<your-nextcloud-client>"
KC_SECRET="<your-nextcloud-secret>"

NC_BASE="<nextcloud-base>" # e.g. http://localhost:8081
NC_UID="<nextcloud-user-id>"

resp=$(curl -s -X POST "$KC_BASE/realms/$KC_REALM/protocol/openid-connect/token" \
 -H "Content-Type: application/x-www-form-urlencoded" \
 -d 'grant_type=password' \
 -d "client_id=$KC_CLIENT" -d "client_secret=$KC_SECRET" \
 -d "username=$KC_USERNAME" -d "password=$KC_PASSWORD" \
 -d "scope=nextcloud")

token=$(echo $resp | jq -r .access_token)

[[ ! -n "$token" || "$token" == "null" ]]; then
    echo $resp
    exit 1
fi

curl -X PROPFIND \
    -H "Depth: 1" \
    -H "Authorization: Bearer $token" \
    $NC_BASE/remote.php/dav/files/$NC_UID/

If everything worked as expected, you should get a long XML response that looks something like this:

<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">
  <d:response>
    <d:href>/remote.php/dav/files/4b5e7a7e-6fd9-4c5a-b4be-18bbfd4eed64/</d:href>
    <d:propstat>
      <d:prop>
        <d:getlastmodified>Sat, 24 Apr 2021 13:50:01 GMT</d:getlastmodified>
        <d:resourcetype>
          <d:collection />
        </d:resourcetype>
        <d:quota-used-bytes>16611184</d:quota-used-bytes>
        <d:quota-available-bytes>-3</d:quota-available-bytes>
        <d:getetag>"60842209bab96"</d:getetag>
      </d:prop>
      <d:status>HTTP/1.1 200 OK</d:status>
    </d:propstat>
  </d:response>
</d:multistatus>

@sirkrypt0 sirkrypt0 force-pushed the feature/webdav-bearer branch 3 times, most recently from 1b94e55 to b0abd66 Compare April 25, 2021 13:58
@torshid
Copy link

torshid commented Jun 3, 2021

Exactly what I was looking for. Any news? Or is there any alternatives available?

Copy link
Owner

@pulsejet pulsejet left a comment

Choose a reason for hiding this comment

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

Sorry I've not had enough time to review this (huge) PR. Overall it looks good to go, though I'm not really familiar about how WebDAV works (and how many moving parts in the Nextcloud implementation etc). If you could fix the conflict then I could test locally and merge.

$storagesService = class_exists('\OCA\Files_External\Service\GlobalStoragesService') ?
$container->query(\OCA\Files_External\Service\GlobalStoragesService::class) : null;
} catch (Exception $e) {}
return $storagesService;
Copy link
Owner

Choose a reason for hiding this comment

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

I'm assuming returning null here is fine

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes it is. Like before, the parameter storagesService in the constructor of a class would then be null as well.

@mstilkerich
Copy link

@sirkrypt0 Does this also enable bearer authentication for CardDAV / CalDAV to access the contacts and calendars?

@sirkrypt0
Copy link
Collaborator Author

@sirkrypt0 Does this also enable bearer authentication for CardDAV / CalDAV to access the contacts and calendars?

Yes it does :)

@sirkrypt0
Copy link
Collaborator Author

Sorry I've not had enough time to review this (huge) PR. Overall it looks good to go, though I'm not really familiar about how WebDAV works (and how many moving parts in the Nextcloud implementation etc). If you could fix the conflict then I could test locally and merge.

I fixed the conflicts and added the newest changes from master :)

@mstilkerich
Copy link

mstilkerich commented Jul 12, 2021

@sirkrypt0 Does this also enable bearer authentication for CardDAV / CalDAV to access the contacts and calendars?

Yes it does :)

That's awesome :-) It finally enables to integrate nextcloud as a contact/calendar resource service in a single-sign on setup!

I tried this today and could in the end get it working, but some notes from my experience:

No advertisement of Bearer authentication to clients

Nextcloud does not advertise bearer authentication in the WWW-Authenticate header when sending a 401 response (I removed most of the response headers for brevity):

HTTP/1.1 401 Unauthorized
Date: Mon, 12 Jul 2021 16:18:55 GMT
Server: Apache/2.4.41 (Ubuntu)
WWW-Authenticate: Basic realm="Nextcloud", charset="UTF-8"
Content-Length: 666
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
  <s:message>No public access to this resource., No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured</s:message>
</d:error>

It mentions bearer authentication in the response body only, but this is normally not interpreted by HTTP clients. If Bearer authentication is not advertised, it is likely that the client will not attempt it. It is required to advertise the scheme per RFC6750.

Audience Mapper configuration unclear

It may be clear to someone who knows what they are doing here (which I was not), but my understanding of your instructions on configuring the client audience mapper

ensure that Included Client Audience contains your Nextcloud client

was that I should include the nextcloud client (in my case: roundcube). This didn't work. I found that I have to actually add nextcloud here, not the DAV client application. I think it would be clear if you wrote

ensure that Included Client Audience contains your Nextcloud client ID

instead.

Previously, we only returned a 401 response code without setting the WWW-Authenticate header accordingly to Bearer. As some clients won't attempt Bearer authentication in that case, we explicitly advertise Bearer authentication now.
@sirkrypt0
Copy link
Collaborator Author

@sirkrypt0 Does this also enable bearer authentication for CardDAV / CalDAV to access the contacts and calendars?

Yes it does :)

That's awesome :-) It finally enables to integrate nextcloud as a contact/calendar resource service in a single-sign on setup!

I tried this today and could in the end get it working, but some notes from my experience:

No advertisement of Bearer authentication to clients

Nextcloud does not advertise bearer authentication in the WWW-Authenticate header when sending a 401 response (I removed most of the response headers for brevity):

HTTP/1.1 401 Unauthorized
Date: Mon, 12 Jul 2021 16:18:55 GMT
Server: Apache/2.4.41 (Ubuntu)
WWW-Authenticate: Basic realm="Nextcloud", charset="UTF-8"
Content-Length: 666
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
  <s:message>No public access to this resource., No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured</s:message>
</d:error>

It mentions bearer authentication in the response body only, but this is normally not interpreted by HTTP clients. If Bearer authentication is not advertised, it is likely that the client will not attempt it. It is required to advertise the scheme per RFC6750.

Audience Mapper configuration unclear

It may be clear to someone who knows what they are doing here (which I was not), but my understanding of your instructions on configuring the client audience mapper

ensure that Included Client Audience contains your Nextcloud client

was that I should include the nextcloud client (in my case: roundcube). This didn't work. I found that I have to actually add nextcloud here, not the DAV client application. I think it would be clear if you wrote

ensure that Included Client Audience contains your Nextcloud client ID

instead.

Hey, thanks for your detailed notes. I now removed the part that caused the WWW-Authenticate header to not be set properly. In my tests, the header is now set correctly. Does that solve your issues?

@mcesnik
Copy link

mcesnik commented Sep 5, 2021

I really want to use WebDav to connect my Kodi to nextcloud and its a shame I cannot use OIDC. I like idea here but I do have a few comments/requests.

  1. The /bin/bash script noted above, it references the client id/secret can this not be handled by the plugin? Would I really need to specify this somehow?
  2. Would it be possible to make a single request to the WebDav in the form of https://user:pass@ip/remote.php/webdav instead of acquiring a token separately?
  3. Would it also be possible to implement an auth code flow? I don't like the idea of using passwords all over the place and would prefer having codes which can be revoked from within Keycloak at any time. I guess like in 2, the address could look like https://authcode@ip/remote.php/webdav

Anyhow hope some of this is possible.

@sirkrypt0
Copy link
Collaborator Author

sirkrypt0 commented Sep 6, 2021

Hey @mcesnik ,

The /bin/bash script noted above, it references the client id/secret can this not be handled by the plugin? Would I really need to specify this somehow?

The Bash script is for demonstration purposes only. It shows how the interaction with the Nextcloud with the OIDC plugin enabled works. It uses the Keycloak Direct Grant to receive an access token from Keycloak and presents that token to Nextcloud. It could very well perform any other flow such as the auth code flow to obtain an access token.

Would it be possible to make a single request to the WebDav in the form of https://user:pass@ip/remote.php/webdav instead of acquiring a token separately?

Nextcloud natively supports Basic Authentication using username and password (see here). Hence, you don't need this plugin for that if the users' credentials are stored in Nextcloud.

If you want to send your credentials to the Nextcloud which then exchanges those for an access token, this would generally be possible using the password grant type shown in the Bash script. However, this somehow defeats the purpose of OIDC, as the idea is that the user only enters their password on one trusted site (see here)

Would it also be possible to implement an auth code flow? I don't like the idea of using passwords all over the place and would prefer having codes which can be revoked from within Keycloak at any time. I guess like in 2, the address could look like https://authcode@ip/remote.php/webdav

The auth code flow generally requires user interaction by requesting a certain URL of the provider which then redirects back to our application (see here). This is what already happens in this plugin (even without the changes presented in this MR). Once you enable this plugin in your Nextcloud instance, a new button will pop up on the login screen that lets users sign in.

I hope that helps.

This MR adds the possibility to access WebDAV by providing a previously obtained access token (e.g. by using the oidc-agent) to the Nextcloud in the Authorization HTTP header as a Bearer token.

Thus, if Kodi is able to obtain an access token for a user, e.g. using the auth code flow, it can present that token to the Nextcloud in the Authorization: Bearer header (if you use Keycloak, make sure that you include the nextcloud or any similar scope as described in the description of this MR to ensure that the token can be used for your Nextcloud client)

@mcesnik
Copy link

mcesnik commented Sep 6, 2021

@sirkrypt0 so my problem is I don't use the native username/password and Kodi is built on the premise of supplying them. I understand the script is an example but is the assumption that, when I call the remote.php/webdav endpoint I would supply a bearer token via the Authorization header? I am guessing based on what you are saying, is yes, but I guess that this plugin doesn't actually handle the parsing of the original request and just offloads when the token is a Bearer, am I correct?

I was kind of hoping there would be a way to take the whole request when oidc was enabled and somehow automate the whole obtaining of a bearer token for you. As for the auth code it only requires user interaction when creating the code. This can be done via the Keycloak independently of this flow. The actual exchange would not require any user interaction. I also agree in principle with the password comment but it isn't a hard and fast rule and can be exchanged by anyone who has the credentials.

@mstilkerich
Copy link

Hey, thanks for your detailed notes. I now removed the part that caused the WWW-Authenticate header to not be set properly. In my tests, the header is now set correctly. Does that solve your issues?

Finally I found time to try this - and yes, it works :-) I hope this can be merged soon, I think it's a huge step forward for this app and a differentiating factor from the other OIDC apps. Thanks for your great work!

@antoniogfs
Copy link

This would be very helpful also for me. Any news on that?

@torshid
Copy link

torshid commented Sep 23, 2021

That's a feature requested since a long time from the Nextcloud community, this PR is actually the first one to implement it. Hope it will be merged soon too.

@pulsejet pulsejet merged commit e557324 into pulsejet:master Sep 23, 2021
@pulsejet
Copy link
Owner

Sorry for the delay. Merged, thanks!

@azmeuk
Copy link
Collaborator

azmeuk commented Sep 27, 2021

Hi. I run nextcloud 22.1.1 with nextcloud-oidc-login v2.1.0. I installed a functional roundcube 1.5beta with rcmcarddav 4.2.0, and I try to plug rcmcarddav to nextcloud. The OIDC server is canaille (not keycloak). The OIDC login works correctly both in roundcube and nextcloud.

However it seems that rcmcarddav does not succeed to authenticate against nextcloud and I get a 401 error in the logs. This looks somewhat similar to the issue you had @mstilkerich and it seems you had a solution related to the aud claim but I am not sure what is it, as the configuration instructions seems to be exclusively for keycloak.

Can you please provide a more generic documentation?

Is it a carddav, nextcloud or nextcloud-oidc-login configuration error?

Thank you for your help.

carddav.log

[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [1 DBG] carddav::checkMigrations
[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [1 DBG] internalGet query: SELECT "filename" FROM carddav_migrations
[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [1 DBG] carddav::initPresets
[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [1 DBG] internalGet query: SELECT * FROM carddav_addressbooks WHERE (("user_id" = '1'))
[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [2 NFO] Adding preset for  at URL https://cloud.mydomain.tld/remote.php/dav/addressbooks/users/myusername/contacts/
[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [1 DBG] Starting discovery with input https://cloud.mydomain.tld/remote.php/dav/addressbooks/users/myusername/contacts/
[27-Sep-2021 14:01:23 +0200]: <a719cj3j> [1 DBG] Try context path /.well-known/carddav
[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [1 DBG] Trying auth scheme bearer
[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [1 DBG] Using auth scheme bearer
[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [1 DBG] None of the available auth schemes worked
[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [2 NFO] Exception while querying current-user-principal: Expected Multistatus HTTP request was not successful (401 Unauthorized): <?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
  <s:message>No public access to this resource., Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured</s:message>
</d:error>

[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [1 DBG] Try context path /
[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [2 NFO] Exception while querying current-user-principal: Expected Multistatus HTTP request was not successful (405 Not Allowed): <html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx</center>
</body>
</html>

[27-Sep-2021 14:01:26 +0200]: <a719cj3j> [1 DBG] Try context path /co
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [2 NFO] Exception while querying current-user-principal: Expected Multistatus HTTP request was not successful (405 Method Not Allowed):
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] Try context path /remote.php/dav/addressbooks/users/myusername/contacts/
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] Trying auth scheme bearer
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] Using auth scheme bearer
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] None of the available auth schemes worked
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [2 NFO] Exception while querying current-user-principal: Expected Multistatus HTTP request was not successful (401 Unauthorized): <?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
  <s:message>No public access to this resource., Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured</s:message>
</d:error>

[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] Trying auth scheme bearer
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] Using auth scheme bearer
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] None of the available auth schemes worked
[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [1 DBG] internalGet query: SELECT * FROM carddav_addressbooks WHERE (("user_id" = '1'))
[27-Sep-2021 14:01:30 +0200]: <a719cj3j> [1 DBG] internalGet query: SELECT * FROM carddav_addressbooks WHERE (("user_id" = '1'))
[27-Sep-2021 14:01:30 +0200]: <a719cj3j> [1 DBG] internalGet query: SELECT * FROM carddav_addressbooks WHERE (("user_id" = '1'))

carddav_http.log

[27-Sep-2021 14:01:29 +0200]: <a719cj3j> [2 NFO] "PROPFIND /remote.php/dav/addressbooks/users/myuser/contacts/ HTTP/1.1" 401
>>>>>>>>
PROPFIND /remote.php/dav/addressbooks/users/myuser/contacts/ HTTP/1.1
Content-Length: 205
User-Agent: GuzzleHttp/7
Host: cloud.mydomain.tld
Depth: 0
Content-Type: application/xml; charset=UTF-8
Prefer: return=minimal
Authorization: --- REDACTED BY MStilkerich\CardDavAddressbook4Roundcube\RoundcubeLogger ---

<?xml version="1.0"?>
<DAV:propfind xmlns:DAV="DAV:" xmlns:CARDDAV="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/">
 <DAV:prop>
  <DAV:resourcetype/>
 </DAV:prop>
</DAV:propfind>

<<<<<<<<
HTTP/1.1 401 Unauthorized
Server: nginx
Date: Mon, 27 Sep 2021 12:01:29 GMT
Content-Type: application/xml; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: oc_sessionPassphrase=K0pRKc5jRyaHixncYTVGATS3%2Bmav05kubEG2ajlJVafAbOh3Xx73MDprQpr83x3NsatGACyfCDnjEyMMf55mhXZJ%2Bin5RAWDrDcM9WNX2059FXeQuJ%2FLL6D%2F1O7VY7z7; path=/; secure; HttpOnly; SameSite=Lax
Set-Cookie: ocqgcz6lzt8v=h8h1ouds0imju5vin6o9n47lck; path=/; secure; HttpOnly; SameSite=Lax
Set-Cookie: __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax
Set-Cookie: __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=strict
Content-Security-Policy: default-src 'none';
WWW-Authenticate: Bearer realm="Nubla", Basic realm="Nubla", charset="UTF-8"
Strict-Transport-Security: max-age=15768000; includeSubDomains; preload;
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Robots-Tag: none
X-XSS-Protection: 1; mode=block

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
  <s:message>No public access to this resource., Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured</s:message>
</d:error>

--------
NULL

nextcloud config.php

  'oidc_login_provider_url' => 'https://auth.mydomain.tld',
  'oidc_login_client_id' => 'xxxxx',
  'oidc_login_client_secret' => 'yyyyyy',
  'oidc_login_auto_redirect' => true,
  'oidc_login_logout_url' => 'https://auth.mydomain.tld/logout',
  'oidc_login_hide_password_form' => true,
  'oidc_login_attributes' =>
  array (
    'id' => 'sub',
    'name' => 'name',
    'mail' => 'email',
    'quota' => 'ownCloudQuota',
    'home' => 'homeDirectory',
    'ldap_uid' => 'uid',
    'groups' => 'groups',
  ),
  'oidc_login_default_group' => '',
  'oidc_login_use_external_storage' => false,
  'oidc_login_scope' => 'profile email groups',
  'oidc_login_proxy_ldap' => false,
  'oidc_login_disable_registration' => false,
  'oidc_login_redir_fallback' => false,
  'oidc_login_tls_verify' => true,
  'oidc_login_default_quota' => '10737418240',
  'oidc_create_groups' => false,
  'oidc_login_webdav_enabled' => true,
  'oidc_login_public_key_caching_time' => 86400,
  'oidc_login_min_time_between_jwks_requests' => 10,
  'oidc_login_well_known_caching_time' => 86400,

carddav config.inc.php

$prefs['_GLOBAL']['fixed'] = false;
$prefs['_GLOBAL']['hide_preferences'] = false;
$prefs['_GLOBAL']['pwstore_scheme'] = 'plain';
$prefs['_GLOBAL']['loglevel'] = \Psr\Log\LogLevel::DEBUG;
$prefs['_GLOBAL']['loglevel_http'] = \Psr\Log\LogLevel::DEBUG;
$prefs['Personnel'] = [
	'name'         =>  'Personnel',
	'url'          =>  'https://cloud.mydomain.tld/remote.php/dav/addressbooks/users/%l/contacts/',
	'username'     =>  '',
	'password'     =>  '%b',
	'active'       =>  true,
	'readonly'     =>  false,
	'refresh_time' => '02:00:00',
	'fixed'        =>  [],
	'require_always' => ['email'],
	'hide' => false,
];

@mstilkerich
Copy link

Hi. I run nextcloud 22.1.1 with nextcloud-oidc-login v2.1.0. I installed a functional roundcube 1.5beta with rcmcarddav 4.2.0, and I try to plug rcmcarddav to nextcloud. The OIDC server is canaille (not keycloak). The OIDC login works correctly both in roundcube and nextcloud.

However it seems that rcmcarddav does not succeed to authenticate against nextcloud and I get a 401 error in the logs. This looks somewhat similar to the issue you had @mstilkerich and it seems you had a solution related to the aud claim but I am not sure what is it, as the configuration instructions seems to be exclusively for keycloak.

Hello,
I don't know if this is the right place to discuss this, but I'll answer nonetheless: Nextcloud will only accept the token if the "aud" property of the token contains nextcloud. This indicates that this token was meant to be used with nextcloud. This is what you do with the Audience mapper in the documentation bit you referred. For your AUTH server, you will also have to configure it such that a token issued to the roundcube client application includes nextcloud in the intended audience (aud). If you can't figure that out from the documentation of your AUTH server, maybe seek for support there.

(From the error message you get from nextcloud, you can see that rcmcarddav supplied a bearer token for authentication, but it was subsequently rejected, so I believe chances are the above is in fact the issue you are facing).

@azmeuk
Copy link
Collaborator

azmeuk commented Oct 1, 2021

Thank you for the details. Is the nextcloud scope required too or is it just some Keycloak only configuration?

I tuned my setup so the aud claim in the generated id_token for roundcube is now correct and embed the nextcloud client ID.

Now I face a new problem: I have set additional logs into the code, just here:

private function login(string $bearerToken) {

The token endpoint of my identity server return an access_token and an id_token. I can see that in the above login function, the $bearerToken value is the access_token instead of the id_token. Obviously it fails to read the aud claim. I am not sure which fault it is.

By setting a debug log in rmccarddav, I can see that the $_SESSION['oauth_token'] array does not contain any id_token field.

https://github.com/mstilkerich/rcmcarddav/blob/512bcb61fc7f64bb57ef5f6a521d12a580c4b003/src/Config.php#L146

Maybe it is more related to rcmcarddav and roundcube and we should continue the discussion somewhere else?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants