Exemplo n.º 1
0
async def update_password(request):
    """Update a user's password.  The request must come from an admin.
    Args:
        request:
            obj: a request object
    """
    env = Env()
    next_enabled = env.int("ENABLE_NEXT_BASE_USE", 0)
    if not next_enabled:
        raise ApiBadRequest("This capability is not enabled for this mode.")
    required_fields = ["next_id", "password"]
    utils.validate_fields(required_fields, request.json)
    txn_key, txn_user_id = await utils.get_transactor_key(request)
    is_admin = await utils.check_admin_status(txn_user_id)
    if not is_admin:
        raise ApiBadRequest("You are not a NEXT Administrator.")
    hashed_pwd = hashlib.sha256(
        request.json.get("password").encode("utf-8")
    ).hexdigest()
    conn = await create_connection()
    await users_query.update_user_password(
        conn, request.json.get("next_id"), hashed_pwd
    )
    conn.close()
    return json({"message": "Password successfully updated"})
Exemplo n.º 2
0
async def delete_pack(request, pack_id):
    """Delete pack from NEXT
    Args:
        request:
            object: request object
        pack_id:
            str: ID of pack to delete
    """
    txn_key, txn_user_id = await utils.get_transactor_key(request)

    pack = await packs_query.get_pack_by_pack_id(request.app.config.DB_CONN, pack_id)
    if not pack:
        raise ApiBadRequest(
            "Error: Pack does not currently exist or has already been deleted."
        )
    owners = await packs_query.get_pack_owners_by_id(
        request.app.config.DB_CONN, pack_id
    )
    if txn_user_id not in owners and not await utils.check_admin_status(txn_user_id):
        raise ApiBadRequest(
            "Error: You do not have the authorization to delete this pack."
        )
    await packs_query.delete_pack_by_id(request.app.config.DB_CONN, pack_id)
    return json(
        {
            "message": "Pack {} successfully deleted".format(pack_id),
            "deleted": 1,
            "id": pack_id,
        }
    )
Exemplo n.º 3
0
async def update_proposal(request, proposal_id):
    """Update proposal."""
    LOGGER.debug("update proposal %s\n%s", proposal_id, request.json)
    required_fields = ["reason", "status"]
    utils.validate_fields(required_fields, request.json)
    if request.json["status"] not in ("REJECTED", "APPROVED"):
        raise ApiBadRequest(
            "Bad Request: status must be either 'REJECTED' or 'APPROVED'")
    txn_key, txn_user_id = await utils.get_transactor_key(request=request)

    conn = await create_connection()
    proposal_resource = await proposals_query.fetch_proposal_resource(
        conn, proposal_id=proposal_id)

    approvers_list = await compile_proposal_resource(conn, proposal_resource)
    if txn_user_id not in approvers_list["approvers"]:
        raise ApiBadRequest(
            "Bad Request: You don't have the authorization to APPROVE or REJECT the proposal"
        )

    conn.close()

    batch_list = PROPOSAL_TRANSACTION[proposal_resource.get("type")][
        request.json["status"]].batch_list(
            signer_keypair=txn_key,
            signer_user_id=txn_user_id,
            proposal_id=proposal_id,
            object_id=proposal_resource.get("object"),
            related_id=proposal_resource.get("target"),
            reason=request.json.get("reason"),
        )
    await utils.send(request.app.config.VAL_CONN, batch_list,
                     request.app.config.TIMEOUT)
    return json({"proposal_id": proposal_id})
Exemplo n.º 4
0
def validate_fields(required_fields, body):
    try:
        for field in required_fields:
            if body.get(field) is None:
                raise ApiBadRequest(
                    "Bad Request: {} field is required".format(field))
    except ValueError:
        raise ApiBadRequest("Bad Request: Improper JSON format")
Exemplo n.º 5
0
def validate_fields(required_fields, body):
    """Checks that all required_fields are in body, raises exception if not."""
    try:
        for field in required_fields:
            if body.get(field) is None:
                raise ApiBadRequest(
                    "Bad Request: {} field is required".format(field))
    except ValueError:
        raise ApiBadRequest("Bad Request: Improper JSON format")
