def update(dn): """ api call - update a single rule (full set update...) """ dn = force_attribute_type("dn", Rules.META["dn"]["type"], dn) # build update list based on user data and writeable attributes data = get_user_data([]) update = {} for attr in Rules.META: if Rules.META[attr]["write"] and attr in data: update[attr] = force_attribute_type(attr, Rules.META[attr]["type"], data[attr]) # for now only admins can set owner - might open up later... if g.user.role == Roles.FULL_ADMIN and "owner" in data: update["owner"] = data["owner"] # if attribute provided that cannot be written, return error for v in data: # skip 'dn' and 'owner' (already handled) if v == "dn" or v == "owner": continue if v not in Rules.META or not Rules.META[v]["write"]: abort(400, "unknown or invalid attribute '%s'" % v) # ensure at least one valid attribute provided for rule if len(update) == 0: abort(400, "no valid parameter provided") r = current_app.mongo.db.rules.update_one({"dn": dn}, {"$set": update}) if r.matched_count == 0: abort(404, "Rule(%s) not found" % dn) return {"success": True}
def create(cls): """ api call - create new user, returns dict with username """ # get user data with required parameters and validate parameters data = get_user_data(["username", "password"]) username = force_attribute_type("username", Users.META["username"]["type"], data["username"]) password = Users.hash_pass( force_attribute_type("password", Users.META["password"]["type"], data["password"])) role = data.get("role", Users.META["role"]["default"]) if not Roles.valid(role): abort(400, "Invalid role: %s" % role) # block reserved users from being created if username in Users.RESERVED: abort(400, "Username \"%s\" is reserved" % username) # find groups that user may already be a member of groups = Users.find_groups(username) # create user update = Rest.create.__func__(cls, current_app.mongo.db.users, rule_dn="/users/", override_attr={ "username": username, "password": password, "role": role, "groups": groups }) return {"success": True, "username": username}
def create(): """ api call - create new rule, returns DICT (not json) """ # get user data with required parameters (only dn is required) data = get_user_data(["dn"]) # minimum required attributes update = {"dn": data["dn"]} # for now only admins can set owner - might open up later... if g.user.role == Roles.FULL_ADMIN and "owner" in data: update["owner"] = data["owner"] else: update["owner"] = g.user.username # validate mandatory attributes for v in ("dn", "owner"): update[v] = force_attribute_type(v, str, update[v]) # dn must always be in the form /path... update["dn"] = "/%s" % update["dn"].strip("/") # reserved dn 'incr' used by api call to update_incr if update["dn"] == "/incr": abort(400, "'/incr' is no a valid DN") # validate optional attributes for v in Rules.META: if Rules.META[v]["write"] and v in data and v not in update: update[v] = force_attribute_type(v, Rules.META[v]["type"], data[v]) elif v not in update: # ensure all attributes are set for create operation update[v] = Rules.META[v]["default"] # if attribute provided that cannot be written, return error for v in data: # skip 'dn' and 'owner', already handled if v == "dn" or v == "owner": continue if v not in Rules.META or not Rules.META[v]["write"]: abort(400, "unknown or invalid attribute '%s'" % v) try: current_app.mongo.db.rules.insert_one(update) except DuplicateKeyError as e: abort(400, "Dn \"%s\" already exists" % update["dn"]) # create returns dict, not json, allowing calling function to # add/remove attributes as required by api return {"success": True, "dn": update["dn"]}
def update(cls, username): """ api call - update user """ # block reserved users if username in Users.RESERVED: abort(400, "Username \"%s\" is reserved" % username) # pre-processing custom attributes data = get_user_data([]) override_attr = {} # encrypt password if provided in update if "password" in data: override_attr["password"] = User.hash_pass( force_attribute_type("password", cls.META["password"]["type"], data["password"])) # validate role if provided in update if "role" in data: if not Roles.valid(data["role"]): abort(400, "Invalid role: %s" % data["role"]) override_attr["role"] = data["role"] # perform update (aborts on error) update = Rest.update.__func__( cls, current_app.mongo.db.users, update_one=("username", username), rule_dn="/users/%s" % username, override_attr=override_attr, ) return {"success": True}
def update_incr(cls): """ api call - incremental add/remove of entries in list - group is provided as a required attribute (similar to create) - list_name {"add":[list], "remove":[list]} """ # get user data with required parameters (only dn is required) data = get_user_data(["group"]) group = force_attribute_type("group", Groups.META["group"]["type"], data["group"]) # perform update_incr (aborts on error) update = Rest.update_incr.__func__( cls, current_app.mongo.db.groups, update_one=("group", group), rule_dn="/groups/%s" % group, ) # need to remove/add users from appropriate groups # (always perform 'remove' operation first) if "members" in update: m_update = update["members"] if "remove" in m_update and len(m_update["remove"]) > 0: Users.remove_groups(m_update["remove"], group) if "add" in m_update and len(m_update["add"]) > 0: Users.add_groups(m_update["add"], group) return {"success": True}
def update_incr(): """ api call - incremental add/remove of entries in list - dn is provided as a required attribute (similar to create) - list_name {"add":[list], "remove":[list]} """ # get user data with required parameters (only dn is required) data = get_user_data(["dn"]) dn = force_attribute_type("dn", Rules.META["dn"]["type"], data["dn"]) update = {} # validate optional attributes for v in ("read_users", "write_users", "read_groups", "write_groups"): if v in data: update[v] = {} if type(data[v]) is not dict: abort(400, "attribute '%s' should by type 'dict'" % v) for opt in ("add", "remove"): if opt not in data[v]: continue if type(data[v][opt]) is not list: abort( 400, "attribute %s[%s] should be type 'list'" % (v, opt)) if len(data[v][opt]) == 0: continue update[v][opt] = [] for entry in data[v][opt]: # force entry to string and append to update update[v][opt].append(str(entry)) # no validate data provided, pop index if len(update[v]) == 0: update.pop(v, None) # ensure at least one valid attribute provided for rule if len(update) == 0: incr_msg = "Expected at least one 'add' or 'remove' attribute" abort(400, "No valid parameter provided. %s" % incr_msg) # perform add/remove updates for v in update: if "add" in update[v] and len(update[v]["add"]) > 0: r = current_app.mongo.db.rules.update_one( {"dn": dn}, {"$addToSet": { v: { "$each": update[v]["add"] } }}) if r.matched_count == 0: abort(404, "Rule(%s) not found" % dn) if "remove" in update[v] and len(update[v]["remove"]) > 0: r = current_app.mongo.db.rules.update_one( {"dn": dn}, {"$pullAll": { v: update[v]["remove"] }}) if r.matched_count == 0: abort(404, "Rule(%s) not found" % dn) return {"success": True}
def delete(dn): """ api call - delete dn """ dn = force_attribute_type("dn", Rules.META["dn"]["type"], dn) r = filtered_read(current_app.mongo.db.rules, meta=Rules.META, filters={"dn": dn}) if len(r) == 0: abort(404, "Rule(%s) not found" % dn) # for now, only admin or rule owner can delete rule if g.user.role != Roles.FULL_ADMIN and \ r[0]["owner"] != g.user.username: abort(403, MSG_403) # delete the rule r = current_app.mongo.db.rules.delete_one({"dn": dn}) # verify delete occurred if r.deleted_count == 0: abort(404, "DN(%s) not found" % dn) return {"success": True}
def read(dn=None): """ api call - read one or more rules """ flt = {} if dn is not None: dn = force_attribute_type("dn", Rules.META["dn"]["type"], dn) flt["dn"] = dn # read rules results = filtered_read(current_app.mongo.db.rules, meta=Rules.META, filters=flt) # dn only provided on read_rule, need 404 error if not found if dn is not None: if len(results) == 0: abort(404, "DN(%s) not found" % dn) return results[0] # return full list of rules return {"rules": results}
def create(cls): """ api call - create new group, returns dict with group name """ # special checks for group put in override fields data = get_user_data(["group"]) group = force_attribute_type("group", str, data["group"]) if group == "incr": abort(400, "'incr' is no a valid group name") # create new group Rest.create.__func__(cls, current_app.mongo.db.groups, rule_dn="/groups/", required_attr=[], override_attr={"group": group}) # add group to list of users if 'members' provided if "members" in data and len(data["members"]) > 0: Users.add_groups(data["members"], group) # create returns dict, not json, allowing calling function to # add/remove attributes as required by api return {"success": True, "group": group}