mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-06-03 10:50:20 +00:00
ejabberd: Add let's encrypt component for managing certificates
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
This commit is contained in:
parent
9fd1b95244
commit
49b543599a
111
actions/ejabberd
111
actions/ejabberd
@ -21,11 +21,10 @@ Configuration helper for the ejabberd service
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import socket
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
from distutils.version import LooseVersion as LV
|
||||
|
||||
import ruamel.yaml
|
||||
@ -56,7 +55,10 @@ def parse_arguments():
|
||||
help='The domain name that will be used by the XMPP service.')
|
||||
|
||||
# Setup ejabberd configuration
|
||||
subparsers.add_parser('setup', help='Setup ejabberd configuration')
|
||||
setup = subparsers.add_parser('setup', help='Setup ejabberd configuration')
|
||||
setup.add_argument(
|
||||
'--domainname',
|
||||
help='The domain name that will be used by the XMPP service.')
|
||||
|
||||
# Prepare ejabberd for hostname change
|
||||
pre_hostname_change = subparsers.add_parser(
|
||||
@ -103,7 +105,7 @@ def subcommand_pre_install(arguments):
|
||||
input=b'ejabberd ejabberd/hostname string ' + domainname.encode())
|
||||
|
||||
|
||||
def subcommand_setup(_):
|
||||
def subcommand_setup(arguments):
|
||||
"""Enabled LDAP authentication"""
|
||||
with open(EJABBERD_CONFIG, 'r') as file_handle:
|
||||
conf = ruamel.yaml.round_trip_load(file_handle, preserve_quotes=True)
|
||||
@ -122,7 +124,7 @@ def subcommand_setup(_):
|
||||
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
||||
ruamel.yaml.round_trip_dump(conf, file_handle)
|
||||
|
||||
upgrade_config()
|
||||
upgrade_config(arguments.domainname)
|
||||
|
||||
try:
|
||||
subprocess.check_output(['ejabberdctl', 'restart'])
|
||||
@ -130,7 +132,7 @@ def subcommand_setup(_):
|
||||
print('Failed to restart ejabberd with new configuration: %s', err)
|
||||
|
||||
|
||||
def upgrade_config():
|
||||
def upgrade_config(domain):
|
||||
"""Fix the config file by removing deprecated settings"""
|
||||
current_version = _get_version()
|
||||
if not current_version:
|
||||
@ -154,6 +156,14 @@ def upgrade_config():
|
||||
if listen_port['port'] == 5280:
|
||||
listen_port['port'] = 5443
|
||||
|
||||
cert_dir = pathlib.Path('/etc/ejabberd/letsencrypt') / domain
|
||||
cert_file = str(cert_dir / 'ejabberd.pem')
|
||||
cert_file = ruamel.yaml.scalarstring.DoubleQuotedScalarString(cert_file)
|
||||
conf['s2s_certfile'] = cert_file
|
||||
for listen_port in conf['listen']:
|
||||
if 'certfile' in listen_port:
|
||||
listen_port['certfile'] = cert_file
|
||||
|
||||
# Write changes back to the file
|
||||
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
||||
ruamel.yaml.round_trip_dump(conf, file_handle)
|
||||
@ -220,9 +230,6 @@ def subcommand_change_domainname(arguments):
|
||||
# If new domainname is blank, use hostname instead.
|
||||
domainname = socket.gethostname()
|
||||
|
||||
action_utils.service_stop('ejabberd')
|
||||
subprocess.call(['pkill', '-u', 'ejabberd'])
|
||||
|
||||
# Add updated domainname to ejabberd hosts list.
|
||||
with open(EJABBERD_CONFIG, 'r') as file_handle:
|
||||
conf = ruamel.yaml.round_trip_load(file_handle, preserve_quotes=True)
|
||||
@ -233,8 +240,6 @@ def subcommand_change_domainname(arguments):
|
||||
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
||||
ruamel.yaml.round_trip_dump(conf, file_handle)
|
||||
|
||||
action_utils.service_start('ejabberd')
|
||||
|
||||
|
||||
def subcommand_mam(argument):
|
||||
"""Enable, disable, or get status of Message Archive Management (MAM)."""
|
||||
@ -284,90 +289,6 @@ def subcommand_mam(argument):
|
||||
subprocess.call(['ejabberdctl', 'reload_config'])
|
||||
|
||||
|
||||
def subcommand_letsencrypt(arguments):
|
||||
"""
|
||||
Add/drop usage of Let's Encrypt cert. The command 'add' applies only to
|
||||
current domain, will be called by action 'letsencrypt run_renew_hooks',
|
||||
when certbot renews the cert (if ejabberd is selected for cert use).
|
||||
Drop of a cert must be possible for any domain to respond to domain change.
|
||||
"""
|
||||
current_domain = config.get_domainname()
|
||||
|
||||
with open(EJABBERD_CONFIG, 'r') as file_handle:
|
||||
conf = ruamel.yaml.round_trip_load(file_handle, preserve_quotes=True)
|
||||
|
||||
if arguments.domain is not None and arguments.domain not in conf['hosts']:
|
||||
print('Aborted: Current domain "%s" not configured for ejabberd.' %
|
||||
arguments.domain)
|
||||
sys.exit(1)
|
||||
|
||||
if arguments.command == 'add' and arguments.domain is not None \
|
||||
and arguments.domain != current_domain:
|
||||
print('Aborted: Only certificate of current domain "%s" can be added.'
|
||||
% current_domain)
|
||||
sys.exit(2)
|
||||
|
||||
if arguments.domain is None:
|
||||
arguments.domain = current_domain
|
||||
|
||||
cert_folder = '/etc/ejabberd/letsencrypt/' + arguments.domain
|
||||
cert_file = cert_folder + '/ejabberd.pem'
|
||||
|
||||
if arguments.command == 'add':
|
||||
le_folder = os.path.join(LE_LIVE_DIRECTORY, current_domain)
|
||||
le_privkey = os.path.join(le_folder, 'privkey.pem')
|
||||
le_fullchain = os.path.join(le_folder, 'fullchain.pem')
|
||||
|
||||
if not os.path.exists(le_folder):
|
||||
print('Aborted: No certificate directory at %s.' % le_folder)
|
||||
sys.exit(3)
|
||||
|
||||
if not os.path.exists(cert_folder):
|
||||
os.makedirs(cert_folder)
|
||||
shutil.chown(cert_folder, 'ejabberd', 'ejabberd')
|
||||
|
||||
with open(cert_file, 'w') as outfile:
|
||||
with open(le_privkey, 'r') as infile:
|
||||
for line in infile:
|
||||
if line.strip():
|
||||
outfile.write(line)
|
||||
with open(le_fullchain, 'r') as infile:
|
||||
for line in infile:
|
||||
if line.strip():
|
||||
outfile.write(line)
|
||||
shutil.chown(cert_file, 'ejabberd', 'ejabberd')
|
||||
os.chmod(cert_file, stat.S_IRUSR | stat.S_IWUSR)
|
||||
|
||||
cert_file = ruamel.yaml.scalarstring.DoubleQuotedScalarString(
|
||||
cert_file)
|
||||
conf['s2s_certfile'] = cert_file
|
||||
|
||||
for listen_port in conf['listen']:
|
||||
if 'certfile' in listen_port:
|
||||
listen_port['certfile'] = cert_file
|
||||
|
||||
else: # arguments.command == 'drop' (ensured by parser)
|
||||
orig_cert_file = ruamel.yaml.scalarstring.DoubleQuotedScalarString(
|
||||
EJABBERD_ORIG_CERT)
|
||||
|
||||
for listen_port in conf['listen']:
|
||||
if 'certfile' in listen_port \
|
||||
and listen_port['certfile'] == cert_file:
|
||||
listen_port['certfile'] = orig_cert_file
|
||||
|
||||
if conf['s2s_certfile'] == cert_file:
|
||||
conf['s2s_certfile'] = orig_cert_file
|
||||
|
||||
if os.path.exists(cert_folder):
|
||||
shutil.rmtree(cert_folder)
|
||||
|
||||
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
||||
ruamel.yaml.round_trip_dump(conf, file_handle)
|
||||
|
||||
if action_utils.service_is_running('ejabberd'):
|
||||
action_utils.service_restart('ejabberd')
|
||||
|
||||
|
||||
def _get_version():
|
||||
""" Get the current ejabberd version """
|
||||
try:
|
||||
|
||||
@ -19,6 +19,7 @@ FreedomBox app to configure ejabberd server.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pathlib
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@ -30,6 +31,7 @@ from plinth.daemon import Daemon
|
||||
from plinth.modules import config
|
||||
from plinth.modules.apache.components import Webserver
|
||||
from plinth.modules.firewall.components import Firewall
|
||||
from plinth.modules.letsencrypt.components import LetsEncrypt
|
||||
from plinth.signals import (domainname_change, post_hostname_change,
|
||||
pre_hostname_change)
|
||||
from plinth.utils import format_lazy
|
||||
@ -42,6 +44,8 @@ managed_services = ['ejabberd']
|
||||
|
||||
managed_packages = ['ejabberd']
|
||||
|
||||
managed_paths = [pathlib.Path('/etc/ejabberd/')]
|
||||
|
||||
name = _('ejabberd')
|
||||
|
||||
short_description = _('Chat Server')
|
||||
@ -104,6 +108,15 @@ class EjabberdApp(app_module.App):
|
||||
webserver = Webserver('webserver-ejabberd', 'jwchat-plinth')
|
||||
self.add(webserver)
|
||||
|
||||
letsencrypt = LetsEncrypt(
|
||||
'letsencrypt-ejabberd', domains=get_domains, daemons=['ejabberd'],
|
||||
should_copy_certificates=True,
|
||||
private_key_path='/etc/ejabberd/letsencrypt/{domain}/ejabberd.pem',
|
||||
certificate_path='/etc/ejabberd/letsencrypt/{domain}/ejabberd.pem',
|
||||
user_owner='ejabberd', group_owner='ejabberd',
|
||||
managing_app='ejabberd')
|
||||
self.add(letsencrypt)
|
||||
|
||||
daemon = Daemon('daemon-ejabberd', managed_services[0])
|
||||
self.add(daemon)
|
||||
|
||||
@ -129,11 +142,29 @@ def setup(helper, old_version=None):
|
||||
|
||||
helper.call('pre', actions.superuser_run, 'ejabberd',
|
||||
['pre-install', '--domainname', domainname])
|
||||
# XXX: Configure all other domain names
|
||||
helper.install(managed_packages)
|
||||
helper.call('post', actions.superuser_run, 'ejabberd', ['setup'])
|
||||
helper.call('post',
|
||||
app.get_component('letsencrypt-ejabberd').setup_certificates,
|
||||
[domainname])
|
||||
helper.call('post', actions.superuser_run, 'ejabberd',
|
||||
['setup', '--domainname', domainname])
|
||||
helper.call('post', app.enable)
|
||||
|
||||
|
||||
def get_domains():
|
||||
"""Return the list of domains that ejabberd is interested in.
|
||||
|
||||
XXX: Retrieve the list from ejabberd configuration.
|
||||
|
||||
"""
|
||||
setup_helper = globals()['setup_helper']
|
||||
if setup_helper.get_state() == 'needs-setup':
|
||||
return []
|
||||
|
||||
return [config.get_domainname()]
|
||||
|
||||
|
||||
def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
|
||||
"""
|
||||
Backup ejabberd database before hostname is changed.
|
||||
@ -165,8 +196,8 @@ def on_domainname_change(sender, old_domainname, new_domainname, **kwargs):
|
||||
del kwargs # Unused
|
||||
|
||||
actions.superuser_run(
|
||||
'ejabberd', ['change-domainname', '--domainname', new_domainname],
|
||||
run_in_background=True)
|
||||
'ejabberd', ['change-domainname', '--domainname', new_domainname])
|
||||
app.get_component('letsencrypt-ejabberd').setup_certificates()
|
||||
|
||||
|
||||
def diagnose():
|
||||
|
||||
@ -47,7 +47,7 @@ class EjabberdAppView(AppView):
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
"""Add service to the context data."""
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['domainname'] = config.get_domainname()
|
||||
context['domainname'] = ejabberd.get_domains()[0]
|
||||
context['clients'] = ejabberd.clients
|
||||
return context
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user