Exemplo n.º 6
0
async def send(conn, batch_list, timeout, webhook=False):
    """Send batch_list to sawtooth."""
    batch_request = client_batch_submit_pb2.ClientBatchSubmitRequest()
    batch_request.batches.extend(list(batch_list.batches))
    validator_response = await conn.send(
        validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
        batch_request.SerializeToString(),
        timeout,
    )
    client_response = client_batch_submit_pb2.ClientBatchSubmitResponse()
    client_response.ParseFromString(validator_response.content)
    status = client_response.status

    if not webhook:
        if status == client_batch_submit_pb2.ClientBatchSubmitResponse.INTERNAL_ERROR:
            raise ApiInternalError("Internal Error")
        elif status == client_batch_submit_pb2.ClientBatchSubmitResponse.INVALID_BATCH:
            raise ApiBadRequest("Invalid Batch")
        elif status == client_batch_submit_pb2.ClientBatchSubmitResponse.QUEUE_FULL:
            raise ApiInternalError("Queue Full")
    elif status != client_batch_submit_pb2.ClientBatchSubmitResponse.OK:
        return None

    status_request = client_batch_submit_pb2.ClientBatchStatusRequest()
    status_request.batch_ids.extend(
        list(b.header_signature for b in batch_list.batches))
    status_request.wait = True
    status_request.timeout = timeout
    validator_response = await conn.send(
        validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
        status_request.SerializeToString(),
        timeout,
    )
    status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
    status_response.ParseFromString(validator_response.content)
    status = status_response.status

    if not webhook:
        if status != client_batch_submit_pb2.ClientBatchStatusResponse.OK:
            raise ApiInternalError("Internal Error")
    elif status != client_batch_submit_pb2.ClientBatchStatusResponse.OK:
        return None

    response = status_response.batch_statuses[0]
    status = response.status

    if not webhook:
        if status == client_batch_submit_pb2.ClientBatchStatus.INVALID:
            raise ApiBadRequest("Bad Request: {}".format(
                response.invalid_transactions[0].message))
        elif status == client_batch_submit_pb2.ClientBatchStatus.PENDING:
            raise ApiInternalError("Internal Error: Transaction timed out.")
        elif status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
            raise ApiInternalError("Internal Error: Unspecified error.")
    return status
Exemplo n.º 7
0
async def send(conn, batch_list, timeout):
    batch_request = client_batch_submit_pb2.ClientBatchSubmitRequest()
    batch_request.batches.extend(list(batch_list.batches))

    validator_response = await conn.send(
        validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
        batch_request.SerializeToString(),
        timeout,
    )

    client_response = client_batch_submit_pb2.ClientBatchSubmitResponse()
    client_response.ParseFromString(validator_response.content)

    if (client_response.status ==
            client_batch_submit_pb2.ClientBatchSubmitResponse.INTERNAL_ERROR):
        raise ApiInternalError("Internal Error")
    elif (client_response.status ==
          client_batch_submit_pb2.ClientBatchSubmitResponse.INVALID_BATCH):
        raise ApiBadRequest("Invalid Batch")
    elif (client_response.status ==
          client_batch_submit_pb2.ClientBatchSubmitResponse.QUEUE_FULL):
        raise ApiInternalError("Queue Full")

    status_request = client_batch_submit_pb2.ClientBatchStatusRequest()
    status_request.batch_ids.extend(
        list(b.header_signature for b in batch_list.batches))
    status_request.wait = True
    status_request.timeout = timeout

    validator_response = await conn.send(
        validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
        status_request.SerializeToString(),
        timeout,
    )

    status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
    status_response.ParseFromString(validator_response.content)

    if status_response.status != client_batch_submit_pb2.ClientBatchStatusResponse.OK:
        raise ApiInternalError("Internal Error")

    resp = status_response.batch_statuses[0]

    if resp.status == client_batch_submit_pb2.ClientBatchStatus.COMMITTED:
        return resp
    elif resp.status == client_batch_submit_pb2.ClientBatchStatus.INVALID:
        raise ApiBadRequest("Bad Request: {}".format(
            resp.invalid_transactions[0].message))
    elif resp.status == client_batch_submit_pb2.ClientBatchStatus.PENDING:
        raise ApiInternalError(
            "Internal Error: Transaction submitted but timed out.")
    elif resp.status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
        raise ApiInternalError(
            "Internal Error: Something went wrong. Try again later.")
