Installing Seafile with UCS LDAP synchronization

In this how-to, I will show you how to set up Seafile (or Seafile Pro) with LDAP sync of users and groups between Univention UCS and Seafile.

Installing Seafile with UCS LDAP synchronization

Setup Seafile

Yes, I know you can use the SeaFile from the UCS App Center, but I prefer to keep it on a separate server and also had a few issues with the App Center version that made it simpler for me to fix when the installation is separate. Let's get started.
I will skip all the details of the setup, the Seafile docs will explain more about it, my main focus will be the LDAP integration, but for the lazy ones out there, here's my docker-compose to get this started.

version: '2.0'
services:
  db:
    image: mariadb:10.1
    container_name: foo.example.com-mysql
    environment:
      - MYSQL_ROOT_PASSWORD=<INSERT MYSQL ROOT HERE> # Requested, set the root's password of MySQL service.
      - MYSQL_LOG_CONSOLE=true
    volumes:
      - /opt/docker/foo.example.com/seafile-mysql/db:/var/lib/mysql  # Requested, specifies the path to MySQL data persistent store.
    networks:
      - foo.example.com-net

  memcached:
    image: memcached:1.5.6
    container_name: foo.example.com-memcached
    entrypoint: memcached -m 256
    networks:
      - foo.example.com-net

  elasticsearch:
    image: seafileltd/elasticsearch-with-ik:5.6.16
    container_name: foo.example.com-elasticsearch
    environment:
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    mem_limit: 2g
    volumes:
      - /opt/docker/foo.example.com/seafile-elasticsearch/data:/usr/share/elasticsearch/data  # Requested, specifies the path to Elasticsearch data persistent store.
    networks:
      - foo.example.com-net

  seafile:
    image: docker.seadrive.org/seafileltd/seafile-pro-mc:latest
    container_name: foo.example.com-seafile
    ports:
      - "3300:80"
#      - "33443:443"  # If https is enabled, cancel the comment.
    volumes:
      - /opt/docker/foo.example.com/seafile-data:/shared   # Requested, specifies the path to Seafile data persistent store.
    environment:
      - DB_HOST=db
      - DB_ROOT_PASSWD=<INSERT MYSQL ROOT HERE> # Requested, the value shuold be root's password of MySQL service.
      - TIME_ZONE=Europe/Vienna # Optional, default is UTC. Should be uncomment and set to your local time zone.
      - SEAFILE_ADMIN_EMAIL=admin@example.net # Specifies Seafile admin user, default is 'me@example.com'
      - SEAFILE_ADMIN_PASSWORD=<ADMIN PASSWORD HERE> # Specifies Seafile admin password, default is 'asecret'
      - SEAFILE_SERVER_LETSENCRYPT=false # Whether to use https or not
      - SEAFILE_SERVER_HOSTNAME=foo.example.com # Specifies your host name if https is enabled
    depends_on:
      - db
      - memcached
      - elasticsearch
    networks:
      - foo.example.com-net

networks:
  foo.example.com-net:
docker-compose for saefile pro

Replace the MySQL root password <INSERT MYSQL ROOT HERE> in both places and define an admin user + password: <ADMIN PASSWORD HERE>

One note about the admin user, this admin user will consume a license from the SeaFile pro version. You can use the same user here as you have in LDAP but it will still consume two licenses! Bear in mind if you delete this user it will be recreated when starting up the docker-compose. I have also decided to skip role syncing via LDAP, I might look into that in the future but for my case, I only have one or a few admins and I prefer to create that via the Seafile admin interface and have only normal users synced to Seafile via LDAP.

Setup UCS for Seafile

There are some things you should do to make life easier when selecting which users and which groups you want to sync. Since SeaFile Pro has a pay per user licensing you might not want to add all the users to SeaFile, also the default UCS installation comes with more than 50 groups, having them all on SeaFile is probably not what you really want. So let's use some of the UCS features to make this more configurable.

Setup LDAP Search user

Proceed according to the UCS article "Cool Solution - LDAP search user / simple authentication account" to create a search user, we will need this later on.

Add new Group for Seafile users

The simplest way to decide which users should be synced to SeaFile is by creating a new group, every user assigned to this group will be synced to SeaFile so I will call this group seafile.

Add new parameter for groups

To be able to select which groups you want to sync to SeaFile you can either use some special naming like seaf_XXX and filter only these groups or use a custom parameter. Since I wouldn't like all my SeaFile groups to start with saef_ I decided to go with the second option, having a special parameter for the group.
To accomplish this, you need a new "Extended attribute" in the LDAP like I already used for the Mikrotik / RADIUS setup.

Go to Domain -> LDAP Directory and under univention -> custom attributes, add a new attribute.

new UCS custom attribute

Make it a "Settings: Extended attribute"

UCS extended attribute

Give the attribute a name, I think "SeafileGroup" fits the purpose of this parameter.

Seafile UCS Group Attribute

Under "module", define that it extends the "Group" settings.

UCS extend group module

