Skip to content

A simple, internal-use file server with Azure AD authentication and per-user bucket-based access control.

License

Notifications You must be signed in to change notification settings

zharmon2/flask-fileserver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ—‚οΈ flask-fileserver

Python Flask License

A simple, internal-use file server with Azure AD authentication and per-user bucket-based access control.

Ideal for internal homepages, admin panels, or internal tools that need secure file upload/download functionality without full cloud complexity.


🎯 Features

  • Bucket + file system storage
  • Per-user access control (read, write, admin)
  • Microsoft Azure AD (Entra ID) token authentication
  • Simple local file locking for safe concurrent writes
  • Max file size limits via environment variable
  • Extremely low operational overhead

βš™οΈ System Requirements

Requirement Description
Python 3.8+
Flask Flask web server
Azure Tenant ID Obtained via Entra
Azure Client ID Obtained via Entra
FILE_STORAGE_LOCATION Local folder path for storage
DEFAULT_ADMIN Initial system admin username (UPN)

Recommended: run behind nginx (or similar) in production.


πŸ”§ Setup

  1. Clone this repo
  2. Install dependencies:
pip install -r requirements.txt
  1. Create a .env file:
MSAL_TENANT_ID=<Azure Tenant ID>
MSAL_CLIENT_ID=<Azure Client ID>
FILE_STORAGE_LOCATION=/path/to/files
DEFAULT_ADMIN=<admin user UPN (email)>
MAX_FILE_SIZE_MB=100     # optional, defaults to 100
  1. Run the server:
python app.py

This will create:

  • FILESERVER_BUCKETS.fsconfig
  • FILESERVER_PERMISSIONS.fsconfig

πŸš€ Production Deployment Notes

By default, app.py enables CORS only for http://localhost:*.
If deploying behind nginx, or accessing from non-local clients, update:

CORS(
    app,
    supports_credentials=True,
    origins=["http://your-frontend-url.com"],
    allow_headers=["Authorization", "Content-Type"]
)

Also modify app.run() to bind to 0.0.0.0 if you want to expose it:

app.run(debug=True, host="0.0.0.0", port=5000)

πŸ”‘ Authentication

This server does not issue tokens.
Clients must acquire an Azure AD token using MSAL (Microsoft Authentication Library) for their platform.
Supply the token on every request:

Authorization: Bearer <your_token>

All tokens must be acquired on company-managed compliant devices (if Conditional Access applies).


πŸ“ Permissions Model

Level Description
admin Full control of system or bucket
write Can upload or delete files
read Can download or list files
remove Used to remove user access

DEFAULT_ADMIN automatically has admin on SYSTEM and all buckets.


πŸ“š API Reference

All routes require:

Authorization: Bearer <Azure Token>

Buckets

GET /buckets

Get list of user-accessible buckets.

[
  {
    "bucket_id": "uuid",
    "bucket_name": "Reports",
    "created_by": "user@example.com",
    "created_at": "ISO8601"
  }
]

POST /buckets

Create a bucket.

{ "bucket_name": "MyBucket" }

Returns:

{ "bucket_id": "uuid" }

DELETE /buckets/<bucket_id>

Delete a bucket.

{ "success": true }

Files

GET /buckets/<bucket_id>/files

List files in a bucket.

[
  {
    "file_id": "uuid",
    "file_name": "report.pdf",
    "file_size": 1.2,
    "created_by": "user@example.com",
    "created_at": "ISO8601"
  }
]

POST /buckets/<bucket_id>/files

Upload a file (multipart/form-data):

file = <binary file>

Returns:

{ "file_id": "uuid" }

GET /buckets/<bucket_id>/files/<file_id>

Download a file.
Returns file as attachment.

DELETE /buckets/<bucket_id>/files/<file_id>

Delete a file.

{ "success": true }

Permissions

POST /buckets/<bucket_id>/permissions

Set or remove a user’s permission:

{
  "user": "user@example.com",
  "permission": "admin"   // or "read", "write", "remove"
}

Returns:

{ "success": true }

System Admins

POST /system/admins

Grant SYSTEM admin rights:

{ "admin": "user@example.com" }

DELETE /system/admins

Revoke SYSTEM admin rights:

{ "admin": "user@example.com" }

πŸ§‘β€πŸ’» Example curl Requests

Get Buckets

curl -H "Authorization: Bearer <your_token>" http://localhost:5000/buckets

Create Bucket

curl -X POST -H "Authorization: Bearer <your_token>" -H "Content-Type: application/json" -d '{"bucket_name": "MyNewBucket"}' http://localhost:5000/buckets

Upload File

curl -X POST -H "Authorization: Bearer <your_token>" -F "file=@/path/to/your/file.pdf" http://localhost:5000/buckets/<bucket_id>/files

🎯 Purpose & Scope

This system is designed to:

  • Replace internal app file storage systems using base64 blobs
  • Provide internal tools with simple secure file uploads
  • Be easily auditable and fully controlled by developers

This is NOT designed for:

  • Internet-scale workloads
  • Unmanaged public access
  • Extreme file sizes (>2GB)
  • Multi-server high availability

Think: internal team utility, not production cloud file service.


⚠️ Disclaimer

This system is meant for internal environments only.
Do not expose directly to the public internet.
Deploy behind internal reverse proxies and firewalls for safety.


βœ… Status

Production stable for small to medium internal use cases.
Actively used in practice projects and prototype tooling.


πŸŽ‰ Done!

This system is minimal by design and provides just enough features to be powerful without complexity.
Use it, customize it, improve it!