Exemplo n.º 8
0
def auth_via_ldap(user_map, password, env):
    """Authorize via LDAP credentials to access NEXT."""
    ldap_server = env("LDAP_SERVER")
    if ldap_server:
        server = Server(ldap_server)
        conn = Connection(
            server, user=user_map["remote_id"], password=password, read_only=True
        )
        if not conn.bind():
            ldap_login_msg = re.search(
                "data ([0-9a-fA-F]*), v[0-9a-fA-F]*", conn.result["message"]
            )
            if ldap_login_msg and ldap_login_msg.group(1):
                ldap_err_code = ldap_login_msg.group(1)
                login_error = LDAP_ERR_MESSAGES.get(
                    ldap_err_code, LDAP_ERR_MESSAGES["default"]
                )
            else:
                login_error = LDAP_ERR_MESSAGES["default"]

            raise ApiUnauthorized(login_error)
        conn.unbind()

        token = generate_api_key(env("SECRET_KEY"), user_map["next_id"])
        return utils.create_authorization_response(
            token,
            {"message": "Authorization successful", "next_id": user_map["next_id"]},
        )
    raise ApiBadRequest("Missing LDAP_SERVER env variable.")
Exemplo n.º 9
0
async def create_corpuser(request):
    """Create a new CORP user."""
    required_fields = ["id", "password"]
    utils.validate_fields(required_fields, request.json)
    log_request(request, True)

    env = Env()
    username = env("ADAPI_USERNAME")
    password = env("ADAPI_PASSWORD")

    auth = aiohttp.BasicAuth(login=username, password=password)
    url = ADAPI_REST_ENDPOINT + "?command=new-corpuser"
    data = {
        "ntid": request.json.get("id"),
        "userName": request.json.get("id"),
        "password": request.json.get("password"),
    }
    conn = aiohttp.TCPConnector(
        limit=request.app.config.AIOHTTP_CONN_LIMIT,
        ttl_dns_cache=request.app.config.AIOHTTP_DNS_TTL,
        verify_ssl=False,
    )
    async with aiohttp.ClientSession(connector=conn, auth=auth) as session:
        async with session.post(url=url, json=data) as response:
            data = await response.read()
            res = json.loads(data.decode("utf-8"))
            if res.get("success") == "false":
                raise ApiBadRequest("Invalid CORP account request.")
            return sanic_json({"data": {"message": "CORP account request successful."}})
Exemplo n.º 10
0
async def get_block(request, block_id):
    if "?head=" in request.url:
        raise ApiBadRequest(
            "Bad Request: 'head' parameter should not be specified")
    block_resource = await blocks_query.fetch_block_by_id(
        request.app.config.DB_CONN, block_id)
    return json({"data": block_resource, "link": request.url})
Exemplo n.º 11
0
async def update_proposal(request, proposal_id):
    required_fields = ["reason", "status"]
    utils.validate_fields(required_fields, request.json)
    if request.json["status"] not in [Status.REJECTED, Status.APPROVED]:
        raise ApiBadRequest(
            "Bad Request: status must be either 'REJECTED' or 'APPROVED'")
    txn_key = await utils.get_transactor_key(request=request)
    block = await utils.get_request_block(request)
    proposal_resource = await proposals_query.fetch_proposal_resource(
        request.app.config.DB_CONN,
        proposal_id=proposal_id,
        head_block_num=block.get("num"),
    )

    batch_list, _ = PROPOSAL_TRANSACTION[proposal_resource.get("type")][
        request.json["status"]](
            txn_key,
            request.app.config.BATCHER_KEY_PAIR,
            proposal_id,
            proposal_resource.get("object"),
            proposal_resource.get("target"),
            request.json.get("reason"),
        )
    await utils.send(request.app.config.VAL_CONN, batch_list,
                     request.app.config.TIMEOUT)
    return json({"proposal_id": proposal_id})
