mstilkerich / rcmcarddav

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

Shared address book is not added #339

Closed vdovenkov closed 3 years ago

vdovenkov commented 3 years ago

Installed on my server:

Also, trying to install RCMCardDAV v4.1.0 from release tarball.

Configuration CardDav: /usr/local/www/roundcube/plugins/carddav/config.inc.php

<?php

$prefs['_GLOBAL']['loglevel'] = \Psr\Log\LogLevel::DEBUG;
$prefs['_GLOBAL']['loglevel_http'] = \Psr\Log\LogLevel::DEBUG;

$prefs['CORP'] = [
    'name'           =>  'Addressbook',
    'username'       =>  '%u',
    'password'       =>  '%p',
    'url'            =>  'https://mail.domain.tld:5232/public/gab/', //path to PUBLIC addressbook
    'active'         =>  true,
    'readonly'       =>  true,
    'refresh_time'   => '02:00:00',
    'fixed'          =>  [ ],
    'require_always' => ['email'],
    'hide'           => false,
];

Radicale return one public address book (to authorized users only). Personal address books are not used yet.

Mail clients, such as Outlook and Thunderbird easily get the public address book, using the plugins (Outlook CalDav Synchronizer and CardBook).

With these settings, I get messages in the logs: /usr/local/www/roundcube/logs/carddav.log

[1 DBG] carddav::checkMigrations 
[1 DBG] internalGet query: SELECT `filename` FROM carddav_migrations 
[1 DBG] carddav::initPresets 
[1 DBG] internalGet query: SELECT * FROM carddav_addressbooks WHERE ((`user_id` = '46')) 
[2 NFO] Adding preset for myusername@domain.tld at URL https://mail.domain.tld:5232/public/gab/ 
[1 DBG] Starting discovery with input https://mail.domain.tld:5232/public/gab/ 
[1 DBG] Try context path /.well-known/carddav 
[2 NFO] Exception while querying current-user-principal: Expected Multistatus HTTP request was not successful (404 Not Found): The requested resource could not be found. 
[1 DBG] Try context path / 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[2 NFO] principal URL: https://mail.domain.tld:5232/myusername%40domain.tld/ 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[2 NFO] addressbook home: https://mail.domain.tld:5232/myusername%40domain.tld/ 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[1 DBG] Try context path /co 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[1 DBG] None of the available auth schemes worked 
[2 NFO] Exception while querying current-user-principal: Expected Multistatus HTTP request was not successful (403 Forbidden): Access to the requested resource forbidden. 
[1 DBG] Try context path /public/gab/ 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[2 NFO] principal URL: https://mail.domain.tld:5232/myusername%40domain.tld/ 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[2 NFO] addressbook home: https://mail.domain.tld:5232/myusername%40domain.tld/ 
[1 DBG] Trying auth scheme basic 
[1 DBG] Using auth scheme basic 
[1 DBG] internalGet query: SELECT * FROM carddav_addressbooks WHERE ((`user_id` = '46'))

/usr/local/www/roundcube/logs/errors.log

PHP Warning:  dns_get_record(): DNS Query failed in /usr/local/www/roundcube/plugins/carddav/vendor/mstilkerich/carddavclient/src/Services/Discovery.php on line 166

For some reason, the carddav plugin is trying to get a personal address book instead of a public one. And since it is empty, no address book is added.

Any ideas how to fix this?

mstilkerich commented 3 years ago

Hello,

yes, rcmcarddav discovers only addressbooks under the the addressbook home of the user. The public addressbook lives outside the user's addressbook-home and therefore is not found.

I will try to add a public addressbook to my test instance of radicale to get this working. I'd appreciate if you could share the bits of your radicale configuration that concern the setup of a public addressbook if possible.

vdovenkov commented 3 years ago

Hello Michael! Thanks for the quick response.

My radicale configuration is typical. However, I use Radicale Dovecot Auth.

/usr/local/etc/radicale/config

[server]
# CalDAV server hostnames separated by a comma
hosts = localhost:5234

# Max parallel connections
max_connections = 60

# Max size of request body (bytes)
max_content_length = 100000000

# SSL flag, enable HTTPS protocol
ssl = False

[encoding]

[auth]
# Authentication method
# Value: none | htpasswd | remote_user | http_x_remote_user
#type = none
type = radicale_dovecot_auth
auth_socket = /var/run/radicale/auth

[rights]
# Rights backend
# Value: none | authenticated | owner_only | owner_write | from_file
type = from_file

# File for rights management from_file
file = /usr/local/etc/radicale/rights

[storage]
# Storage backend
# Value: multifilesystem
type = multifilesystem

# Folder for storing local collections, created if not present
filesystem_folder = /var/radicale/collections

[web]

[logging]

[headers]

/usr/local/etc/radicale/rights

# Allow reading root collection for authenticated users
[root]
user: .+
collection:
permissions: R

# Allow reading and writing principal collection (same as user name)
[principal]
user: .+
collection: {user}
permissions: RW

# Allow reading and writing calendars and address books that are direct
# children of the principal collection
[calendars]
user: .+
collection: {user}/[^/]+
permissions: rw

# Allow reading collection "public" for authenticated users
[public-principal]
user: .+
collection: public
permissions: R

# Allow reading all calendars and address books that are direct children of
# the collection "public" for authenticated users
[public-calendars]
user: .+
collection: public/[^/]+
permissions: r

With the same settings for Roundcube 1.4.11, Radicale 3.0.6 and RCMCardDAV v3.0.3 on another server, it works as intended.

