コード例 #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
    """
    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"})
コード例 #2
0
async def delete_user(request, next_id):
    """Delete a specific user by next_id."""
    log_request(request)
    env = Env()
    if not env.int("ENABLE_NEXT_BASE_USE"):
        raise ApiDisabled("Not a valid action. Source not enabled.")
    txn_list = []
    txn_key, _ = await get_transactor_key(request)
    txn_list = await create_del_ownr_by_user_txns(txn_key, next_id, txn_list)
    txn_list = await create_del_admin_by_user_txns(txn_key, next_id, txn_list)
    txn_list = await create_del_mmbr_by_user_txns(txn_key, next_id, txn_list)
    txn_list = create_delete_user_txns(txn_key, next_id, txn_list)

    if txn_list:
        batch = batcher.make_batch_from_txns(transactions=txn_list,
                                             signer_keypair=txn_key)
    batch_list = batcher.batch_to_list(batch=batch)
    await send(request.app.config.VAL_CONN, batch_list,
               request.app.config.TIMEOUT)

    await reject_users_proposals(next_id, request)

    return json({
        "message": "User {} successfully deleted".format(next_id),
        "deleted": 1
    })
コード例 #3
0
async def check_role_name(request):
    """Check if a role exists with provided name."""
    log_request(request)
    conn = await create_connection()
    response = await roles_query.roles_search_duplicate(conn, request.args.get("name"))
    conn.close()
    return json({"exists": bool(response)})
コード例 #4
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,
    })
コード例 #5
0
async def fetch_open_proposals(request, next_id):
    """Get open proposals for a user, by their next_id.
    Args:
        request:
            obj: request object to api
        next_id:
            str: next_id of user for open proposals as assigned_approval
    """
    log_request(request)
    head_block = await get_request_block(request)
    start, limit = get_request_paging_info(request)
    conn = await create_connection()
    proposals = await proposals_query.fetch_all_proposal_resources(
        conn, start, limit)
    proposal_resources = []
    for proposal in proposals:
        proposal_resource = await compile_proposal_resource(conn, proposal)
        proposal_resources.append(proposal_resource)
    conn.close()
    open_proposals = []
    for proposal_resource in proposal_resources:
        if (proposal_resource["status"] == "OPEN"
                and next_id in proposal_resource["assigned_approver"]):
            open_proposals.append(proposal_resource)

    return await create_response(conn,
                                 request.url,
                                 open_proposals,
                                 head_block,
                                 start=start,
                                 limit=limit)
コード例 #6
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})
コード例 #7
0
async def add_task_owner(request, task_id):
    """Propose add a task owner."""
    log_request(request)
    required_fields = ["id"]
    validate_fields(required_fields, request.json)

    txn_key, txn_user_id = await get_transactor_key(request)
    proposal_id = str(uuid4())
    conn = await create_connection()
    approver = await fetch_relationships("task_admins", "task_id",
                                         task_id).run(conn)
    conn.close()
    batch_list = Task().owner.propose.batch_list(
        signer_keypair=txn_key,
        signer_user_id=txn_user_id,
        proposal_id=proposal_id,
        task_id=task_id,
        next_id=request.json.get("id"),
        reason=request.json.get("reason"),
        metadata=request.json.get("metadata"),
        assigned_approver=approver,
    )
    await send(request.app.config.VAL_CONN, batch_list,
               request.app.config.TIMEOUT)
    return json({"proposal_id": proposal_id})
コード例 #8
0
async def add_role_owner(request, role_id):
    """Add an owner to a role."""
    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())
    conn = await create_connection()
    approver = await fetch_relationships("role_admins", "role_id", role_id).run(conn)
    conn.close()
    batch_list = Role().owner.propose.batch_list(
        signer_keypair=txn_key,
        signer_user_id=txn_user_id,
        proposal_id=proposal_id,
        role_id=role_id,
        next_id=request.json.get("id"),
        reason=request.json.get("reason"),
        metadata=request.json.get("metadata"),
        assigned_approver=approver,
    )
    await send(request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT)
    if isinstance(approver, list):
        for user in approver:
            await send_notification(user, proposal_id)
    else:
        await send_notification(approver, proposal_id)
    return json({"proposal_id": proposal_id})
コード例 #9
0
async def update_proposal(request, proposal_id):
    """Update proposal."""
    log_request(request)
    LOGGER.debug("update proposal %s\n%s", proposal_id, request.json)
    required_fields = ["reason", "status"]
    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 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)
    conn.close()
    if txn_user_id not in approvers_list["approvers"]:
        raise ApiUnauthorized(
            "Bad Request: You don't have the authorization to APPROVE or REJECT the proposal"
        )
    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 send(request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT)
    await send_notification(proposal_resource.get("target"), proposal_id)
    return json({"proposal_id": proposal_id})
コード例 #10
0
async def fetch_rejected_proposals(request, next_id):
    """Get confirmed proposals for a user, by their next_id."""
    log_request(request)
    head_block = await get_request_block(request)
    start, limit = get_request_paging_info(request)
    conn = await create_connection()
    proposals = await proposals_query.fetch_all_proposal_resources(
        conn, start, limit)
    proposal_resources = []
    for proposal in proposals:
        proposal_resource = await compile_proposal_resource(conn, proposal)
        proposal_resources.append(proposal_resource)
    conn.close()

    rejected_proposals = []
    for proposal_resource in proposal_resources:
        if (proposal_resource["status"] == "REJECTED"
                and next_id in proposal_resource["approvers"]):
            rejected_proposals.append(proposal_resource)

    return await create_response(conn,
                                 request.url,
                                 rejected_proposals,
                                 head_block,
                                 start=start,
                                 limit=limit)
コード例 #11
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."}})
コード例 #12
0
async def batch_update_proposals(request):
    """Update multiple proposals"""
    log_request(request)
    required_fields = ["ids"]
    validate_fields(required_fields, request.json)
    for proposal_id in request.json["ids"]:
        await update_proposal(request, proposal_id)
    return json({"proposal_ids": request.json["ids"]})
コード例 #13
0
async def get_role(request, role_id):
    """Get a specific role by role_id."""
    log_request(request)
    head_block = await get_request_block(request)
    conn = await create_connection()
    role_resource = await roles_query.fetch_role_resource(conn, role_id)
    conn.close()
    return await create_response(conn, request.url, role_resource, head_block)
コード例 #14
0
async def get_task(request, task_id):
    """Get a specific task by task_id."""
    log_request(request)
    head_block = await get_request_block(request)
    conn = await create_connection()
    task_resource = await tasks_query.fetch_task_resource(conn, task_id)
    conn.close()
    return await create_response(conn, request.url, task_resource, head_block)
コード例 #15
0
async def get_proposal(request, proposal_id):
    """Get specific proposal by proposal_id."""
    log_request(request)
    head_block = await get_request_block(request)
    conn = await create_connection()
    proposal = await proposals_query.fetch_proposal_resource(conn, proposal_id)
    proposal_resource = await compile_proposal_resource(conn, proposal)
    conn.close()
    return await create_response(conn, request.url, proposal_resource, head_block)
コード例 #16
0
async def get_pack(request, pack_id):
    """Get a single pack"""
    log_request(request)
    head_block = await get_request_block(request)
    conn = await create_connection()
    pack_resource = await packs_query.fetch_pack_resource(conn, pack_id)
    conn.close()

    return await create_response(conn, request.url, pack_resource, head_block)
コード例 #17
0
async def get_user_relationships(request, next_id):
    """Get relationships for a specific user, by next_id."""
    log_request(request)
    head_block = await get_request_block(request)
    conn = await create_connection()
    user_resource = await users_query.fetch_user_relationships(conn, next_id)
    conn.close()

    return await create_response(conn, request.url, user_resource, head_block)
コード例 #18
0
async def add_pack_role(request, pack_id):
    """Add roles to a pack"""
    log_request(request)
    required_fields = ["roles"]
    validate_fields(required_fields, request.json)
    conn = await create_connection()
    await packs_query.add_roles(conn, pack_id, request.json.get("roles"))
    conn.close()
    return json({"roles": request.json.get("roles")})
コード例 #19
0
async def get_user_summary(request, next_id):
    """This endpoint is for returning summary data for a user, just it's next_id,name, email."""
    log_request(request)
    head_block = await get_request_block(request)
    conn = await create_connection()
    user_resource = await users_query.fetch_user_resource_summary(
        conn, next_id)
    conn.close()

    return await create_response(conn, request.url, user_resource, head_block)