Exemplo n.º 12
0
async def update_password(request):
    """Update a user's password.  The request must come from an admin.
    Args:
        request:
            obj: a request object
    """
    log_request(request)
    env = Env()
    if not env.int("ENABLE_NEXT_BASE_USE"):
        raise ApiDisabled("Not a valid action. Source not enabled")
    required_fields = ["next_id", "password"]
    validate_fields(required_fields, request.json)
    txn_key, txn_user_id = await get_transactor_key(request)
    is_admin = await check_admin_status(txn_user_id)
    if not is_admin:
        raise ApiBadRequest("You are not a NEXT Administrator.")

    salt = hashlib.sha256(os.urandom(60)).hexdigest().encode("utf-8")
    password = request.json.get("password").encode("utf-8")
    hashed_password = hashlib.pbkdf2_hmac("sha256", password, salt,
                                          100000).hex()

    conn = await create_connection()
    await users_query.update_user_password(conn,
                                           request.json.get("next_id"),
                                           hashed_password=hashed_password,
                                           salt=salt)
    conn.close()
    return json({"message": "Password successfully updated"})
Exemplo n.º 13
0
async def delete_pack(request, pack_id):
    """Delete pack from NEXT
    Args:
        request:
            object: request object
        pack_id:
            str: ID of pack to delete
    """
    log_request(request)
    _, txn_user_id = await get_transactor_key(request)

    conn = await create_connection()
    pack = await packs_query.get_pack_by_pack_id(conn, pack_id)
    if not pack:
        raise ApiBadRequest(
            "Error: Pack does not currently exist or has already been deleted."
        )
    owners = await packs_query.get_pack_owners_by_id(conn, pack_id)
    if txn_user_id not in owners and not await check_admin_status(txn_user_id):
        raise ApiForbidden(
            "Error: You do not have the authorization to delete this pack.")
    await packs_query.delete_pack_by_id(conn, pack_id)
    conn.close()
    return json({
        "message": "Pack {} successfully deleted".format(pack_id),
        "deleted": 1,
        "id": pack_id,
    })
Exemplo n.º 14
0
async def update_proposal(request, proposal_id):
    LOGGER.debug("update proposal %s\n%s", proposal_id, request.json)
    required_fields = ["reason", "status"]
    utils.validate_fields(required_fields, request.json)
    if request.json["status"] not in [Status.REJECTED, Status.APPROVED]:
        raise ApiBadRequest(
            "Bad Request: status must be either 'REJECTED' or 'APPROVED'")
    txn_key, txn_user_id = await utils.get_transactor_key(request=request)
    block = await utils.get_request_block(request)

    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )

    proposal_resource = await proposals_query.fetch_proposal_resource(
        conn, proposal_id=proposal_id, head_block_num=block.get("num"))
    conn.close()

    batch_list = PROPOSAL_TRANSACTION[proposal_resource.get("type")][
        request.json["status"]](
            signer_keypair=txn_key,
            signer_user_id=txn_user_id,
            proposal_id=proposal_id,
            object_id=proposal_resource.get("object"),
            related_id=proposal_resource.get("target"),
            reason=request.json.get("reason"),
        )
    await utils.send(request.app.config.VAL_CONN, batch_list,
                     request.app.config.TIMEOUT)
    return json({"proposal_id": proposal_id})
Exemplo n.º 15
0
async def create_new_role(request):
    """Create a new role."""
    required_fields = ["name", "administrators", "owners"]
    utils.validate_fields(required_fields, request.json)

    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )
    response = await roles_query.roles_search_duplicate(conn, request.json.get("name"))
    if not response:
        txn_key, txn_user_id = await utils.get_transactor_key(request)
        role_id = str(uuid4())
        batch_list = Role().batch_list(
            signer_keypair=txn_key,
            signer_user_id=txn_user_id,
            name=request.json.get("name"),
            role_id=role_id,
            metadata=request.json.get("metadata"),
            admins=request.json.get("administrators"),
            owners=request.json.get("owners"),
            description=request.json.get("description"),
        )
        await utils.send(
            request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT
        )
        return create_role_response(request, role_id)
    raise ApiBadRequest(
        "Error: could not create this role because role name has been taken or already exists"
    )
