Files @ 01cb988e82a5
Branch filter:

Location: kallithea/kallithea/bin/kallithea_cli_ssh.py

mads
celery: celery-run should only initialize app and sqlalchemy after workers have been forked

If app and SqlAlchemy were initialized before launching celery, the forked
workers would inherit the database connection ... and that doesn't work.

This could be handled by disposing the engine after forking the worker or
before each task ... but it remains unnecessary and wrong to initialize the
engine early when it isn't used, and then fork it.
# -*- coding: utf-8 -*-
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging
import os
import shlex
import sys

import click

import kallithea
import kallithea.bin.kallithea_cli_base as cli_base
from kallithea.lib.utils2 import asbool
from kallithea.lib.vcs.ssh.git import GitSshHandler
from kallithea.lib.vcs.ssh.hg import MercurialSshHandler
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException


log = logging.getLogger(__name__)


@cli_base.register_command(config_file_initialize_app=True, hidden=True)
@click.argument('user-id', type=click.INT, required=True)
@click.argument('key-id', type=click.INT, required=True)
def ssh_serve(user_id, key_id):
    """Serve SSH repository protocol access.

    The trusted command that is invoked from .ssh/authorized_keys to serve SSH
    protocol access. The access will be granted as the specified user ID, and
    logged as using the specified key ID.
    """
    if not asbool(kallithea.CONFIG.get('ssh_enabled', False)):
        sys.stderr.write("SSH access is disabled.\n")
        return sys.exit(1)

    ssh_locale = kallithea.CONFIG.get('ssh_locale')
    if ssh_locale:
        os.environ['LC_ALL'] = ssh_locale # trumps everything, including LANG, except LANGUAGE
        os.environ['LANGUAGE'] = ssh_locale # trumps LC_ALL for GNU gettext message handling

    ssh_original_command = os.environ.get('SSH_ORIGINAL_COMMAND', '')
    client_ip = os.environ.get('SSH_CONNECTION', '').split(' ', 1)[0] or '0.0.0.0'
    log.debug('ssh-serve was invoked for SSH command %r from %s', ssh_original_command, client_ip)

    if not ssh_original_command:
        if os.environ.get('SSH_CONNECTION'):
            sys.stderr.write("'kallithea-cli ssh-serve' can only provide protocol access over SSH. Interactive SSH login for this user is disabled.\n")
        else:
            sys.stderr.write("'kallithea-cli ssh-serve' cannot be called directly. It must be specified as command in an SSH authorized_keys file.\n")
        return sys.exit(1)

    try:
        ssh_command_parts = shlex.split(ssh_original_command)
    except ValueError as e:
        sys.stderr.write('Error parsing SSH command %r: %s\n' % (ssh_original_command, e))
        sys.exit(1)
    for VcsHandler in [MercurialSshHandler, GitSshHandler]:
        vcs_handler = VcsHandler.make(ssh_command_parts)
        if vcs_handler is not None:
            vcs_handler.serve(user_id, key_id, client_ip)
            assert False # serve is written so it never will terminate

    sys.stderr.write("This account can only be used for repository access. SSH command %r is not supported.\n" % ssh_original_command)
    sys.exit(1)


@cli_base.register_command(config_file_initialize_app=True)
def ssh_update_authorized_keys():
    """Update .ssh/authorized_keys file.

    The file is usually maintained automatically, but this command will also re-write it.
    """
    try:
        SshKeyModel().write_authorized_keys()
    except SshKeyModelException as e:
        sys.stderr.write("%s\n" % e)
        sys.exit(1)