403 Forbidden File Creation with groov Manage Rest API

Hey! I’d like to run a python program locally that writes csv files to the local unsecured folder on the EPIC. I tried using the built in swagger interface to try to test the code. Specifically, it’s the put function /api/v1/files/{area}/rpc/create-file/{areaPath}.

In spite of putting in the recommended area and areaPath (unsecured and /home/dev/unsecured/log.csv), I keep getting a 403 forbidden error. I’m logged in as an admin and have tried a handful of areaPaths to no avail. This problem exists both on an EPIC and a RIO.

Is this something to do with the https side of things vs http? Something else?

https://rio-xxxxx/manage/api/v1/files/unsecured/rpc/create-file/%2Fhome%2Fdev%2Funsecured%2Flog.csv

our request body is the stock one:
{
“file”: “string”
}

Thanks!

1 Like

Are you also sending the API key as a header with your request? How are you formatting that?

I’d also try sending other HTTP requests besides file creation to see if it’s an authentication / file access issue or something else

I got some python code working already with the api key I do have. Some get functions and some post functions to write some variables - those were straightforward.

Using the same syntax, I’m getting a litany of errors, probably tied to how i’m structuring the area and areaPath is my guess. Regardless, it doesn’t work out of the swagger ui OR the python side.

Swagger UI is giving me 400 errors.
I did miss the lock-icon initially, so that might have lent to the ‘forbidden’ issue.

https://192.168.10.10/manage/api/v1/files/secured/rpc/create-file/filetest.csv

{
  "error": {
    "code": 1,
    "message": "Form did not include \"file\" file."
  }
}

in python, the request just goes-and-goes and eventually times out until I ctrl-c out of it. It never seems to resolve with an error. I’m curious if the json belongs in the put. There’s an alternate option for ‘files’ that doesn’t work as well.

import requests
def createFile(args):
url = “https://192.168.10.10/manage/api/v1/files/secured/rpc/create-file/filetest.csv
# address = ‘https://%s/pac/device/strategy/vars/strings’ % (self.args.ipaddress)
auth = (args.user, args.password)
headers = {‘apiKey’: args.apikey}
print(url, auth, headers)
r = requests.put(url=url, auth=auth, headers=headers, verify=False, json={“file”:“value”})
print(r)
return

1 Like

Thanks for the thorough response; for the file, can you instead provide the complete path rather than just the file name? I’m suspecting that the reason the script hangs is because it’s looking for a file that it cannot find and so it’s stuck looking for it.

Which “file” do you mean?

Not sure if you meant filename (in areaPath) or the request body, but changing areaPath to something like “/home/dev/secured/filetest.csv” gets me the same error (my Rio firmware is in that weird version that lacks unsecured).

The changing either the key or the value of ‘file’ in the request body nets me 503 again {serverLoading: True} or an error like 'Form did not include 'file'… again.

If there’s a sequence of things that work in the swagger ui (minus api key) on an Epic that’s been tested, I’d be happy working off of that as a basis.

1 Like

I was thinking the areaPath / filename, yes, but you’re right. I’ve reproduced the same results that you’re seeing on my end. I’m not entirely sure what we’re doing wrong, but I’ll keep at it and update this thread with anything I figure out.

image
Interestingly enough, when I tested a file upload through groov Manage (just an unrelated *.py file) it put an extra slash in the areaPath part of the URL:
https://epic-dev/manage/api/v1/files/unsecured/rpc/create-file//apiKey.py

But more importantly, the payload file was binary encoded:
image

I’m not sure swagger supports that kind of payload format, where the “Accept-Encoding” in the request headers lists gzip, deflate, br, zstd
image

With your Python script, can you send the payload as binary and see if the script still hangs? Depending on what file type you want to create, that may be what’s causing the issue, although I’m not sure why you’re not getting an error back.

2 Likes

To help get a jump start on having this work with Python, here’s a script we put together (thanks to @ccaldwell). Note that depending on the exact file you’re sending, you may want to substitute this line:

files = { 'file': (fileName, file_content, 'multipart/form-data') }

The important thing being that the request content-type is correct. It seems that groov Manage does not very elegantly recover if that is incorrect or missing entirely.


import requests

# Define the API endpoint and parameters
area = 'unsecured'  # or 'secured', 'usb' as required
area_path = 'testing'  # Adjust as needed
hostname = 'opto-02-2A-22'  # Adjust as needed
apiKey = 'insertapikeyhere'  # Replace with actual API key
fileName = 'upload_test.py'
url = f'https://{hostname}/manage/api/v1/files/{area}/rpc/create-file/{fileName}'

# Set up the headers, including the required apiKey
headers = {
    'accept': '*/*',
    'apiKey': apiKey,
}

# Open the script file and read it in binary mode
with open(fileName, 'rb') as f:
    file_content = f.read()

# Binary-encode the file content
files = {
    'file': (fileName, file_content, 'application/octet-stream')  # Correct MIME type
}

# Make the PUT request with the file included in the multipart/form-data
response = requests.put(url, headers=headers, files=files, verify=False)

# Print the response status and body for verification
print(f"Status Code: {response.status_code}")
print(f"Response Body: {response.text}")
2 Likes