def check_duplicate_name(form, field): name = field.data existing = groups.get_by_name(name, assert_exists=False) if existing: if not hasattr(form, 'group_id') or (hasattr(form, 'group_id') and \ existing.id != form.group_id.data): raise ValidationError("Group \"{0}\" already exists.".format(name))
def getGroup(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 group.to_dict(include_resources=True)
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 export_data(options): """ Interactive target to export GPG-encrypted YAML file(s) for specified group(s). """ try: dirpath = options.export_data.dir except AttributeError: dirpath = None try: singlefile = options.export_data.file except AttributeError: singlefile = None if dirpath is None and singlefile is None: raise BuildFailure('One of --dir/-d or --file/-f is required.') elif dirpath is not None and singlefile is not None: raise BuildFailure('The --dir/-d or --file/-f are mutually exclusive') try: grouplist = options.export_data.groups except AttributeError: grouplist = None try: groupfile = options.export_data.groupfile except AttributeError: groupfile = None if groupfile is None and grouplist is None: raise BuildFailure("One of --groupfile/-G or --groups/-g options must be specified.") elif groupfile is not None and grouplist is not None: raise BuildFailure("The --groupfile/-G and --groups/-g options are mutually exclusive.") # First read in the groups by either comma-separating the list or by if grouplist: group_names = re.split(r'\s*,\s*', grouplist) else: with open(groupfile, 'r') as fp: group_names = [l.strip() for l in fp if l.strip() != '' and not l.strip().startswith('#')] # Check these against the database. Fail fast. groups = [groups_dao.get_by_name(gn, assert_exists=True) for gn in group_names] passphrase = raw_input("GPG Passphrase for export file(s): ") if singlefile: group_ids = [g.id for g in groups] print "Exporting groups {0!r} to file: {1}".format(group_names, singlefile) exporter = GpgYamlExporter(use_tags=False, passphrase=passphrase, resource_filters=[model.GroupResource.group_id.in_(group_ids)]) # @UndefinedVariable with open(singlefile, 'w') as output_file: exporter.export(stream=output_file) else: # Iterate over the groups. Export file per group. for g in groups: exporter = GpgYamlExporter(use_tags=False, passphrase=passphrase, resource_filters=[model.GroupResource.group_id==g.id]) # @UndefinedVariable fn='group-{0}-export.pgp'.format(re.sub('[^\w\-\.]', '_', g.name)) print "Exporting group '{0}' to file: {1}".format(g.name, fn) with open(os.path.join(dirpath, fn), 'w') as output_file: exporter.export(stream=output_file)
def from_structure(self, structure): """ Populates the SQLAlchemy model from a python dictionary of the database structure. """ session = meta.Session() try: for resource_s in structure['resources']: log.debug("Importing: {0!r}".format(resource_s)) # First build up a list of group_ids for this resource that will correspond to groups # in *this* database. group_ids = [] for gname in resource_s['groups']: group = groups.get_by_name(gname, assert_exists=False) if not group: group = groups.create(gname) log.info("Created group: {0!r}".format(group)) else: log.info("Found existing group: {0!r}".format(group)) group_ids.append(group.id) # First we should see if there is a match for the id and name; we can't rely on name alone since # there is no guarantee of name uniqueness (even with a group) resource = None resource_candidate = resources.get(resource_s['id'], assert_exists=False) if resource_candidate and resource_candidate.name == resource_s['name']: resource = resource_candidate else: # If we find a matching resource (by name) and there is only one then we'll use that. try: resource = resources.get_by_name(resource_s['name'], assert_single=True, assert_exists=True) except MultipleResultsFound: log.info("Multiple resource matched name {0!r}, will create a new one.".format(resource_s['name'])) except exc.NoSuchEntity: log.debug("No resource found matching name: {0!r}".format(resource_s['name'])) pass resource_attribs = ('name', 'addr', 'description', 'notes', 'tags') resource_attribs_update = dict([(k,v) for (k,v) in resource_s.items() if k in resource_attribs]) if resource: (resource, modified) = resources.modify(resource.id, group_ids=group_ids, **resource_attribs_update) # (yes, we are overwriting 'resource' var with new copy returned from this method) log.info("Updating existing resource: {0!r} (modified: {1!r})".format(resource, modified)) if modified and modified != ['group_ids']: if not self.force: raise RuntimeError("Refusing to modify existing resource attributes {0!r} on {1!r} (use 'force' to override this).".format(modified, resource)) else: log.warning("Overwriting resource attributes {0!r} on {1!r}".format(modified, resource)) else: # We will just assume that we need to create the resource. Yes, it's possible it'll match an existing # one, but better to build a merge tool than end up silently merging things that are not the same. resource = resources.create(group_ids=group_ids, **resource_attribs_update) log.info("Created new resource: {0!r}".format(resource)) # Add the passwords for password_s in resource_s['passwords']: password_attribs = ('username', 'description', 'password', 'tags') password_attribs_update = dict([(k,v) for (k,v) in password_s.items() if k in password_attribs]) # Look for a matching password. We do know that this is unique. password = passwords.get_for_resource(password_s['username'], password_s['resource_id'], assert_exists=False) if password: (password, modified) = passwords.modify(password_id=password.id, **password_attribs_update) # (Yeah, we overwrite password object.) log.info("Updating existing password: {0!r} (modified: {1!r})".format(password, modified)) non_pw_modified = set(modified) - set(['password']) if not modified: log.debug("Password row not modified.") else: log.debug("Password modified: {0!r}".format(modified)) # If anything changed other than password, we need to ensure that force=true if non_pw_modified: if not self.force: raise RuntimeError("Refusing to modify existing password attributes {0!r} on {1!r} (use 'force' to override this).".format(non_pw_modified, password)) else: log.warning("Overwriting password attributes {0!r} on {1!r}".format(non_pw_modified, password)) else: password = passwords.create(resource_id=resource.id, **password_attribs_update) log.info("Creating new password: {0!r}".format(password)) # This probably isn't necessary as all the DAO methods should also flush session, but might as well. session.flush() except: session.rollback() raise