Exemplo n.º 16
0
async def create_new_pack(request):
    """Create a new pack"""
    required_fields = ["owners", "name", "roles"]
    utils.validate_fields(required_fields, request.json)
    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )
    response = await packs_query.packs_search_duplicate(
        conn, request.json.get("name"))
    if not response:
        pack_id = str(uuid4())
        await packs_query.create_pack_resource(
            conn,
            pack_id,
            request.json.get("owners"),
            request.json.get("name"),
            request.json.get("description"),
        )
        await packs_query.add_roles(conn, pack_id, request.json.get("roles"))
        conn.close()
        return create_pack_response(request, pack_id)
    raise ApiBadRequest(
        "Error: could not create this pack because pack name has been taken or already exists"
    )
Exemplo n.º 17
0
async def update_manager(request, next_id):
    """Update a user's manager."""
    log_request(request)
    env = Env()
    if not env.int("ENABLE_NEXT_BASE_USE"):
        raise ApiDisabled("Not a valid action. Source not enabled")
    required_fields = ["id"]
    validate_fields(required_fields, request.json)
    txn_key, txn_user_id = await get_transactor_key(request)
    proposal_id = str(uuid4())
    if await check_admin_status(txn_user_id):
        conn = await create_connection()
        next_admins_list = await users_query.get_next_admins(conn)
        conn.close()
        batch_list = User().manager.propose.batch_list(
            signer_keypair=txn_key,
            signer_user_id=txn_user_id,
            proposal_id=proposal_id,
            next_id=next_id,
            new_manager_id=request.json.get("id"),
            reason=request.json.get("reason"),
            metadata=request.json.get("metadata"),
            assigned_approver=next_admins_list,
        )
        await send(request.app.config.VAL_CONN, batch_list,
                   request.app.config.TIMEOUT)
        await send_notification(request.json.get("id"), proposal_id)
    else:
        raise ApiBadRequest("Proposal opener is not a Next Admin.")
    return json({"proposal_id": proposal_id})
Exemplo n.º 18
0
async def create_new_role(request):
    """Create a new role."""
    required_fields = ["name", "administrators", "owners"]
    utils.validate_fields(required_fields, request.json)
    conn = await create_connection()
    role_title = " ".join(request.json.get("name").split())
    response = await roles_query.roles_search_duplicate(conn, role_title)
    if request.json.get("metadata") is None or request.json.get("metadata") == {}:
        set_metadata = {}
    else:
        set_metadata = request.json.get("metadata")
    set_metadata["sync_direction"] = "OUTBOUND"
    if not response:
        txn_key, txn_user_id = await utils.get_transactor_key(request)
        role_id = str(uuid4())
        batch_list = Role().batch_list(
            signer_keypair=txn_key,
            signer_user_id=txn_user_id,
            name=role_title,
            role_id=role_id,
            metadata=set_metadata,
            admins=request.json.get("administrators"),
            owners=request.json.get("owners"),
            description=request.json.get("description"),
        )
        await utils.send(
            request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT
        )
        conn.close()
        if role_title != "NextAdmins":
            distinguished_name_formatted = "CN=" + role_title + "," + GROUP_BASE_DN
            data_formatted = {
                "created_date": r.now(),
                "distinguished_name": distinguished_name_formatted,
                "group_nickname": role_title,
                "group_types": -2147483646,
                "name": role_title,
                "remote_id": distinguished_name_formatted,
            }
            outbound_entry = {
                "data": data_formatted,
                "data_type": "group",
                "timestamp": r.now(),
                "provider_id": LDAP_DC,
            }
            # Insert to outbound_queue and close
            conn = await create_connection()
            role_outbound_resource = await roles_query.insert_to_outboundqueue(
                conn, outbound_entry
            )
            conn.close()
        else:
            LOGGER.info(
                "The role being created is NextAdmins, which is local to NEXT and will not be inserted into the outbound_queue."
            )
        return create_role_response(request, role_id)
    raise ApiBadRequest(
        "Error: Could not create this role because the role name already exists."
    )
Exemplo n.º 19
0
async def get_latest_block(request):
    if "?head=" in request.url:
        raise ApiBadRequest(
            "Bad Request: 'head' parameter should not be specified")
    block_resource = await blocks_query.fetch_latest_block_with_retry(
        request.app.config.DB_CONN)
    url = request.url.replace("latest", block_resource.get("id"))
    return json({"data": block_resource, "link": url})