Adding a SRV and TXT records to the DNS did not give any result.

C:\Users\myusername>nslookup -type=SRV _carddavs._tcp.domain.tld
Server:  ns1.domain.tld
Address:  172.16.0.2

_carddavs._tcp.domain.tld       SRV service location:
          priority       = 10
          weight         = 20
          port           = 5232
          svr hostname   = mail.domain.tld
mail.domain.tld     internet address = 172.16.1.25

C:\Users\myusername>nslookup -type=TXT _carddavs._tcp.domain.tld
Server:  ns1.domain.tld
Address:  172.16.0.2

_carddavs._tcp.domain.tld       text =

        "path=/public"
mstilkerich commented 3 years ago

Hello,

AFAIK 3.0.3 did not use the discovery process for presets. From 4.0, rcmcarddav uniformly uses discovery to identify all addressbooks of the user. Essentially, it discovers the addressbook home of the user using a variety of mechanisms (DNS based / well-known URI / user input). This part works fine on your end (i.e., there is no issue with your DNS setup, DNS is just one of several ways to find the addressbook location). The addressbook home is supposed to be the parent collection of the user's addressbooks. Now if your users don't have any addressbooks, there will be nothing under the addressbook home, and thus nothing will be found.

Your public addressbook lives in a different place, but rcmcarddav does not look there. I'll think on how to fix it. With the current 4.1.0 it's as simple as trying if there is an addressbook at the URL entered by the user, but for 4.2.0 I intend to implement periodic re-discovery, and manually added addressbooks (i.e. that would not be discovered and hence be removed on rediscovery) will need some special treatment here. I expect I can provide a fixed 4.1.1 soon.

Thanks for providing the config. I was specifically interested in the rights file. I guess your create the public addressbook manually, because radicale web interface does only allow users to administrate their own addressbooks?

vdovenkov commented 3 years ago

Michael, you're right. I am creating an address book manually.

Еhis is how the directory structure looks like:

/var
    /radicale
        /collections
            /collection-root
                /myusername@domain.tld
                /public
                    /gab
                        /.Radicale.props
                        /1529825c-27c8-4cac-8e89-b2d49970eaa4.vcf
                        /304a7cbe-7ede-4df0-bf96-6d9c4885b76d.vcf
                        .
                        .
                        .
                /secondusername@domain.tld
                /thirdusername@domain.tld

This is how the .Radicale.props for a public book looks like: /var/radicale/collections/collection-root/public/gab/.Radicale.props

{
    "CR:addressbook-description": "Public address book",
    "D:displayname": "CORP Address book",
    "tag": "VADDRESSBOOK",
    "{http://inf-it.com/ns/ab/}addressbook-color": "#3ef3b3ff"
}
mstilkerich commented 3 years ago

(This is mostly a note to my future self :-))

There is different ways we can enable adding addressbooks that fail to be discovered because they are not under the addressbook home of the user. What is common to all options is that discovery remains as is when the entered URI does not point directly to an addressbook collection.

Option 1: When given URI points to an addressbook, skip discovery and add only that addressbook

This would allow admins and users to add any specific addressbook. The idea of the current rcmcarddav design is, however, that a user will be shown all their addressbooks and can enable/disable those they want to see using the corresponding setting in the preferences (active). Users also are not always aware of the differences in URIs and may have an addressbook URI simply because that's what the web interface of nextcloud (or whatever they use) gave them. Consequently, this would be a quite disruptive change and may also not be in the interest of users (admins, on the other hand, might prefer this ability).

For admins this option allows to define presets in a fairly flexible way, particularly to have global read-only addressbooks and also add the user's addressbooks as writeable addressbooks using a different preset.

In addition, when looking into the future, when we think about periodic re-discovery it would require treating such "individual addressbooks" as a special case, otherwise upon the next rediscovery all the other addressbooks of the user would show up.

Option 2: When given URI points to an addressbook, add this addressbook and additionally any discovered ones

This behavior would be most compatible and only extend existing behavior. As long a the URI points to an individual addressbook of the user, nothing would change to the current behavior, only the option to additionally have external addressbooks would be added.

The downside from an admin perspective is that they cannot define a preset for a public addressbook without also having all the regular addressbooks of the user discovered. This is bad if the admin wants to use different settings (especially concerning readonly) for the public addressbook.

Option 3: When given URI points to an addressbook: If the addressbook is a child of the user's addressbook-home collection, perform discovery and add all found addressbooks. Otherwise, only add the specified addressbook.

This is like Option 1, but remains backwards compatible. It also enables an admin to define different settings for non-individual addressbooks and those that belong to a user. It has the same downside for external addressbooks concerning rediscovery, i.e. they would have to be marked in a way that limits re-discovery to deleting the addressbook when it does not exist anymore, without an attempt to discover the new location.

Unfortunately, this is also the one with the most effort to implement.

Decision

Because it remains backwards compatible and still provides admins with the anticipated use case that non-individual addressbooks may be readonly, whereas individual addressbooks may be read-write, I will aim for option 3.

mstilkerich commented 3 years ago

This is fixed on the branch issue_339. Implementation is done and docs are updated, but I want to create test cases before doing a release.

It would be great if you could let me know if it now works for you.

vdovenkov commented 3 years ago

Michael, thank you very much! Contacts appeared from the public addressbook.

mstilkerich commented 3 years ago

Hi, I'm glad it works for you :+1:

Thanks for reporting this and helping me in quickly getting a working test environment for this.

In the meantime, I have added test cases and will release 4.1.1 soon.