diff --git a/actions/ssh b/actions/ssh
index 8c3c0c8eb..1c3035304 100755
--- a/actions/ssh
+++ b/actions/ssh
@@ -15,7 +15,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
-
"""
Configuration helper for SSH server.
"""
@@ -28,6 +27,8 @@ import stat
import subprocess
import sys
+import augeas
+
from plinth import action_utils
@@ -47,6 +48,13 @@ def parse_arguments():
set_keys.add_argument('--username')
set_keys.add_argument('--keys')
+ subparsers.add_parser('get-password-config',
+ help='Get SSH password auth configuration')
+
+ set_password_config = subparsers.add_parser(
+ 'set-password-config', help='Set SSH password auth configuration')
+ set_password_config.add_argument('--value')
+
subparsers.required = True
return parser.parse_args()
@@ -107,6 +115,33 @@ def subcommand_set_keys(arguments):
os.chmod(key_file_path, stat.S_IRUSR | stat.S_IWUSR)
+def _load_augeas():
+ """Initialize augeas for this app's configuration file."""
+ aug = augeas.Augeas(
+ flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD)
+ aug.set('/augeas/load/Sshd/lens', 'Sshd.lns')
+ aug.set('/augeas/load/Sshd/incl[last() + 1]', '/etc/ssh/sshd_config')
+ aug.load()
+
+ return aug
+
+
+def subcommand_get_password_config(_):
+ """Retrieve value of password authentication from sshd configuration."""
+ aug = _load_augeas()
+ field_path = '/files/etc/ssh/sshd_config/PasswordAuthentication'
+ get_value = aug.get(field_path)
+ print(get_value or 'yes')
+
+
+def subcommand_set_password_config(arguments):
+ """Set value of password authentication in sshd configuration."""
+ aug = _load_augeas()
+ aug.set('/files/etc/ssh/sshd_config/PasswordAuthentication',
+ arguments.value)
+ aug.save()
+
+
def main():
"""Parse arguments and perform all duties."""
arguments = parse_arguments()
diff --git a/plinth/modules/ssh/__init__.py b/plinth/modules/ssh/__init__.py
index 2169ab7a2..5a079d64b 100644
--- a/plinth/modules/ssh/__init__.py
+++ b/plinth/modules/ssh/__init__.py
@@ -105,3 +105,9 @@ def get_host_keys():
host_keys.append(match.groupdict())
return host_keys
+
+
+def is_password_authentication_disabled():
+ """Return if ssh password authentication is enabled."""
+ return actions.superuser_run('ssh',
+ ['get-password-config']).strip() == 'no'
diff --git a/plinth/modules/ssh/forms.py b/plinth/modules/ssh/forms.py
new file mode 100644
index 000000000..439e55890
--- /dev/null
+++ b/plinth/modules/ssh/forms.py
@@ -0,0 +1,35 @@
+#
+# This file is part of FreedomBox.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+"""
+FreedomBox configuration form for OpenSSH server.
+"""
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+from plinth.forms import AppForm
+
+
+class SSHServerForm(AppForm):
+ """SSH server configuration form."""
+ password_auth_disabled = forms.BooleanField(
+ label=_('Disable password authentication'),
+ help_text=_('Improves security by preventing password guessing. '
+ 'Ensure that you have setup SSH keys in your '
+ 'administrator user account before enabling this option.'),
+ required=False,
+ )
diff --git a/plinth/modules/ssh/views.py b/plinth/modules/ssh/views.py
index 83ce5b5f0..47d381e38 100644
--- a/plinth/modules/ssh/views.py
+++ b/plinth/modules/ssh/views.py
@@ -17,10 +17,16 @@
"""
Views for the SSH module
"""
+from django.contrib import messages
+from django.utils.translation import ugettext_lazy as _
+from plinth import action_utils, actions
from plinth.modules import ssh
from plinth.views import AppView
+from . import is_password_authentication_disabled
+from .forms import SSHServerForm
+
class SshAppView(AppView):
app_id = 'ssh'
@@ -28,9 +34,43 @@ class SshAppView(AppView):
description = ssh.description
port_forwarding_info = ssh.port_forwarding_info
template_name = 'ssh.html'
+ form_class = SSHServerForm
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['host_keys'] = ssh.get_host_keys()
return context
+
+ def get_initial(self):
+ """Initial form value"""
+ initial = super().get_initial()
+ initial.update({
+ 'password_auth_disabled': is_password_authentication_disabled(),
+ })
+
+ return initial
+
+ def form_valid(self, form):
+ """Apply changes from the form"""
+ old_config = self.get_initial()
+ new_config = form.cleaned_data
+
+ def is_field_changed(field):
+ return old_config[field] != new_config[field]
+
+ passwd_auth_changed = is_field_changed('password_auth_disabled')
+ if passwd_auth_changed:
+ if new_config['password_auth_disabled']:
+ passwd_auth = 'no'
+ message = _('SSH authentication with password disabled.')
+ else:
+ passwd_auth = 'yes'
+ message = _('SSH authentication with password enabled.')
+
+ actions.superuser_run(
+ 'ssh', ['set-password-config', '--value', passwd_auth])
+ actions.superuser_run('service', ['reload', 'ssh'])
+ messages.success(self.request, message)
+
+ return super().form_valid(form)