Exemplo n.º 20
0
async def authorize(request):
    """ API Endpoint to authenticate and login to the NEXT platform. """
    required_fields = ["id", "password"]
    utils.validate_fields(required_fields, request.json)
    log_request(request, True)
    username = request.json.get("id")
    password = request.json.get("password")
    env = Env()

    if username == "" or password == "":
        raise ApiBadRequest(LDAP_ERR_MESSAGES["default"])
    user = await get_user_by_username(request)
    if not user:
        raise ApiBadRequest(LDAP_ERR_MESSAGES["default"])
    user_maps = await get_user_map_by_next_id(user["next_id"])

    # Locating auth source.  Prioritizes external syncs
    next_auth = None
    for user_map in user_maps:
        result = None
        if user_map["provider_id"] == env("LDAP_DC") and env.int("ENABLE_LDAP_SYNC"):
            result = auth_via_ldap(user_map, password, env)
        elif user_map["provider_id"] == env("TENANT_ID") and env.int(
            "ENABLE_AZURE_SYNC"
        ):
            auth_via_azure(user_map)
        elif user_map["provider_id"] == "NEXT-created":
            next_auth = user_map
        if result:
            auth_entry = {
                "next_id": user_map["next_id"],
                "username": user["username"],
                "email": user["email"],
                "encrypted_private_key": user_map["encrypted_key"],
                "public_key": user_map["public_key"],
            }
            await create_auth_entry(auth_entry)
            return result

    # Authorization via NEXT
    if next_auth and env.int("ENABLE_NEXT_BASE_USE"):
        return await auth_via_next(next_auth, password, env)

    raise ApiBadRequest("Invalid authentication source.")
Exemplo n.º 21
0
async def get_block(request, block_id):
    """Get a specific block, by block_id"""
    if "?head=" in request.url:
        raise ApiBadRequest(
            "Bad Request: 'head' parameter should not be specified")

    conn = await create_connection()
    block_resource = await blocks_query.fetch_block_by_id(conn, block_id)
    conn.close()

    return json({"data": block_resource, "link": request.url})
Exemplo n.º 22
0
async def get_latest_block(request):
    """Get the newest block on blockchain."""
    if "?head=" in request.url:
        raise ApiBadRequest(
            "Bad Request: 'head' parameter should not be specified")

    conn = await create_connection()
    block_resource = await blocks_query.fetch_latest_block_with_retry(conn)
    conn.close()

    url = request.url.replace("latest", block_resource.get("id"))
    return json({"data": block_resource, "link": url})
Exemplo n.º 23
0
async def get_block(request, block_id):
    if "?head=" in request.url:
        raise ApiBadRequest(
            "Bad Request: 'head' parameter should not be specified")

    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )

    block_resource = await blocks_query.fetch_block_by_id(conn, block_id)

    conn.close()

    return json({"data": block_resource, "link": request.url})
Exemplo n.º 24
0
async def check_admin_status(next_id):
    """Verfiy that a user is a member of NEXT admins.  Return boolean.
    Args:
        next_id:
            str: user's next_id
    """
    conn = await create_connection()
    admin_role = await get_role_by_name(conn, "NextAdmins")
    if not admin_role:
        raise ApiBadRequest("NEXT administrator group has not been created.")
    admin_membership = await get_role_membership(conn, next_id,
                                                 admin_role[0]["role_id"])
    conn.close()
    if admin_membership:
        return True
    return False
Exemplo n.º 25
0
async def get_latest_block(request):
    if "?head=" in request.url:
        raise ApiBadRequest(
            "Bad Request: 'head' parameter should not be specified")

    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )

    block_resource = await blocks_query.fetch_latest_block_with_retry(conn)

    conn.close()

    url = request.url.replace("latest", block_resource.get("id"))
    return json({"data": block_resource, "link": url})
Exemplo n.º 26
0
async def create_new_pack(request):
    """Create a new pack"""
    required_fields = ["owners", "name", "roles"]
    utils.validate_fields(required_fields, request.json)
    pack_title = " ".join(request.json.get("name").split())
    response = await packs_query.packs_search_duplicate(
        request.app.config.DB_CONN, pack_title)
    if not response:
        pack_id = str(uuid4())
        await packs_query.create_pack_resource(
            request.app.config.DB_CONN,
            pack_id,
            request.json.get("owners"),
            pack_title,
            request.json.get("description"),
        )
        await packs_query.add_roles(request.app.config.DB_CONN, pack_id,
                                    request.json.get("roles"))
        return create_pack_response(request, pack_id)
    raise ApiBadRequest(
        "Error: Could not create this pack because the pack name already exists."
    )
