vinbigdata-medical / vindr-lab-uploader

A part of the VinDr Lab project. Uploader modifies and transfers the DICOM files to database.
MIT License
9 stars 2 forks source link

How to upload files using the api call? #2

Open FeryET opened 2 years ago

FeryET commented 2 years ago

I am trying to write a terminal based client for vindr in order to batch upload many files using terminal.

Currently, I'm trying to mimick the api call using this.

import pathlib
import httpx
from keycloak import KeycloakOpenID

# token is gotten using python keycloak library
api = httpx.client()
path="temp.dcm"
result = api.post(
            f"{BASE_URL}/api/studies/upload",
            files={
                "file": (
                    pathlib.Path(path.strip()).name,
                    open(path, "rb").read(),
                    "application/dicom",
                )
            },
            data={"project_id": project_id.strip()},
            headers={"Authorization": f"Bearer {token}"},
            timeout=300,
        )

But I get 403 error. I don't get 403 error when trying to call other api endpoints using the same header after logging in keycloak. Any ideas what might cause this?

iamatsundere commented 2 years ago

Can you provide the token you are using, I recommend you should use the token from the UI. Because we have 2 steps to get the token, one for authentication, the other one for authorization.

FeryET commented 2 years ago

This is the code that I'm using to get the token.

from keycloak import KeycloakOpenID

# get username and password first
keycloak_openid = KeycloakOpenID(
        server_url=f"{BASE_URL}/auth/",
        client_id="vinlab-backend",
        realm_name="vinlab",
        client_secret_key="CLIENT_SECRET",
        verify=True,
    )
token = keycloak_openid.token(username, password)

The token will be something like this:

{
  "token_info": {
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtQlBwOFNnSkgtU2wxSzMtc1lQdTNSZFVYLTZGS0txSzJPTk5oUHlnM0lzIn0.eyJleHAiOjE2NTI4NTMwMTgsImlhdCI6MTY1Mjg1MjcxOCwianRpIjoiMDQ4YWI0MDEtNzgzNi00YTBkLThjMTgtOWJiZmEwZTljNjk1IiwiaXNzIjoiaHR0cHM6Ly9sYWJlbGxpbmcuYWltZWRpYy5jby9hdXRoL3JlYWxtcy92aW5sYWIiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiZjgxZDhlNDUtZmM3Yy00MTA3LWFkMDUtZGI1MzZhZWRhZTFkIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoidmlubGFiLWJhY2tlbmQiLCJzZXNzaW9uX3N0YXRlIjoiYzMxODlmNzktZDlhYi00NjY2LTkwNTctZDcxMmRiNDU2ZmQyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwczovL2xhYmVsbGluZy5haW1lZGljLmNvIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiUE8iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IkZhcmhvb2QgRXRhYXRpIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZmFyaG9vZGV0YWF0aSIsImdpdmVuX25hbWUiOiJGYXJob29kIiwiZmFtaWx5X25hbWUiOiJFdGFhdGkiLCJlbWFpbCI6ImZhcmhvb2RldGFhdGlAZ21haWwuY29tIn0.OGlZ771EalGWNH5zzzpdC12yNKBWtdsR2pO7WBMo6DLMoyeUzjueZjOPH3lFkrJubsSk5toay_F4RNl78NWpkgqao09V21GPCNULp_OTQrslObvkyus3KasiY4axhIXrKPGO4wLlRO5Q5Nj0O3MCf7IaqpeXYRVOQx3-thxdlJX8y_HKsquat5DYQVAJdViTV9SCxlXzJFrNKtPxWl2M_hp9UQNjGFEdCFvS6-RcJTCZuCvvA59z2MGLlAHBL-uoduNUVGe3nPDOWqlAjQqQBfahxod1a9VyFA0XDHSYsgGJoY4R2TztChbZJxpOFF6raNNIwUqxM3YaENeK5VkoMQ",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiM2RlM2I5Yi01OTY5LTQwZTUtYTFiMy01ZDhjZjBhYjkzM2EifQ.eyJleHAiOjE2NTI4NTQ1MTgsImlhdCI6MTY1Mjg1MjcxOCwianRpIjoiODZiOGRmM2EtNTFlOS00YjViLTlkMzgtNmRjNDU2YmMzYWE0IiwiaXNzIjoiaHR0cHM6Ly9sYWJlbGxpbmcuYWltZWRpYy5jby9hdXRoL3JlYWxtcy92aW5sYWIiLCJhdWQiOiJodHRwczovL2xhYmVsbGluZy5haW1lZGljLmNvL2F1dGgvcmVhbG1zL3ZpbmxhYiIsInN1YiI6ImY4MWQ4ZTQ1LWZjN2MtNDEwNy1hZDA1LWRiNTM2YWVkYWUxZCIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJ2aW5sYWItYmFja2VuZCIsInNlc3Npb25fc3RhdGUiOiJjMzE4OWY3OS1kOWFiLTQ2NjYtOTA1Ny1kNzEyZGI0NTZmZDIiLCJzY29wZSI6ImVtYWlsIHByb2ZpbGUifQ.v8L3ZR-QGAeeR5BxkpRu6r9KTh9TFzOmgxZXCdIRpO0",
    "token_type": "bearer",
    "not-before-policy": 0,
    "session_state": "c3189f79-d9ab-4666-9057-d712db456fd2",
    "scope": "email profile"
  },
}

And then in the Authorization header in my request, I put the Bearer {access_token} value.

Is any further step is required to login to the realm and use the api?

Using the token from the UI is not a good option because I want to upload around 25K files to our instance from a remote VM, and I want a way to do it automatically.

iamatsundere commented 2 years ago

I understand your issue with 25k files, totally . If you want to use the access token, you should call 2 requests to Keycloak. The first one is gotten by your above code. But the second one is more complicated. I recommend you to use the API Key that comes from this line of docker-compose file.

FeryET commented 2 years ago

I understand your issue with 25k files, totally . If you want to use the access token, you should call 2 requests to Keycloak. The first one is gotten by your above code. But the second one is more complicated. I recommend you to use the API Key that comes from this line of docker-compose file.

Can you elaborate more about this? In what procedure should I authenticate if not by the tokens? I didn't understand the use of API Key.