コード例 #20
0
async def update_expired_roles(request, next_id):
    """Manually expire user role membership"""
    log_request(request)
    required_fields = ["id"]
    validate_fields(required_fields, request.json)

    conn = await create_connection()
    await roles_query.expire_role_member(conn, request.json.get("id"), next_id)
    conn.close()
    return json({"role_id": request.json.get("id")})
コード例 #21
0
async def get_all_roles(request):
    """Get all roles."""
    log_request(request)
    head_block = await get_request_block(request)
    start, limit = get_request_paging_info(request)
    conn = await create_connection()
    role_resources = await roles_query.fetch_all_role_resources(conn, start, limit)
    conn.close()
    return await create_response(
        conn, request.url, role_resources, head_block, start=start, limit=limit
    )
コード例 #22
0
async def get_latest_block(request):
    """Get the newest block on blockchain."""
    log_request(request)
    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})
コード例 #23
0
async def create_new_role(request):
    """Create a new role."""
    log_request(request)
    env = Env()
    if not env.int("ENABLE_NEXT_BASE_USE"):
        raise ApiDisabled("Not a valid action. Source not enabled.")
    required_fields = ["name", "administrators", "owners"]
    validate_fields(required_fields, request.json)
    role_title = " ".join(request.json.get("name").split())
    conn = await create_connection()
    response = await roles_query.roles_search_duplicate(conn, role_title)
    conn.close()
    if not response:
        txn_key, txn_user_id = await get_transactor_key(request)
        role_id = str(uuid4())

        if request.json.get("metadata") is None:
            set_metadata = {}
        else:
            set_metadata = request.json.get("metadata")
        set_metadata["sync_direction"] = "OUTBOUND"
        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"),
        )
        sawtooth_response = await send(
            request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT
        )

        if not sawtooth_response:
            LOGGER.warning("There was an error submitting the sawtooth transaction.")
            return await handle_errors(
                request,
                ApiInternalError(
                    "There was an error submitting the sawtooth transaction."
                ),
            )

        return create_role_response(request, role_id)
    return await handle_errors(
        request,
        ApiTargetConflict(
            "Error: Could not create this role because the role name already exists."
        ),
    )