Exemplo n.º 27
0
async def update_manager(request, next_id):
    """Update a user's manager."""
    required_fields = ["id"]
    utils.validate_fields(required_fields, request.json)
    txn_key, txn_user_id = await utils.get_transactor_key(request)
    proposal_id = str(uuid4())
    if await utils.check_admin_status(txn_user_id):
        batch_list = User().manager.propose.batch_list(
            signer_keypair=txn_key,
            signer_user_id=txn_user_id,
            proposal_id=proposal_id,
            next_id=next_id,
            new_manager_id=request.json.get("id"),
            reason=request.json.get("reason"),
            metadata=request.json.get("metadata"),
            assigned_approver=[request.json.get("id")],
        )
        await utils.send(request.app.config.VAL_CONN, batch_list,
                         request.app.config.TIMEOUT)
    else:
        raise ApiBadRequest("Proposal opener is not an Next Admin.")
    return json({"proposal_id": proposal_id})
Exemplo n.º 28
0
async def update_user_details(request):
    """Update the details associated with a user.  This is NEXT admin only capability.

    Args:
        request:
            obj: request object from inbound request
    """
    log_request(request)
    # Checks for action viability
    env = Env()
    if not env.int("ENABLE_NEXT_BASE_USE", 0):
        raise ApiDisabled("This action is not enabled in this mode.")
    required_fields = ["next_id", "name", "username", "email"]
    validate_fields(required_fields, request.json)
    txn_key, txn_user_id = await get_transactor_key(request)
    is_admin = await check_admin_status(txn_user_id)
    if not is_admin:
        raise ApiForbidden("You are not a NEXT Administrator.")
    conn = await create_connection()
    user = await users_query.users_search_duplicate(
        conn, request.json.get("username"))
    if user and user[0]["next_id"] != request.json.get("next_id"):
        conn.close()
        raise ApiBadRequest(
            "Username already exists. Please give a different Username.")

    # Get resources for update
    user_info = await users_query.fetch_user_resource(
        conn, request.json.get("next_id"))
    if "manager_id" in user_info:
        manager = user_info["manager_id"]
    else:
        manager = ""
    conn.close()
    if request.json.get("metadata") is None or request.json.get(
            "metadata") == {}:
        set_metadata = {}
    else:
        set_metadata = request.json.get("metadata")
    set_metadata["sync_direction"] = "OUTBOUND"

    # Build and submit transaction
    batch_list = User().update.batch_list(
        signer_keypair=txn_key,
        signer_user_id=txn_user_id,
        next_id=request.json.get("next_id"),
        name=request.json.get("name"),
        username=request.json.get("username"),
        email=request.json.get("email"),
        metadata=set_metadata,
        manager_id=manager,
    )
    await send(request.app.config.VAL_CONN, batch_list,
               request.app.config.TIMEOUT)

    # Update_auth_table
    auth_updates = {
        "username": request.json.get("username"),
        "email": request.json.get("email"),
    }
    await auth_query.update_auth(request.json.get("next_id"), auth_updates)

    # Send back success response
    return json({"message": "User information was successfully updated."})
