Beispiel #1
0
 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})
Beispiel #2
0
 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})
Beispiel #3
0
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})
Beispiel #4
0
 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 })
Beispiel #5
0
 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})
Beispiel #6
0
 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})
Beispiel #7
0
 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})
Beispiel #8
0
    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("/")
Beispiel #9
0
 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})
Beispiel #10
0
 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})
Beispiel #11
0
 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 })
Beispiel #12
0
 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})
Beispiel #13
0
 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})
Beispiel #14
0
 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})
Beispiel #15
0
 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})
Beispiel #16
0
 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 })
Beispiel #17
0
 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})
Beispiel #18
0
 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})
Beispiel #19
0
 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})
Beispiel #20
0
 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})
Beispiel #21
0
 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})
Beispiel #22
0
 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})
Beispiel #23
0
 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 })
Beispiel #24
0
 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})
Beispiel #25
0
 def add(self):
     form = AccessAddForm()
     return render('access/add.html', {'form': form})
Beispiel #26
0
 def list(self):
     return render('access/list.html', {'access': access.list()})
Beispiel #27
0
 def login(self, redirect=None):     
     form = LoginForm(redirect=redirect)
     return render("login.html", {'auth_provider': config['auth.provider'], 'form': form})
Beispiel #28
0
 def startup(self):
     form = PassphraseSubmitForm()
     return render("startup.html", {'form': form})
Beispiel #29
0
 def osd(self):
     return render("osd-search.xml", {'base_url': cherrypy.url('/')})
Beispiel #30
0
 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})