Mercurial > kallithea
changeset 7772:66c208bf56fe
ssh: user management of ssh keys
Add user interface for managing SSH based access.
The work in this commit is based heavily off of the existing API key
code for the sake of consistency.
Updates to use Bootstrap, request.authuser, POST methods and pytest by Anton
Schur <tonich.sh@gmail.com>.
Additional Bootstrap fixes by Dominik Ruf.
The original code has been heavily modified by Mads Kiilerich.
author | Tim Freund <tim@freunds.net> |
---|---|
date | Mon, 17 Nov 2014 14:40:35 -0500 |
parents | 3e84ac8ed579 |
children | 3b147c38b674 |
files | kallithea/config/routing.py kallithea/controllers/admin/my_account.py kallithea/templates/admin/my_account/my_account.html kallithea/templates/admin/my_account/my_account_ssh_keys.html kallithea/tests/functional/test_my_account.py |
diffstat | 5 files changed, 145 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/kallithea/config/routing.py Mon Nov 17 14:42:45 2014 -0500 +++ b/kallithea/config/routing.py Mon Nov 17 14:40:35 2014 -0500 @@ -358,6 +358,13 @@ m.connect("my_account_api_keys_delete", "/my_account/api_keys/delete", action="my_account_api_keys_delete", conditions=dict(method=["POST"])) + m.connect("my_account_ssh_keys", "/my_account/ssh_keys", + action="my_account_ssh_keys", conditions=dict(method=["GET"])) + m.connect("my_account_ssh_keys", "/my_account/ssh_keys", + action="my_account_ssh_keys_add", conditions=dict(method=["POST"])) + m.connect("my_account_ssh_keys_delete", "/my_account/ssh_keys/delete", + action="my_account_ssh_keys_delete", conditions=dict(method=["POST"])) + # ADMIN GIST with rmap.submapper(path_prefix=ADMIN_PREFIX, controller='admin/gists') as m:
--- a/kallithea/controllers/admin/my_account.py Mon Nov 17 14:42:45 2014 -0500 +++ b/kallithea/controllers/admin/my_account.py Mon Nov 17 14:40:35 2014 -0500 @@ -39,13 +39,14 @@ from kallithea.lib import helpers as h from kallithea.lib import auth_modules from kallithea.lib.auth import LoginRequired, AuthUser -from kallithea.lib.base import BaseController, render +from kallithea.lib.base import BaseController, render, IfSshEnabled from kallithea.lib.utils2 import generate_api_key, safe_int from kallithea.model.db import Repository, UserEmailMap, User, UserFollowing from kallithea.model.forms import UserForm, PasswordChangeForm from kallithea.model.user import UserModel from kallithea.model.repo import RepoModel from kallithea.model.api_key import ApiKeyModel +from kallithea.model.ssh_key import SshKeyModel from kallithea.model.meta import Session log = logging.getLogger(__name__) @@ -259,3 +260,28 @@ h.flash(_("API key successfully deleted"), category='success') raise HTTPFound(location=url('my_account_api_keys')) + + @IfSshEnabled + def my_account_ssh_keys(self): + c.active = 'ssh_keys' + self.__load_data() + c.user_ssh_keys = SshKeyModel().get_ssh_keys(request.authuser.user_id) + return render('admin/my_account/my_account.html') + + @IfSshEnabled + def my_account_ssh_keys_add(self): + description = request.POST.get('description') + public_key = request.POST.get('public_key') + new_ssh_key = SshKeyModel().create(request.authuser.user_id, + description, public_key) + Session().commit() + h.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') + raise HTTPFound(location=url('my_account_ssh_keys')) + + @IfSshEnabled + def my_account_ssh_keys_delete(self): + public_key = request.POST.get('del_public_key') + SshKeyModel().delete(public_key, request.authuser.user_id) + Session().commit() + h.flash(_("SSH key successfully deleted"), category='success') + raise HTTPFound(location=url('my_account_ssh_keys'))
--- a/kallithea/templates/admin/my_account/my_account.html Mon Nov 17 14:42:45 2014 -0500 +++ b/kallithea/templates/admin/my_account/my_account.html Mon Nov 17 14:40:35 2014 -0500 @@ -25,6 +25,9 @@ <li class="${'active' if c.active=='profile' else ''}"><a href="${h.url('my_account')}">${_('Profile')}</a></li> <li class="${'active' if c.active=='emails' else ''}"><a href="${h.url('my_account_emails')}">${_('Email Addresses')}</a></li> <li class="${'active' if c.active=='password' else ''}"><a href="${h.url('my_account_password')}">${_('Password')}</a></li> + %if c.ssh_enabled: + <li class="${'active' if c.active=='ssh_keys' else ''}"><a href="${h.url('my_account_ssh_keys')}">${_('SSH Keys')}</a></li> + %endif <li class="${'active' if c.active=='api_keys' else ''}"><a href="${h.url('my_account_api_keys')}">${_('API Keys')}</a></li> <li class="${'active' if c.active=='repos' else ''}"><a href="${h.url('my_account_repos')}">${_('Owned Repositories')}</a></li> <li class="${'active' if c.active=='watched' else ''}"><a href="${h.url('my_account_watched')}">${_('Watched Repositories')}</a></li>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kallithea/templates/admin/my_account/my_account_ssh_keys.html Mon Nov 17 14:40:35 2014 -0500 @@ -0,0 +1,63 @@ +<table class="table"> + %if c.user_ssh_keys: + <tr> + <th>${_('Fingerprint')}</th> + <th>${_('Description')}</th> + <th>${_('Action')}</th> + </tr> + %for ssh_key in c.user_ssh_keys: + <tr> + <td> + ${ssh_key.fingerprint} + </td> + <td> + ${ssh_key.description} + </td> + <td> + ${h.form(url('my_account_ssh_keys_delete'))} + ${h.hidden('del_public_key', ssh_key.public_key)} + <button class="btn btn-danger btn-xs" type="submit" + onclick="return confirm('${_('Confirm to remove this SSH key: %s') % ssh_key.fingerprint}');"> + <i class="icon-trashcan"></i> + ${_('Remove')} + </button> + ${h.end_form()} + </td> + </tr> + %endfor + %else: + <tr> + <td> + <div class="ip">${_('No SSH keys have been added')}</div> + </td> + </tr> + %endif +</table> + +<div> + ${h.form(url('my_account_ssh_keys'))} + <div class="form"> + <div class="form-group"> + <label class="control-label">${_('New SSH key')}</label> + </div> + <div class="form-group"> + <label class="control-label" for="public_key">${_('Public key')}:</label> + <div> + ${h.textarea('public_key', '', class_='form-control', placeholder=_('Public key (contents of e.g. ~/.ssh/id_rsa.pub)'), cols=80, rows=5)} + </div> + </div> + <div class="form-group"> + <label class="control-label" for="description">${_('Description')}:</label> + <div> + ${h.text('description', class_='form-control', placeholder=_('Description'))} + </div> + </div> + <div class="form-group"> + <div class="buttons"> + ${h.submit('save', _('Add'), class_="btn btn-default")} + ${h.reset('reset', _('Reset'), class_="btn btn-default")} + </div> + </div> + </div> + ${h.end_form()} +</div>
--- a/kallithea/tests/functional/test_my_account.py Mon Nov 17 14:42:45 2014 -0500 +++ b/kallithea/tests/functional/test_my_account.py Mon Nov 17 14:40:35 2014 -0500 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from kallithea.model.db import User, UserFollowing, Repository, UserApiKeys +from kallithea.model.db import User, UserFollowing, Repository, UserApiKeys, UserSshKeys from kallithea.tests.base import * from kallithea.tests.fixture import Fixture from kallithea.lib import helpers as h @@ -249,3 +249,47 @@ self.checkSessionFlash(response, 'API key successfully reset') response = response.follow() response.mustcontain(no=[api_key]) + + def test_my_account_add_ssh_key(self): + description = u'something' + public_key = u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== me@localhost' + fingerprint = u'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8' + + self.log_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS) + response = self.app.post(url('my_account_ssh_keys'), + {'description': description, + 'public_key': public_key, + '_authentication_token': self.authentication_token()}) + self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint) + + response = response.follow() + response.mustcontain(fingerprint) + user_id = response.session['authuser']['user_id'] + ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one() + assert ssh_key.fingerprint == fingerprint + assert ssh_key.description == description + Session().delete(ssh_key) + Session().commit() + + def test_my_account_remove_ssh_key(self): + description = u'' + public_key = u'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== me@localhost' + fingerprint = u'Ke3oUCNJM87P0jJTb3D+e3shjceP2CqMpQKVd75E9I8' + + self.log_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS) + response = self.app.post(url('my_account_ssh_keys'), + {'description': description, + 'public_key': public_key, + '_authentication_token': self.authentication_token()}) + self.checkSessionFlash(response, 'SSH key %s successfully added' % fingerprint) + response.follow() + user_id = response.session['authuser']['user_id'] + ssh_key = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).one() + assert ssh_key.description == description + + response = self.app.post(url('my_account_ssh_keys_delete'), + {'del_public_key': ssh_key.public_key, + '_authentication_token': self.authentication_token()}) + self.checkSessionFlash(response, 'SSH key successfully deleted') + keys = UserSshKeys.query().all() + assert 0 == len(keys)