Exemplo n.º 29
0
async def create_new_user(request):
    """Create a new user."""
    required_fields = ["name", "username", "password", "email"]
    utils.validate_fields(required_fields, request.json)
    username_created = request.json.get("username")
    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )
    # Check if username already exists
    if await users_query.fetch_username_match_count(conn,
                                                    username_created) > 0:
        # Throw Error response to Next_UI
        raise ApiBadRequest(
            "Username already exists. Please give a different Username.")
    conn.close()

    # Generate keys
    key_pair = Key()
    next_id = str(uuid4())
    encrypted_private_key = encrypt_private_key(AES_KEY, key_pair.public_key,
                                                key_pair.private_key_bytes)

    # Build create user transaction
    batch_list = User().batch_list(
        signer_keypair=key_pair,
        signer_user_id=next_id,
        next_id=next_id,
        name=request.json.get("name"),
        username=request.json.get("username"),
        email=request.json.get("email"),
        metadata=request.json.get("metadata"),
        manager=request.json.get("manager"),
        key=key_pair.public_key,
    )

    # Submit transaction and wait for complete
    await utils.send(request.app.config.VAL_CONN, batch_list,
                     request.app.config.TIMEOUT)

    # Save new user in auth table
    hashed_password = hashlib.sha256(
        request.json.get("password").encode("utf-8")).hexdigest()

    auth_entry = {
        "next_id": next_id,
        "hashed_password": hashed_password,
        "encrypted_private_key": encrypted_private_key,
        "username": request.json.get("username"),
        "email": request.json.get("email"),
    }

    mapping_data = {
        "next_id": next_id,
        "provider_id": None,
        "remote_id": None,
        "public_key": key_pair.public_key,
        "encrypted_key": encrypted_private_key,
        "active": True,
    }

    # Insert to user_mapping and close
    conn = await db_utils.create_connection(
        request.app.config.DB_HOST,
        request.app.config.DB_PORT,
        request.app.config.DB_NAME,
    )
    await auth_query.create_auth_entry(conn, auth_entry)
    await users_query.create_user_map_entry(conn, mapping_data)
    conn.close()

    # Send back success response
    return create_user_response(request, next_id)
Exemplo n.º 30
0
async def authorize(request):
    """ API Endpoint to authenticate and login to the NEXT platform. """
    required_fields = ["id", "password", "auth_source"]
    utils.validate_fields(required_fields, request.json)
    username = request.json.get("id")
    password = request.json.get("password")
    auth_source = request.json.get("auth_source")

    if auth_source == "next":
        hashed_pwd = hashlib.sha256(password.encode("utf-8")).hexdigest()
        auth_info = await auth_query.fetch_info_by_username(request)
        email = auth_info.get("email")
        if auth_info.get("hashed_password") is None:
            if request.app.config.DEMO_MODE:
                token = generate_api_key(
                    request.app.config.SECRET_KEY, auth_info.get("user_id")
                )
                return utils.create_authorization_response(
                    token,
                    {
                        "message": "Authorization (demo mode) successful",
                        "user_id": auth_info.get("user_id"),
                    },
                )
            if not email:
                raise ApiUnauthorized("No password or email is set on this account.")
            # TODO: send email confirmation with password set link
            raise ApiUnauthorized("No password is set on this account.")
        if auth_info.get("hashed_password") != hashed_pwd:
            # TODO: rate limit password attempts
            raise ApiUnauthorized("The password you entered is incorrect.")

        token = generate_api_key(
            request.app.config.SECRET_KEY, auth_info.get("user_id")
        )
        return utils.create_authorization_response(
            token,
            {
                "message": "Authorization successful",
                "user_id": auth_info.get("user_id"),
            },
        )

    if auth_source == "ldap":
        if LDAP_SERVER:
            if username != "" and password != "":
                ldap_user_dn = await auth_query.fetch_dn_by_username(request)
                server = Server(LDAP_SERVER)
                conn = Connection(
                    server, user=ldap_user_dn, password=password, read_only=True
                )

                if not conn.bind():
                    ldap_login_msg = re.search(
                        "data ([0-9a-fA-F]*), v[0-9a-fA-F]*", conn.result["message"]
                    )
                    if ldap_login_msg and ldap_login_msg.group(1):
                        ldap_err_code = ldap_login_msg.group(1)
                        login_error = LDAP_ERR_MESSAGES.get(
                            ldap_err_code, LDAP_ERR_MESSAGES["default"]
                        )
                    else:
                        login_error = LDAP_ERR_MESSAGES["default"]

                    raise ApiUnauthorized(login_error)

                auth_info = await auth_query.fetch_info_by_username(request)
                conn.unbind()

                token = generate_api_key(
                    request.app.config.SECRET_KEY, auth_info.get("user_id")
                )
                return utils.create_authorization_response(
                    token,
                    {
                        "message": "Authorization successful",
                        "user_id": auth_info.get("user_id"),
                    },
                )
            raise ApiBadRequest(LDAP_ERR_MESSAGES["default"])
        raise ApiBadRequest("Missing LDAP_SERVER env variable.")
    raise ApiBadRequest("Invalid authentication source.")