Mercurial > kallithea
changeset 7769:95c01895c006
ssh: db models for ssh key management
Add database components for SSH based access. Actual use of this will be added
soon.
The work in this commit is based heavily off of the existing API key
code for the sake of consistency.
The original code has been heavily modified by Mads Kiilerich.
Updates to use User.guess_instance by Anton Schur <tonich.sh@gmail.com>.
author | Tim Freund <tim@freunds.net> |
---|---|
date | Mon, 17 Nov 2014 14:40:35 -0500 |
parents | 609d52bbf917 |
children | 6da70f4569bf |
files | kallithea/alembic/versions/b74907136bc1_create_table_for_ssh_keys.py kallithea/model/db.py kallithea/model/ssh_key.py kallithea/tests/models/test_user_ssh_keys.py |
diffstat | 4 files changed, 168 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kallithea/alembic/versions/b74907136bc1_create_table_for_ssh_keys.py Mon Nov 17 14:40:35 2014 -0500 @@ -0,0 +1,52 @@ +# 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/>. + +"""Create table for ssh keys + +Revision ID: b74907136bc1 +Revises: a020f7044fd6 +Create Date: 2017-04-03 18:54:24.490346 + +""" + +# The following opaque hexadecimal identifiers ("revisions") are used +# by Alembic to track this migration script and its relations to others. +revision = 'b74907136bc1' +down_revision = 'ad357ccd9521' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.create_table('user_ssh_keys', + sa.Column('user_ssh_key_id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('public_key', sa.UnicodeText(), nullable=False), + sa.Column('description', sa.UnicodeText(), nullable=False), + sa.Column('fingerprint', sa.String(length=255), nullable=False), + sa.Column('created_on', sa.DateTime(), nullable=False), + sa.Column('last_seen', sa.DateTime(), nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['users.user_id'], name=op.f('fk_user_ssh_keys_user_id')), + sa.PrimaryKeyConstraint('user_ssh_key_id', name=op.f('pk_user_ssh_keys')), + sa.UniqueConstraint('fingerprint', name=op.f('uq_user_ssh_keys_fingerprint')), + ) + with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op: + batch_op.create_index('usk_fingerprint_idx', ['fingerprint'], unique=False) + +def downgrade(): + with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op: + batch_op.drop_index('usk_fingerprint_idx') + op.drop_table('user_ssh_keys')
--- a/kallithea/model/db.py Wed Jul 31 02:55:22 2019 +0200 +++ b/kallithea/model/db.py Mon Nov 17 14:40:35 2014 -0500 @@ -449,6 +449,7 @@ user_emails = relationship('UserEmailMap', cascade='all') # extra API keys user_api_keys = relationship('UserApiKeys', cascade='all') + ssh_keys = relationship('UserSshKeys', cascade='all') @hybrid_property def email(self): @@ -2515,3 +2516,36 @@ base_path = self.base_path() return get_repo(os.path.join(*map(safe_str, [base_path, self.gist_access_id]))) + + +class UserSshKeys(Base, BaseDbModel): + __tablename__ = 'user_ssh_keys' + __table_args__ = ( + Index('usk_public_key_idx', 'public_key'), + Index('usk_fingerprint_idx', 'fingerprint'), + UniqueConstraint('fingerprint'), + _table_args_default_dict + ) + __mapper_args__ = {} + + user_ssh_key_id = Column(Integer(), primary_key=True) + user_id = Column(Integer(), ForeignKey('users.user_id'), nullable=False) + _public_key = Column('public_key', UnicodeText(), nullable=False) + description = Column(UnicodeText(), nullable=False) + fingerprint = Column(String(255), nullable=False, unique=True) + created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now) + last_seen = Column(DateTime(timezone=False), nullable=True) + + user = relationship('User') + + @property + def public_key(self): + return self._public_key + + @public_key.setter + def public_key(self, full_key): + # the full public key is too long to be suitable as database key - instead, + # use fingerprints similar to 'ssh-keygen -E sha256 -lf ~/.ssh/id_rsa.pub' + self._public_key = full_key + enc_key = full_key.split(" ")[1] + self.fingerprint = hashlib.sha256(enc_key.decode('base64')).digest().encode('base64').replace('\n', '').rstrip('=')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kallithea/model/ssh_key.py Mon Nov 17 14:40:35 2014 -0500 @@ -0,0 +1,65 @@ +# -*- 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/>. +""" +kallithea.model.ssh_key +~~~~~~~~~~~~~~~~~~~~~~~ + +SSH key model for Kallithea + +""" + +import logging + +from kallithea.model.db import UserSshKeys, User +from kallithea.model.meta import Session + +log = logging.getLogger(__name__) + +class SshKeyModel(object): + + def create(self, user, description, public_key): + """ + :param user: user or user_id + :param description: description of SshKey + :param publickey: public key text + """ + user = User.guess_instance(user) + + new_ssh_key = UserSshKeys() + new_ssh_key.user_id = user.user_id + new_ssh_key.description = description + new_ssh_key.public_key = public_key + Session().add(new_ssh_key) + + return new_ssh_key + + def delete(self, public_key, user=None): + """ + Deletes given public_key, if user is set it also filters the object for + deletion by given user. + """ + ssh_key = UserSshKeys.query().filter(UserSshKeys._public_key == public_key) + + if user: + user = User.guess_instance(user) + ssh_key = ssh_key.filter(UserSshKeys.user_id == user.user_id) + + ssh_key = ssh_key.scalar() + Session().delete(ssh_key) + + def get_ssh_keys(self, user): + user = User.guess_instance(user) + user_ssh_keys = UserSshKeys.query() \ + .filter(UserSshKeys.user_id == user.user_id).all() + return user_ssh_keys
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kallithea/tests/models/test_user_ssh_keys.py Mon Nov 17 14:40:35 2014 -0500 @@ -0,0 +1,17 @@ +from kallithea.model.db import UserSshKeys + +from kallithea.tests.base import TestController +from kallithea.tests.fixture import Fixture + +fixture = Fixture() + +public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== kallithea@localhost' + + +class TestUserSshKeys(TestController): + + def test_fingerprint_generation(self): + key_model = UserSshKeys() + key_model.public_key = public_key + expected = 'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8' + assert expected == key_model.fingerprint