aboutsummaryrefslogtreecommitdiffstats
path: root/roles/sabredav
diff options
context:
space:
mode:
authorStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:23:43 -0500
committerStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:52:13 -0500
commit0261e875679f1bf63c8d689da7fc7e014597885d (patch)
tree3f19cd74a0c1070944f75437f30b098d6ef2ffcb /roles/sabredav
downloadselfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.tar.gz
selfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.zip
initial commit
Diffstat (limited to 'roles/sabredav')
-rw-r--r--roles/sabredav/defaults/main.yml7
-rw-r--r--roles/sabredav/tasks/composer.yml10
-rw-r--r--roles/sabredav/tasks/database.yml46
-rw-r--r--roles/sabredav/tasks/freeipa.yml27
-rw-r--r--roles/sabredav/tasks/main.yml77
-rw-r--r--roles/sabredav/templates/var/www/sabredav/server.php.j261
-rw-r--r--roles/sabredav/vars/main.yml60
7 files changed, 288 insertions, 0 deletions
diff --git a/roles/sabredav/defaults/main.yml b/roles/sabredav/defaults/main.yml
new file mode 100644
index 0000000..87b98ee
--- /dev/null
+++ b/roles/sabredav/defaults/main.yml
@@ -0,0 +1,7 @@
+sabredav_version: master
+sabredav_user: s-sabredav
+sabredav_db_name: sabredav
+sabredav_db_host: '{{ postgresql_host }}'
+sabredav_imip_from: calendar-noreply@{{ email_domain }}
+sabredav_access_group: role-dav-access
+sabredav_kerberized_cidrs: '{{ kerberized_cidrs }}'
diff --git a/roles/sabredav/tasks/composer.yml b/roles/sabredav/tasks/composer.yml
new file mode 100644
index 0000000..c3aaedd
--- /dev/null
+++ b/roles/sabredav/tasks/composer.yml
@@ -0,0 +1,10 @@
+- name: download composer installer
+ get_url:
+ url: '{{ sabredav_composer_url }}'
+ dest: /tmp/composer-setup.php
+
+- name: install composer
+ command: >-
+ php /tmp/composer-setup.php
+ --install-dir=/usr/local/bin
+ --filename=composer
diff --git a/roles/sabredav/tasks/database.yml b/roles/sabredav/tasks/database.yml
new file mode 100644
index 0000000..0089788
--- /dev/null
+++ b/roles/sabredav/tasks/database.yml
@@ -0,0 +1,46 @@
+- name: create database
+ postgresql_db:
+ name: '{{ sabredav_db_name }}'
+ state: present
+ delegate_to: "{{ postgresql_inventory_host }}"
+ become: yes
+ become_user: postgres
+
+- name: create database user
+ postgresql_user:
+ name: '{{ sabredav_user }}'
+ db: '{{ sabredav_db_name }}'
+ priv: ALL
+ state: present
+ delegate_to: "{{ postgresql_inventory_host }}"
+ become: yes
+ become_user: postgres
+
+- name: check if database schema is initialized
+ postgresql_query:
+ login_user: '{{ sabredav_user }}'
+ login_host: '{{ sabredav_db_host }}'
+ db: '{{ sabredav_db_name }}'
+ query: SELECT 1 FROM calendars
+ become: yes
+ become_user: apache
+ environment:
+ GSS_USE_PROXY: 'yes'
+ register: sabredav_check_db
+ failed_when: no
+
+- name: initialize database schema
+ postgresql_query:
+ login_user: '{{ sabredav_user }}'
+ login_host: '{{ sabredav_db_host }}'
+ db: '{{ sabredav_db_name }}'
+ path_to_script: '{{ sabredav_home }}/pgsql.schema.sql'
+ as_single_query: yes
+ become: yes
+ become_user: apache
+ environment:
+ GSS_USE_PROXY: 'yes'
+ when:
+ - sabredav_check_db.msg is defined
+ - sabredav_check_db.msg is search('relation "calendars" does not exist')
+
diff --git a/roles/sabredav/tasks/freeipa.yml b/roles/sabredav/tasks/freeipa.yml
new file mode 100644
index 0000000..d2c841e
--- /dev/null
+++ b/roles/sabredav/tasks/freeipa.yml
@@ -0,0 +1,27 @@
+- name: create user
+ ipauser:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ name: '{{ sabredav_user }}'
+ loginshell: /sbin/nologin
+ homedir: '{{ sabredav_home }}'
+ givenname: SabreDAV
+ sn: Service Account
+ state: present
+ run_once: yes
+
+- name: retrieve user keytab
+ include_role:
+ name: freeipa_keytab
+ vars:
+ keytab_principal: '{{ sabredav_user }}'
+ keytab_path: '{{ sabredav_keytab }}'
+
+- name: create access group
+ ipagroup:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ name: '{{ sabredav_access_group }}'
+ nonposix: yes
+ state: present
+ run_once: yes
diff --git a/roles/sabredav/tasks/main.yml b/roles/sabredav/tasks/main.yml
new file mode 100644
index 0000000..36b8326
--- /dev/null
+++ b/roles/sabredav/tasks/main.yml
@@ -0,0 +1,77 @@
+- name: install packages
+ dnf:
+ name: '{{ sabredav_packages }}'
+ state: present
+
+- name: create webroot
+ file:
+ path: '{{ sabredav_home }}'
+ state: directory
+
+- name: clone git repository
+ git:
+ repo: '{{ sabredav_git_repo }}'
+ dest: '{{ sabredav_home }}'
+ version: '{{ sabredav_version }}'
+
+- name: set permissions on writeable directories
+ file:
+ path: '{{ sabredav_home }}/{{ item }}'
+ state: directory
+ mode: 0770
+ owner: apache
+ group: apache
+ setype: httpd_sys_rw_content_t
+ loop: '{{ sabredav_writable_dirs }}'
+
+- name: set selinux context on writeable directories
+ sefcontext:
+ target: '{{ sabredav_home }}/{{ item }}(/.*)?'
+ setype: httpd_sys_rw_content_t
+ state: present
+ loop: '{{ sabredav_writable_dirs }}'
+ register: sabredav_writeable_sefcontext
+ tags: selinux
+
+- name: apply selinux context to writeable directories
+ command: 'restorecon -R {{ sabredav_home }}/{{ item }}'
+ when: sabredav_writeable_sefcontext.results[index].changed
+ loop: '{{ sabredav_writable_dirs }}'
+ loop_control:
+ index_var: index
+ tags: selinux
+
+- import_tasks: freeipa.yml
+ tags: freeipa
+
+- name: configure gssproxy for kerberized postgres
+ include_role:
+ name: gssproxy_client
+ vars:
+ gssproxy_name: sabredav
+ gssproxy_section: service/php-fpm
+ gssproxy_client_keytab: '{{ sabredav_keytab }}'
+ gssproxy_cred_usage: initiate
+ gssproxy_euid: apache
+
+- name: check if composer is installed
+ stat:
+ path: /usr/local/bin/composer
+ register: stat_composer
+
+- name: install composer
+ include_tasks: composer.yml
+ when: not stat_composer.stat.exists
+
+- name: install dependencies using composer
+ composer:
+ command: install
+ working_dir: '{{ sabredav_home }}'
+
+- name: generate sabredav configuration
+ template:
+ src: '{{ sabredav_home[1:] }}/server.php.j2'
+ dest: '{{ sabredav_home }}/server.php'
+
+- import_tasks: database.yml
+ tags: database
diff --git a/roles/sabredav/templates/var/www/sabredav/server.php.j2 b/roles/sabredav/templates/var/www/sabredav/server.php.j2
new file mode 100644
index 0000000..36bc973
--- /dev/null
+++ b/roles/sabredav/templates/var/www/sabredav/server.php.j2
@@ -0,0 +1,61 @@
+<?php
+
+// timezone
+date_default_timezone_set('UTC');
+
+// database
+$pdo = new PDO('pgsql:dbname={{ sabredav_db_name }};host={{ sabredav_db_host }}', '{{ sabredav_user }}');
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+// autoloader
+require_once 'vendor/autoload.php';
+
+// freeipa
+$ipa = new \FreeIPA\Connection();
+$allowedGroups = ['{{ sabredav_access_group }}'];
+
+// backends
+$principalBackend = new \FreeIPA\PrincipalBackend($ipa, $allowedGroups);
+$caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
+$carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
+$authBackend = new \FreeIPA\AuthBackend($ipa, $caldavBackend, $carddavBackend, $allowedGroups);
+$lockBackend = new \Sabre\DAV\Locks\Backend\PDO($pdo);
+
+// directory structure
+$server = new Sabre\DAV\Server([
+ new \Sabre\CalDAV\Principal\Collection($principalBackend),
+ new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend),
+ new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend),
+ new \Sabre\DAVACL\FS\HomeCollection($principalBackend, __DIR__.'/webdav')
+]);
+
+// plugins
+$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend,'SabreDAV'));
+$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
+$server->addPlugin(new \Sabre\DAV\Sync\Plugin());
+$server->addPlugin(new \Sabre\DAV\Sharing\Plugin());
+
+$aclPlugin = new \Sabre\DAVACL\Plugin();
+$aclPlugin->hideNodesFromListings = true;
+$server->addPlugin($aclPlugin);
+
+// webdav plugins
+$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
+$server->addPlugin(new \Sabre\DAV\Browser\GuessContentType());
+$server->addPlugin(new \Sabre\DAV\TemporaryFileFilterPlugin(__DIR__.'/tmpdata'));
+
+// caldav plugins
+$server->addPlugin(new \Sabre\CalDAV\Plugin());
+$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
+$server->addPlugin(new \Sabre\CalDAV\Schedule\IMipPlugin('{{ sabredav_imip_from }}'));
+$server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
+$server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
+$server->addPlugin(new \Sabre\CalDAV\SharingPlugin());
+$server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
+
+// carddav plugins
+$server->addPlugin(new \Sabre\CardDAV\Plugin());
+$server->addPlugin(new \Sabre\CardDAV\VCFExportPlugin());
+
+// lets goooooo
+$server->exec();
diff --git a/roles/sabredav/vars/main.yml b/roles/sabredav/vars/main.yml
new file mode 100644
index 0000000..6463d37
--- /dev/null
+++ b/roles/sabredav/vars/main.yml
@@ -0,0 +1,60 @@
+sabredav_packages:
+ - php
+ - php-json
+ - php-ldap
+ - php-mbstring
+ - php-opcache
+ - php-pdo
+ - php-pgsql
+ - php-pecl-zip
+ - php-xml
+ - python3-psycopg2
+ - git
+
+sabredav_composer_url: https://getcomposer.org/installer
+
+sabredav_git_repo: https://github.com/sacredheartsc/sabredav-freeipa
+
+sabredav_home: /var/www/sabredav
+sabredav_keytab: /var/lib/gssproxy/clients/{{ sabredav_user }}.keytab
+
+sabredav_writable_dirs:
+ - webdav
+ - tmpdata
+
+sabredav_php_environment:
+ GSS_USE_PROXY: 'yes'
+
+sabredav_php_flags:
+ output_buffering: no
+ always_populate_raw_post_data: no
+ mbstring.func_overload: no
+
+sabredav_archive_shell: >-
+ TIMESTAMP=$(date +%Y%m%d%H%M%S);
+ tar czf "webdav-${TIMESTAMP}.tar.gz"
+ --transform "s|^\.|webdav-${TIMESTAMP}|"
+ -C "{{ sabredav_home }}/webdav" .
+
+sabredav_apache_config: |
+ Redirect /.well-known/caldav /server.php
+ Redirect /.well-known/carddav /server.php
+
+ RewriteEngine On
+ RewriteCond %{REQUEST_URI} !^/\.well-known/
+ RewriteRule .* /server.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
+
+ <Location />
+ AuthName "FreeIPA Single Sign-On"
+ <If "{% for cidr in sabredav_kerberized_cidrs %}-R '{{ cidr }}'{% if not loop.last %} || {% endif %}{% endfor %}">
+ AuthType GSSAPI
+ GssapiLocalName On
+ {{ apache_gssapi_session_config }}
+ </If>
+ <Else>
+ AuthType Basic
+ AuthBasicProvider ldap
+ </Else>
+ {{ apache_ldap_config }}
+ Require ldap-attribute memberof=cn={{ sabredav_access_group }},{{ freeipa_group_basedn }}
+ </Location>