ssh-keys: added admin panel for managing globally all SSH Keys.
- added also option to manually update the keyfile - fetch and show all user keys for audit purpose
This commit is contained in:
parent
42f25bce8e
commit
3ea8958a92
6 changed files with 254 additions and 5 deletions
|
|
@ -106,6 +106,16 @@ def admin_routes(config):
|
|||
name='admin_permissions_auth_token_access',
|
||||
pattern='/permissions/auth_token_access')
|
||||
|
||||
config.add_route(
|
||||
name='admin_permissions_ssh_keys',
|
||||
pattern='/permissions/ssh_keys')
|
||||
config.add_route(
|
||||
name='admin_permissions_ssh_keys_data',
|
||||
pattern='/permissions/ssh_keys/data')
|
||||
config.add_route(
|
||||
name='admin_permissions_ssh_keys_update',
|
||||
pattern='/permissions/ssh_keys/update')
|
||||
|
||||
# users admin
|
||||
config.add_route(
|
||||
name='users',
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@
|
|||
|
||||
import pytest
|
||||
from rhodecode.model.db import User, UserIpMap
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.permission import PermissionModel
|
||||
from rhodecode.model.ssh_key import SshKeyModel
|
||||
from rhodecode.tests import (
|
||||
TestController, clear_all_caches, assert_session_flash)
|
||||
|
||||
|
|
@ -55,7 +57,14 @@ def route_path(name, params=None, **kwargs):
|
|||
'admin_permissions_ips':
|
||||
ADMIN_PREFIX + '/permissions/ips',
|
||||
'admin_permissions_overview':
|
||||
ADMIN_PREFIX + '/permissions/overview'
|
||||
ADMIN_PREFIX + '/permissions/overview',
|
||||
|
||||
'admin_permissions_ssh_keys':
|
||||
ADMIN_PREFIX + '/permissions/ssh_keys',
|
||||
'admin_permissions_ssh_keys_data':
|
||||
ADMIN_PREFIX + '/permissions/ssh_keys/data',
|
||||
'admin_permissions_ssh_keys_update':
|
||||
ADMIN_PREFIX + '/permissions/ssh_keys/update'
|
||||
|
||||
}[name].format(**kwargs)
|
||||
|
||||
|
|
@ -248,3 +257,30 @@ class TestAdminPermissionsController(TestController):
|
|||
def test_index_overview(self):
|
||||
self.log_user()
|
||||
self.app.get(route_path('admin_permissions_overview'))
|
||||
|
||||
def test_ssh_keys(self):
|
||||
self.log_user()
|
||||
self.app.get(route_path('admin_permissions_ssh_keys'), status=200)
|
||||
|
||||
def test_ssh_keys_data(self, user_util, xhr_header):
|
||||
self.log_user()
|
||||
response = self.app.get(route_path('admin_permissions_ssh_keys_data'),
|
||||
extra_environ=xhr_header)
|
||||
assert response.json == {u'data': [], u'draw': None,
|
||||
u'recordsFiltered': 0, u'recordsTotal': 0}
|
||||
|
||||
dummy_user = user_util.create_user()
|
||||
SshKeyModel().create(dummy_user, 'ab:cd:ef', 'KEYKEY', 'test_key')
|
||||
Session().commit()
|
||||
response = self.app.get(route_path('admin_permissions_ssh_keys_data'),
|
||||
extra_environ=xhr_header)
|
||||
assert response.json['data'][0]['fingerprint'] == 'ab:cd:ef'
|
||||
|
||||
def test_ssh_keys_update(self):
|
||||
self.log_user()
|
||||
response = self.app.post(
|
||||
route_path('admin_permissions_ssh_keys_update'),
|
||||
dict(csrf_token=self.csrf_token), status=302)
|
||||
|
||||
assert_session_flash(
|
||||
response, 'SSH key support is disabled in .ini file')
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
import re
|
||||
import logging
|
||||
import formencode
|
||||
import datetime
|
||||
from pyramid.interfaces import IRoutesMapper
|
||||
|
||||
from pyramid.view import view_config
|
||||
|
|
@ -28,13 +29,15 @@ from pyramid.httpexceptions import HTTPFound
|
|||
from pyramid.renderers import render
|
||||
from pyramid.response import Response
|
||||
|
||||
from rhodecode.apps._base import BaseAppView
|
||||
from rhodecode.apps._base import BaseAppView, DataGridAppView
|
||||
from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
|
||||
from rhodecode.events import trigger
|
||||
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasPermissionAllDecorator, CSRFRequired)
|
||||
from rhodecode.lib.utils2 import aslist
|
||||
from rhodecode.model.db import User, UserIpMap
|
||||
from rhodecode.lib.utils2 import aslist, safe_unicode
|
||||
from rhodecode.model.db import or_, joinedload, coalesce, User, UserIpMap, UserSshKeys
|
||||
from rhodecode.model.forms import (
|
||||
ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
|
||||
from rhodecode.model.meta import Session
|
||||
|
|
@ -45,7 +48,7 @@ from rhodecode.model.settings import SettingsModel
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AdminPermissionsView(BaseAppView):
|
||||
class AdminPermissionsView(BaseAppView, DataGridAppView):
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
|
||||
|
|
@ -367,3 +370,106 @@ class AdminPermissionsView(BaseAppView):
|
|||
|
||||
c.whitelist_views = whitelist_views
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator('hg.admin')
|
||||
@view_config(
|
||||
route_name='admin_permissions_ssh_keys', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/permissions/permissions.mako')
|
||||
def ssh_keys(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'ssh_keys'
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator('hg.admin')
|
||||
@view_config(
|
||||
route_name='admin_permissions_ssh_keys_data', request_method='GET',
|
||||
renderer='json_ext', xhr=True)
|
||||
def ssh_keys_data(self):
|
||||
_ = self.request.translate
|
||||
column_map = {
|
||||
'fingerprint': 'ssh_key_fingerprint',
|
||||
'username': User.username
|
||||
}
|
||||
draw, start, limit = self._extract_chunk(self.request)
|
||||
search_q, order_by, order_dir = self._extract_ordering(
|
||||
self.request, column_map=column_map)
|
||||
|
||||
ssh_keys_data_total_count = UserSshKeys.query()\
|
||||
.count()
|
||||
|
||||
# json generate
|
||||
base_q = UserSshKeys.query().join(UserSshKeys.user)
|
||||
|
||||
if search_q:
|
||||
like_expression = u'%{}%'.format(safe_unicode(search_q))
|
||||
base_q = base_q.filter(or_(
|
||||
User.username.ilike(like_expression),
|
||||
UserSshKeys.ssh_key_fingerprint.ilike(like_expression),
|
||||
))
|
||||
|
||||
users_data_total_filtered_count = base_q.count()
|
||||
|
||||
sort_col = self._get_order_col(order_by, UserSshKeys)
|
||||
if sort_col:
|
||||
if order_dir == 'asc':
|
||||
# handle null values properly to order by NULL last
|
||||
if order_by in ['created_on']:
|
||||
sort_col = coalesce(sort_col, datetime.date.max)
|
||||
sort_col = sort_col.asc()
|
||||
else:
|
||||
# handle null values properly to order by NULL last
|
||||
if order_by in ['created_on']:
|
||||
sort_col = coalesce(sort_col, datetime.date.min)
|
||||
sort_col = sort_col.desc()
|
||||
|
||||
base_q = base_q.order_by(sort_col)
|
||||
base_q = base_q.offset(start).limit(limit)
|
||||
|
||||
ssh_keys = base_q.all()
|
||||
|
||||
ssh_keys_data = []
|
||||
for ssh_key in ssh_keys:
|
||||
ssh_keys_data.append({
|
||||
"username": h.gravatar_with_user(self.request, ssh_key.user.username),
|
||||
"fingerprint": ssh_key.ssh_key_fingerprint,
|
||||
"description": ssh_key.description,
|
||||
"created_on": h.format_date(ssh_key.created_on),
|
||||
"action": h.link_to(
|
||||
_('Edit'), h.route_path('edit_user_ssh_keys',
|
||||
user_id=ssh_key.user.user_id))
|
||||
})
|
||||
|
||||
data = ({
|
||||
'draw': draw,
|
||||
'data': ssh_keys_data,
|
||||
'recordsTotal': ssh_keys_data_total_count,
|
||||
'recordsFiltered': users_data_total_filtered_count,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator('hg.admin')
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
route_name='admin_permissions_ssh_keys_update', request_method='POST',
|
||||
renderer='rhodecode:templates/admin/permissions/permissions.mako')
|
||||
def ssh_keys_update(self):
|
||||
_ = self.request.translate
|
||||
self.load_default_context()
|
||||
|
||||
ssh_enabled = self.request.registry.settings.get(
|
||||
'ssh.generate_authorized_keyfile')
|
||||
key_file = self.request.registry.settings.get(
|
||||
'ssh.authorized_keys_file_path')
|
||||
if ssh_enabled:
|
||||
trigger(SshKeyFileChangeEvent(), self.request.registry)
|
||||
h.flash(_('Updated SSH keys file: {}').format(key_file),
|
||||
category='success')
|
||||
else:
|
||||
h.flash(_('SSH key support is disabled in .ini file'),
|
||||
category='warning')
|
||||
|
||||
raise HTTPFound(h.route_path('admin_permissions_ssh_keys'))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue