def view(self, access_id): level = access.get(access_id) auditlog.log(auditlog.CODE_CONTENT_VIEW, target=level) level_includes = lambda have, want: (have & want) != 0 # This is needed because jinja is whining about the '&' in the conditional return render('access/view.html', {'level': level, 'level_includes': level_includes, 'acl_labels': acl.ACCESS_LEVEL_LABELS})
def initialize(self, **kwargs): form = PassphraseSubmitForm(request_params()) if form.validate(): crypto_util.configure_crypto_state(form.passphrase.data) raise cherrypy.HTTPRedirect("/") else: return render("startup.html", {'form': form})
def error_handler(status, message, traceback, version): if cherrypy.request.headers.get('Accept') == 'application/json': return json.dumps({'error': {'code': status, 'message':message}}) else: return util.render('error.html', {'status': status, 'traceback': traceback, 'message': message, 'version': version})
def add(self, group_id=None): group_ids = [] if group_id: group_ids = [group_id] form = ResourceAddForm(group_ids=group_ids) form.group_ids.choices = [(g.id, g.label) for g in groups.list()] return render('resource/add.html', {'form': form })
def export(self, group_id=None, **kwargs): form = ExportForm(request_params(), group_id=group_id) form.group_id.choices = [(g.id, g.name) for g in groups.list()] exporter_choices = [('yaml', 'YAML (GPG/PGP-encrypted)')] if config['export.keepass.enabled']: if not os.path.exists(config['export.keepass.exe_path']): log.error("KeePass export enabled, but specified converter script does not exist: {0}".format(config.get('export.keepass.exe_path'))) else: exporter_choices.append(('kdb', 'KeePass 1.x')) form.format.choices = exporter_choices if cherrypy.request.method == 'POST': if form.validate(): group = groups.get(form.group_id.data) if form.format.data == 'yaml': exporter = GpgYamlExporter(use_tags=False, passphrase=form.passphrase.data, resource_filters=[model.GroupResource.group_id==group.id]) # @UndefinedVariable encrypted_stream = BytesIO() exporter.export(stream=encrypted_stream) encrypted_stream.seek(0) # Just to ensure it's rewound return serve_fileobj(encrypted_stream, content_type='application/pgp-encrypted', disposition='attachment', name='group-{0}-export.pgp'.format(re.sub('[^\w\-\.]', '_', group.name))) elif form.format.data == 'kdb': exporter = KeepassExporter(passphrase=form.passphrase.data, resource_filters=[model.GroupResource.group_id==group.id]) # @UndefinedVariable encrypted_stream = BytesIO() exporter.export(stream=encrypted_stream) encrypted_stream.seek(0) # Just to ensure it's rewound return serve_fileobj(encrypted_stream, content_type='application/x-keepass-database', disposition='attachment', name='group-{0}-export.kdb'.format(re.sub('[^\w\-\.]', '_', group.name))) else: # I don't think we can get here in normal business. raise RuntimeError("Unhandled format specified: {0}".format(form.format.data)) else: # does not validate return render("group/export.html", {'form': form}) else: # request method is GET return render("group/export.html", {'form': form})
def index(self): # Grab some recent passwords accessed by the current user. results = auditlog.recent_content_views(operator_id=operator_info().user_id, object_type=Password.object_type(), limit=20, skip_count=True) return render("index.html", {'recent_pw_views': results.entries})
def process_add(self, **kwargs): # We don't specify the args explicitly since we are using wtforms here. form = GroupAddForm(request_params()) if form.validate(): group = groups.create(name=form.name.data) auditlog.log(auditlog.CODE_CONTENT_ADD, target=group) notify_entity_activity(group, 'created') raise cherrypy.HTTPRedirect('/group/list') else: return render("group/add.html", {'form': form})
def process_login(self, **kwargs): form = LoginForm(request_params()) # TODO: Refactor to combine with the ensconce.server:checkpassword method. Lots of duplicate # logic here. AT MINIMUM MAKE SURE THAT ANY CHANGES HERE ARE REFLECTED THERE # This is a "flow-control" exception. ... You'll see. :) class _LoginFailed(Exception): pass try: if not form.validate(): raise _LoginFailed() username = form.username.data password = form.password.data for auth_provider in get_configured_providers(): try: auth_provider.authenticate(username, password) except exc.InsufficientPrivileges: form.username.errors.append(ValidationError("Insufficient privileges to log in.")) # Fail fast in this case; we don't want to continue on to try other authenticators. raise _LoginFailed() except exc.AuthError: # Swallow other auth errors so it goes onto next authenticator in the list. pass except: # Other exceptions needs to get logged at least. log.exception("Unexpected error authenticating user using {0!r}".format(auth_provider)) else: log.info("Authentication succeeded for username {0} using provider {1}".format(username, auth_provider)) break else: log.debug("Authenticators exhausted; login failed.") form.password.errors.append(ValidationError("Invalid username/password.")) raise _LoginFailed() except _LoginFailed: auditlog.log(auditlog.CODE_AUTH_FAILED, comment=username) return render("login.html", {'auth_provider': config['auth.provider'], 'form': form}) else: # Resolve the user using the *current value* for auth_provider (as that is the one that passed the auth. user = auth_provider.resolve_user(username) log.debug("Setting up cherrypy session with username={0}, user_id={1}".format(username, user.id)) cherrypy.session['username'] = username # @UndefinedVariable cherrypy.session['user_id'] = user.id # @UndefinedVariable auditlog.log(auditlog.CODE_AUTH_LOGIN) if form.redirect.data: raise cherrypy.HTTPRedirect(form.redirect.data) else: raise cherrypy.HTTPRedirect("/")
def view(self, group_id): try: group_id = int(group_id) except ValueError: group = groups.get_by_name(group_id) else: group = groups.get(group_id) auditlog.log(auditlog.CODE_CONTENT_VIEW, target=group) return render("group/view.html", {'group': group})
def view(self, resource_id): try: resource_id = int(resource_id) except ValueError: resource = resources.get_by_name(resource_id, assert_single=True) else: resource = resources.get(resource_id) auditlog.log(auditlog.CODE_CONTENT_VIEW, target=resource) return render('resource/view.html', {'resource': resource})
def process_add(self, **kwargs): form = OperatorAddForm(request_params()) form.access_id.choices = [(l.id, l.description) for l in access.list()] if form.validate(): operator = operators.create(username=form.username.data, password=form.password.data, access_id=form.access_id.data) auditlog.log(auditlog.CODE_CONTENT_ADD, target=operator) notify_entity_activity(operator, 'created') raise cherrypy.HTTPRedirect('/user/list') else: return render('user/add.html', {'form': form })
def process_add(self, **kwargs): form = PasswordAddForm(request_params()) if form.validate(): pw = passwords.create(username=form.username.data, resource_id=form.resource_id.data, password=form.password_decrypted.data, description=form.description.data, tags=form.tags.data) auditlog.log(auditlog.CODE_CONTENT_ADD, target=pw) notify_entity_activity(pw, 'created') raise cherrypy.HTTPRedirect('/resource/view/%d' % pw.resource_id) else: return render('password/add.html', {'form': form})
def process_edit(self, **kwargs): """ Updates a group (changes name). """ form = GroupEditForm(request_params()) if form.validate(): (group, modified) = groups.modify(form.group_id.data, name=form.name.data) auditlog.log(auditlog.CODE_CONTENT_MOD, target=group, attributes_modified=modified) notify_entity_activity(group, 'updated') raise cherrypy.HTTPRedirect('/group/list') else: return render('group/edit.html', {'form': form})
def process_add(self, **kwargs): form = AccessAddForm(request_params()) if form.validate(): level_mask = 0 for i in form.levels.data: level_mask |= int(i) level = access.create(level_mask, form.description.data) auditlog.log(auditlog.CODE_CONTENT_ADD, target=level) notify_entity_activity(level, 'created') raise cherrypy.HTTPRedirect('/access/list') else: return render('access/add.html', {'form': form})
def process_merge(self, **kwargs): form = MergeForm(request_params()) group_tuples = [(g.id, g.name) for g in groups.list()] form.from_group_id.choices = [(0, '[From Group]')] + group_tuples form.to_group_id.choices = [(0, '[To Group]')] + group_tuples if form.validate(): log.info("Passed validation, somehow.") (moved_resources, from_group, to_group) = groups.merge(form.from_group_id.data, form.to_group_id.data) for r in moved_resources: auditlog.log(auditlog.CODE_CONTENT_MOD, target=r, attributes_modified=['group_id']) auditlog.log(auditlog.CODE_CONTENT_DEL, target=from_group) raise cherrypy.HTTPRedirect('/group/view/{0}'.format(to_group.id)) else: return render("group/merge.html", {'form': form})
def process_add(self, **kwargs): form = ResourceAddForm(request_params()) form.group_ids.choices = [(g.id, g.label) for g in groups.list()] if form.validate(): resource = resources.create(name=form.name.data, group_ids=form.group_ids.data, addr=form.addr.data, description=form.description.data, notes=form.notes_decrypted.data, tags=form.tags.data) # XXX: process auditlog.log(auditlog.CODE_CONTENT_ADD, target=resource) notify_entity_activity(resource, 'created') raise cherrypy.HTTPRedirect('/resource/view/{0}'.format(resource.id)) else: return render('resource/add.html', {'form': form })
def process_edit(self, **kwargs): form = PasswordEditForm(request_params()) if form.validate(): (pw, modified) = passwords.modify(form.password_id.data, username=form.username.data, password=form.password_decrypted.data, description=form.description.data, tags=form.tags.data) auditlog.log(auditlog.CODE_CONTENT_MOD, target=pw, attributes_modified=modified) notify_entity_activity(pw, 'updated') raise cherrypy.HTTPRedirect('/resource/view/{0}'.format(pw.resource_id)) else: log.warning("Form failed validation: {0}".format(form.errors)) return render('password/edit.html', {'form': form})
def delete(self, group_id): """ Deletes a group. """ group = groups.get(group_id) all_resources = group.resources.all() # This is very lazy (could be done in SQL), but simple/easy-to-debug. resources_only_in_this_group = [] resources_in_other_groups_too = [] for r in all_resources: if r.groups.all() == [group]: resources_only_in_this_group.append(r) else: resources_in_other_groups_too.append(r) if cherrypy.request.method == 'POST': # First remove any resources that are only owned by this group. for r in resources_only_in_this_group: # Remove any passwords in this resource for pw in r.passwords: del_pw = passwords.delete(pw.id) auditlog.log(auditlog.CODE_CONTENT_DEL, target=del_pw) del_r = resources.delete(r.id) auditlog.log(auditlog.CODE_CONTENT_DEL, target=del_r) # Next we manually remove the group from any other resources that were associated # with this group. for r in resources_in_other_groups_too: group_ids = set([g.id for g in r.groups.all()]) group_ids.remove(group.id) (mod_r, modified) = resources.modify(r.id, group_ids=group_ids) if modified: auditlog.log(auditlog.CODE_CONTENT_MOD, target=mod_r, attributes_modified=modified) # And finally we can delete the group itself. group = groups.delete(group.id) auditlog.log(auditlog.CODE_CONTENT_DEL, target=group) notify_entity_activity(group, 'deleted') raise cherrypy.HTTPRedirect('/group/list') else: return render('group/delete.html', {'group_id': group_id, 'del_resources': resources_only_in_this_group, 'mod_resources': resources_in_other_groups_too})
def list(self, **kwargs): class PagerForm(Form): page = SelectField('Page', default=1, coerce=int) form = PagerForm(request_params()) page_size = 50 page = form.page.data offset = page_size * (page - 1) limit = page_size results = resources.search(limit=limit, offset=offset) total_pages = int(math.ceil( (1.0 * results.count) / page_size)) form.page.choices = [(i, i) for i in range(1, total_pages+1)] return render('resource/list.html', {'resources': results.entries, 'form': form, 'page': page, 'total_pages': total_pages})
def process_edit(self, **kwargs): form = ResourceEditForm(request_params()) form.group_ids.choices = [(g.id, g.label) for g in groups.list()] if form.validate(): (resource, modified) = resources.modify(form.resource_id.data, name=form.name.data, addr=form.addr.data, group_ids=form.group_ids.data, notes=form.notes_decrypted.data, description=form.description.data, tags=form.tags.data) # XXX: process auditlog.log(auditlog.CODE_CONTENT_MOD, target=resource, attributes_modified=modified) notify_entity_activity(resource, 'updated') raise cherrypy.HTTPRedirect('/resource/view/{0}'.format(resource.id)) else: log.warning("Form validation failed.") log.warning(form.errors) return render('resource/edit.html', {'form': form})
def process_edit(self, **kwargs): log.debug("params = %r" % request_params()) form = OperatorEditForm(request_params()) form.access_id.choices = [(l.id, l.description) for l in access.list()] if form.validate(): params = dict(operator_id=form.operator_id.data, username=form.username.data, access_id=form.access_id.data) # If password is blank, let's just not change it. if form.password.data: params['password'] = form.password.data (operator, modified) = operators.modify(**params) auditlog.log(auditlog.CODE_CONTENT_MOD, target=operator, attributes_modified=modified) notify_entity_activity(operator, 'updated') raise cherrypy.HTTPRedirect('/user/list') else: return render('user/edit.html', {'form': form, 'externally_managed': operator.externally_managed})
def delete(self, resource_id, redirect_to=None): resource = resources.get(resource_id) if cherrypy.request.method == 'POST': # First remove any passwords for this resource. for pw in resource.passwords: del_pw = passwords.delete(pw.id) auditlog.log(auditlog.CODE_CONTENT_DEL, target=del_pw) # Then remove the actual resource resource = resources.delete(resource_id) auditlog.log(auditlog.CODE_CONTENT_DEL, target=resource) notify_entity_activity(resource, 'deleted') if redirect_to: raise cherrypy.HTTPRedirect(redirect_to) else: raise cherrypy.HTTPRedirect('/resource/list') else: return render('resource/delete.html', {'resource': resource, 'redirect_to': redirect_to})
def search(self, searchstr): r_matches = g_matches = p_matches = None if searchstr: (r_matches, g_matches, p_matches) = search.search(searchstr, include_encrypted=True) if len(r_matches) + len(g_matches) + len(p_matches) == 1: # There was only one result, so just send them to the resulting page. notify("Showing you the one result that matched your query.") if r_matches: raise cherrypy.HTTPRedirect("/resource/view/{0}".format(r_matches[0].id)) elif g_matches: raise cherrypy.HTTPRedirect("/group/view/{0}".format(g_matches[0].id)) elif p_matches: # We could also redirect them to the password view/history page if that is more helpful? raise cherrypy.HTTPRedirect("/resource/view/{0}".format(p_matches[0].resource_id)) auditlog.log(auditlog.CODE_SEARCH, comment=searchstr) return render('search.html', {'resource_matches': r_matches, 'group_matches': g_matches, 'password_matches': p_matches, 'searchstr': searchstr })
def auditlog(self, **kwargs): form = AuditlogForm(request_params()) page_size = 50 page = form.page.data offset = page_size * (page - 1) limit = page_size log.debug("Page = {0}, offset={1}, limit={2}".format(page, offset, limit)) results = auditlog.search(start=form.start.data, end=form.end.data, code=form.code.data, operator_username=form.operator.data, offset=offset, limit=limit) if results.count < offset: form.page.data = 1 form.page.raw_data = ['1'] # Apparently need this too! total_pages = int(math.ceil( (1.0 * results.count) / page_size)) return render('auditlog.html', {'entries': results.entries, 'form': form, 'total_pages': total_pages})
def add(self): form = AccessAddForm() return render('access/add.html', {'form': form})
def list(self): return render('access/list.html', {'access': access.list()})
def login(self, redirect=None): form = LoginForm(redirect=redirect) return render("login.html", {'auth_provider': config['auth.provider'], 'form': form})
def startup(self): form = PassphraseSubmitForm() return render("startup.html", {'form': form})
def osd(self): return render("osd-search.xml", {'base_url': cherrypy.url('/')})
def edit(self, group_id): group = groups.get(group_id) form = GroupEditForm(request_params(), group, group_id=group.id) return render('group/edit.html', {'form': form})