mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
ssh: action script: Require user credentials when editing ssh keys
This change prevents the plinth user to set the ssh-keys without knowing the user password. - Debian: added new dependency python3-pampy to authenticate users. - Added additional required parameter --auth-user to the 'actions/ssh set-keys' command. A password should be provided through STDIN. Tests performed: - running 'actions/ssh set-keys' with empty or wrong admin credentials fails. - running 'actions/ssh set-keys' with correct admin credentials succeeds. - running 'actions/ssh set-keys' with correct non-admin credentials succeeds if the --username is the same user. - running 'actions/ssh set-keys' with correct non-admin credentials fails if the --username is a different user. Signed-off-by: Veiko Aasa <veiko17@disroot.org> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
98f9d59ef1
commit
6b61ca2f18
31
actions/ssh
31
actions/ssh
@ -5,6 +5,7 @@ Configuration helper for SSH server.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import grp
|
||||
import os
|
||||
import pwd
|
||||
import shutil
|
||||
@ -14,7 +15,7 @@ import sys
|
||||
|
||||
import augeas
|
||||
|
||||
from plinth import action_utils
|
||||
from plinth import action_utils, utils
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
@ -32,6 +33,7 @@ def parse_arguments():
|
||||
help='Set SSH authorized keys')
|
||||
set_keys.add_argument('--username', required=True, type=_managed_user)
|
||||
set_keys.add_argument('--keys', required=True)
|
||||
set_keys.add_argument('--auth-user', required=True)
|
||||
|
||||
subparsers.add_parser('get-password-config',
|
||||
help='Get SSH password auth configuration')
|
||||
@ -44,6 +46,24 @@ def parse_arguments():
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def _validate_user(username, must_be_admin=True):
|
||||
"""Validate a user."""
|
||||
if must_be_admin:
|
||||
try:
|
||||
admins = grp.getgrnam('admin').gr_mem
|
||||
except KeyError:
|
||||
admins = []
|
||||
|
||||
if username not in admins:
|
||||
msg = '"{}" is not authorized to perform this action'.format(
|
||||
username)
|
||||
raise argparse.ArgumentTypeError(msg)
|
||||
|
||||
password = _read_password()
|
||||
if not utils.is_authenticated_user(username, password):
|
||||
raise argparse.ArgumentTypeError("Invalid credentials")
|
||||
|
||||
|
||||
def _managed_user(username):
|
||||
"""Raise an error if the user is root."""
|
||||
if pwd.getpwnam(username).pw_gid == 0:
|
||||
@ -52,6 +72,11 @@ def _managed_user(username):
|
||||
return username
|
||||
|
||||
|
||||
def _read_password():
|
||||
"""Read the password from stdin."""
|
||||
return ''.join(sys.stdin)
|
||||
|
||||
|
||||
def subcommand_setup(arguments):
|
||||
"""Setup Open SSH server.
|
||||
|
||||
@ -91,6 +116,10 @@ def subcommand_get_keys(arguments):
|
||||
def subcommand_set_keys(arguments):
|
||||
"""Set SSH authorized keys."""
|
||||
user = arguments.username
|
||||
auth_user = arguments.auth_user
|
||||
|
||||
must_be_admin = user != auth_user
|
||||
_validate_user(auth_user, must_be_admin=must_be_admin)
|
||||
|
||||
ssh_folder = os.path.join(get_user_homedir(user), '.ssh')
|
||||
key_file_path = os.path.join(ssh_folder, 'authorized_keys')
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@ -32,6 +32,7 @@ Build-Depends:
|
||||
python3-flake8,
|
||||
python3-gi,
|
||||
python3-markupsafe,
|
||||
python3-pampy,
|
||||
python3-paramiko,
|
||||
python3-psutil,
|
||||
python3-pytest,
|
||||
@ -104,6 +105,7 @@ Depends:
|
||||
python3-django-stronghold,
|
||||
python3-gi,
|
||||
python3-markupsafe,
|
||||
python3-pampy,
|
||||
python3-paramiko,
|
||||
python3-psutil,
|
||||
python3-requests,
|
||||
|
||||
@ -12,6 +12,7 @@ import string
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import markupsafe
|
||||
import pam
|
||||
import ruamel.yaml
|
||||
from django.utils.functional import lazy
|
||||
|
||||
@ -156,3 +157,9 @@ def is_axes_old():
|
||||
return False
|
||||
|
||||
return LooseVersion(version) < LooseVersion('5.0')
|
||||
|
||||
|
||||
def is_authenticated_user(username, password):
|
||||
"""Return true if the user authentication succeeds."""
|
||||
pam_authenticator = pam.pam()
|
||||
return bool(pam_authenticator.authenticate(username, password))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user