def delete(self, token: AccessToken.Payload, username: str): # delete user deleted_count = Users().delete_one({ "username": username }).deleted_count if deleted_count == 0: raise errors.NotFound() Workers().delete_many({"username": username}) return Response(status=HTTPStatus.NO_CONTENT)
def patch(self, username: str, token: AccessToken.Payload): query = {"username": username} request_json = request.get_json() if username == token.username: # user is trying to set their own password # get current password password_current = request_json.get("current", None) if password_current is None: raise errors.BadRequest() # get current password hash user = Users().find_one(query, {"password_hash": 1}) if user is None: raise errors.NotFound() # check current password is valid is_valid = check_password_hash(user["password_hash"], password_current) if not is_valid: raise errors.Unauthorized() else: # user is trying to set other user's password # check permission if not token.get_permission("users", "change_password"): raise errors.NotEnoughPrivilege() # get new password password_new = request_json.get("new", None) if password_new is None: raise errors.BadRequest() # set new password matched_count = (Users().update_one( query, { "$set": { "password_hash": generate_password_hash(password_new) } }).matched_count) # send response if matched_count == 0: raise errors.NotFound() return Response(status=HTTPStatus.NO_CONTENT)
def get(self, username: str, token: AccessToken.Payload): # if user in url is not user in token, check user permission if username != token.username: if not token.get_permission("users", "ssh_keys"): raise errors.NotEnoughPrivilege() user = Users().find_one({"username": username}, {"ssh_keys": 1}) if user is None: raise errors.NotFound() ssh_keys = user.get("ssh_keys", []) return jsonify(ssh_keys)
def delete(self, username: str, fingerprint: str, token: AccessToken.Payload): # if user in url is not user in token, check user permission if username != token.username: if not token.get_permission("users", "ssh_keys"): raise errors.NotEnoughPrivilege() # database result = Users().update_one( {"username": username}, {"$pull": {"ssh_keys": {"fingerprint": fingerprint}}}, ) if result.modified_count > 0: Response(status=HTTPStatus.NO_CONTENT) else: raise errors.NotFound() return Response(status=HTTPStatus.NO_CONTENT)
def get(self, token: AccessToken.Payload, username: str): # if user in url is not user in token, check user permission if username != token.username: if not token.get_permission("users", "read"): raise errors.NotEnoughPrivilege() # find user based on _id or username user = Users().find_one( {"username": username}, {"_id": 0, "username": 1, "email": 1, "scope": 1, "ssh_keys": 1}, ) if user is None: raise errors.NotFound() user["role"] = get_role_for(user.get("scope")) return jsonify(user)
def get(self, username: str, fingerprint: str): # list of permission to test the matching user against requested_permissions = request.args.getlist("with_permission") or [] query = {} # request using `-` as username searchs on all users if username != "-": query.update({"username": username}) query.update({"ssh_keys.fingerprint": fingerprint}) # database user = Users().find_one( query, { "username": 1, "scope": 1, "ssh_keys": 1, }, ) # no user means no matching SSH key for fingerprint if not user: raise errors.NotFound() key = [ key for key in user["ssh_keys"] if key["fingerprint"] == fingerprint ][-1] for permission in requested_permissions: namespace, perm_name = permission.split(".", 1) if not user.get("scope", {}).get(namespace, {}).get(perm_name): raise errors.NotEnoughPrivilege(permission) payload = { "username": user["username"], "key": key["key"], "type": key["type"], "name": key["name"], } return jsonify(payload)
def patch(self, token: AccessToken.Payload, username: str): # find user based on username query = {"username": username} if Users().count_documents(query) != 1: raise errors.NotFound() try: request_json = UserUpdateSchema().load(request.get_json()) except ValidationError as e: raise errors.BadRequest(e.messages) update = {} if "email" in request_json: update["email"] = request_json["email"] if "role" in request_json: update["scope"] = ROLES.get(request_json["role"]) Users().update_one(query, {"$set": update}) return Response(status=HTTPStatus.NO_CONTENT)
def post(self, username: str, token: AccessToken.Payload): # if user in url is not user in token, not allowed to add ssh keys if username != token.username: if not token.get_permission("users", "ssh_keys"): raise errors.NotEnoughPrivilege() try: request_json = KeySchema().load(request.get_json()) except ValidationError as e: raise errors.InvalidRequestJSON(e.messages) # parse public key string key = request_json["key"] key_parts = key.split(" ") if len(key_parts) >= 2: key = key_parts[1] # compute fingerprint try: rsa_key = paramiko.RSAKey(data=base64.b64decode(key)) fingerprint = binascii.hexlify(rsa_key.get_fingerprint()).decode() except (binascii.Error, paramiko.SSHException): raise errors.BadRequest("Invalid RSA key") # get existing ssh key fingerprints query = {"username": username} user = Users().find_one(query, {"ssh_keys.fingerprint": 1}) if user is None: raise errors.NotFound() # find out if new ssh already exist fingerprints = set( [ssh_key["fingerprint"] for ssh_key in user.get("ssh_keys", [])] ) if fingerprint in fingerprints: raise errors.BadRequest("SSH key already exists") # add new ssh key to database ssh_key = { "name": request_json["name"], # ssh-keygen -l -f xxx.pub -E md5 - just data, without dots "fingerprint": fingerprint, "key": key, "type": "RSA", "added": datetime.now(), "last_used": None, } # get PKCS8 - ssh-keygen -e -f xxx.priv -m PKCS8 with tempfile.NamedTemporaryFile(mode="w", suffix=".pub", delete=False) as fp: fp.write("ssh-rsa {} {}\n".format(ssh_key["key"], ssh_key["name"])) keygen = subprocess.run( ["/usr/bin/ssh-keygen", "-e", "-f", fp.name, "-m", "PKCS8"], capture_output=True, text=True, ) if keygen.returncode != 0: raise errors.BadRequest(keygen.stderr) ssh_key.update({"pkcs8_key": keygen.stdout}) os.unlink(fp.name) Users().update_one(query, {"$push": {"ssh_keys": ssh_key}}) return Response(status=HTTPStatus.CREATED)