Under LDAP mapping set the LDAP object class to univentionFreeAttributes and the LDAP attribute to univentionFreeAttributeN where N stands for the next free attribute. If you have not defined any attribute until now this would be univentionFreeAttribute1 if however you already have used one then just pick the next number here.

UCS free attribute


Create a new tab for UMC

UMC new tab


Define the Datatype as boolean and make the default false, by default I don't want to sync groups except when I explicitly click on the checkbox.

data type


Hit the "create LDAP object" button to create the group.

Create a new group

Ok now, go ahead and create a new group, call it "Test" and under the SeaFile tab enable the "Seafile group" option.

sync group to seafile

Configure LDAP on SeaFile

Open up ccnet.conf which you can find in /opt/docker/foo.example.com/seafile-data/seafile/conf (depending on your docker-compose settings) and add an LDAP section at the end of the configuration file.

[LDAP]
HOST = ldap://ucs.foo.net:7389
BASE = dc=foo,dc=net
USER_DN = uid=LDAPsearch,cn=users,dc=foo,dc=net
PASSWORD = <LDAP PASSWORD>
LOGIN_ATTR = mailPrimaryAddress
FILTER = memberOf=cn=seafile,cn=groups,dc=foo,dc=net

As host, enter the IP/Domain of your UCS, please note that my settings do not use SSL and since both instances are in my network I don't really need to. I also had some issues getting it connected to LDAPS so I just went without SSL.
The port 7389 is not a typo, I also had issues connecting to the main LDAP hence the 7389 port which connects directly to the slapd running on UCS.

Be careful with the BASE, if you follow the Seafile instructions and use something like cn=users,dc=foo,dc=net everything will work great until you want to sync groups! Use dc=foo,dc=net as the base and let the filter take care of the rest.
By setting the LOGIN_ATTR = mailPrimaryAddress you tell SeaFile to create the users based on the primary email address, you could also use uid here if you prefer to have users without an email address.

It's very important to have a primary email for every user if you want to use any mail features from Seafil!

Syncing LDAP users

Now to enable the LDAP sync, again in ccnet.conf add one more section at the end.

[LDAP_SYNC]
ENABLE_USER_SYNC = true
DEACTIVE_USER_IF_NOTFOUND = true
SYNC_INTERVAL = 60
USER_OBJECT_CLASS = person
ENABLE_EXTRA_USER_INFO_SYNC = true
FIRST_NAME_ATTR = givenName
LAST_NAME_ATTR = sn
UID_ATTR = uid

This will enable the user synchronization every 60 minutes. You can turn up the frequency during testing and dial it back once everything works.

Syncing groups

The group syncing is similar to the user sync but since I had set up LDAP base DN with cn=users it took me a while to figure out why it's not working and why no groups are synced but more on this later.

Add this to the LDAP_SYNC section

ENABLE_GROUP_SYNC = true
GROUP_OBJECT_CLASS = univentionGroup
GROUP_MEMBER_ATTR = uniqueMember
GROUP_FILTER = univentionFreeAttribute2=1
DEL_GROUP_IF_NOT_FOUND = true

Make sure to set the univentionFreeAttribute2 to match your attribute.
What this does is enable syncing of groups by searching LDAP for  univentionGroup with a univentionFreeAttribute2=1 and getting its members from uniqueMember.
This will now sync the groups and assign members to it according to the UCS settings.

You can now start up the SeaFile containers and should have a working synchronization against UCS for users, groups and user group assignments.

Debugging

There is a way according to the Seafile docs to test the LDAP settings but I could not make this work from the docker based version of Seafile so I did the LDAP searches via UCS to see what comes out.

Check the seafevents.log file to see what LDAP is doing. This file can be found under /opt/docker/foo.example.com/seafile-data/seafile/logs
Then a group is synced for example it should look like this:

[2020-02-28 11:44:28,751] [INFO] LDAP group sync result: add [0]group, update [1]group, delete [0]group

and it will also show you if there are any LDAP errors.

Finding users

Here is how you can find out which users will sync.

ldapsearch -x -D uid=LDAPsearch,cn=users,dc=foo,dc=net -b "dc=foo,dc=net" -s sub "(&(objectclass=person)(memberOf=cn=seafile,cn=groups,dc=foo,dc=net))" -W

Make sure to set the BASE DN (the -b parameter) to the same as in the ccnet.conf and let objectclass match your USER_OBJECT_CLASS setting.

Finding groups

Here is how you can find out which groups will sync.

ldapsearch -x -D uid=LDAPsearch,cn=users,dc=foo,dc=net -b "dc=foo,dc=net" -s sub "(&(objectclass=univentionGroup)(univentionFreeAttribute2=1))" -W

Make sure to set the BASE DN (the -b parameter) to the same as in the ccnet.conf and let objectclass match your GROUP_OBJECT_CLASS setting.
This will yield all found groups based on the settings in ccnet.conf and these groups will be synced.

That's it, I'm done! Let me know if you hit a bump on the road or any other issues come up.