コード例 #24
0
async def add_pack_member(request, pack_id):
    """Add a member to the roles of a pack"""
    log_request(request)
    required_fields = ["id"]
    validate_fields(required_fields, request.json)

    conn = await create_connection()
    pack_resource = await packs_query.fetch_pack_resource(conn, pack_id)
    conn.close()
    request.json["metadata"] = ""
    request.json["pack_id"] = pack_id
    for role_id in pack_resource.get("roles"):
        await add_role_member(request, role_id)
    return json({"pack_id": pack_id})
コード例 #25
0
async def get_all_proposals(request):
    """Get all proposals"""
    log_request(request)
    head_block = await get_request_block(request)
    start, limit = get_request_paging_info(request)
    conn = await create_connection()
    proposals = await proposals_query.fetch_all_proposal_resources(conn, start, limit)
    proposal_resources = []
    for proposal in proposals:
        proposal_resource = await compile_proposal_resource(conn, proposal)
        proposal_resources.append(proposal_resource)
    conn.close()
    return await create_response(
        conn, request.url, proposal_resources, head_block, start=start, limit=limit
    )
コード例 #26
0
async def search_all(request):
    """API Endpoint to get all roles, packs, or users containing a string."""
    log_request(request)
    search_query = request.json.get("query")

    # Check for valid payload containing query and search object types
    errors = validate_search_payload(search_query)
    if errors:
        return json(errors)

    # Create response data object
    data = {"packs": [], "roles": [], "users": []}

    # Pagination and total pages
    try:
        paging = search_paginate(search_query["page_size"], search_query["page"])
    except KeyError:
        paging = (0, 50)

    object_counts = []

    # Run search queries
    conn = await create_connection()
    if "pack" in search_query["search_object_types"]:
        # Fetch packs with search input string

        pack_results = await search_packs(conn, search_query, paging)
        data["packs"] = pack_results
        object_counts.append(await search_packs_count(conn, search_query))

    if "role" in search_query["search_object_types"]:
        # Fetch roles with search input string
        role_results = await search_roles(conn, search_query, paging)
        data["roles"] = role_results
        object_counts.append(await search_roles_count(conn, search_query))

    if "user" in search_query["search_object_types"]:
        # Fetch users with search input string
        user_results = await search_users(conn, search_query, paging)
        data["users"] = user_results
        object_counts.append(await search_users_count(conn, search_query))
    conn.close()

    total_pages = get_total_pages(object_counts, search_query["page_size"])

    return json(
        {"data": data, "page": search_query["page"], "total_pages": total_pages}
    )
コード例 #27
0
async def get_all_blocks(request):
    """Get all blocks."""
    conn = await create_connection()
    log_request(request)
    head_block = await get_request_block(request)
    start, limit = get_request_paging_info(request)
    block_resources = await blocks_query.fetch_all_blocks(
        conn, head_block.get("num"), start, limit)
    conn.close()

    return await create_response(conn,
                                 request.url,
                                 block_resources,
                                 head_block,
                                 start=start,
                                 limit=limit)
コード例 #28
0
async def fetch_all_users(request):
    """Returns all users."""
    log_request(request)
    head_block = await get_request_block(request)
    start, limit = get_request_paging_info(request)
    conn = await create_connection()
    user_resources = await users_query.fetch_all_user_resources(
        conn, start, limit)
    conn.close()

    return await create_response(conn,
                                 request.url,
                                 user_resources,
                                 head_block,
                                 start=start,
                                 limit=limit)
コード例 #29
0
async def update_role(request, role_id):
    """Update a role."""
    log_request(request)
    env = Env()
    if not env.int("ENABLE_NEXT_BASE_USE"):
        raise ApiDisabled("Not a valid action. Source not enabled")
    required_fields = ["description"]
    validate_fields(required_fields, request.json)
    txn_key, txn_user_id = await get_transactor_key(request)
    role_description = request.json.get("description")
    batch_list = Role().update.batch_list(
        signer_keypair=txn_key,
        signer_user_id=txn_user_id,
        role_id=role_id,
        description=role_description,
    )
    await send(request.app.config.VAL_CONN, batch_list, request.app.config.TIMEOUT)
    return json({"id": role_id, "description": role_description})
コード例 #30
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.")