mirror of
https://git.collinwebdesigns.de/oscar.krause/fastapi-dls.git
synced 2024-12-28 22:39:34 +03:00
Merge branch 'dev' into 'main'
1.2 See merge request oscar.krause/fastapi-dls!16
This commit is contained in:
commit
c894537ff9
@ -6,10 +6,12 @@ CONFIG_DIR=/etc/fastapi-dls
|
||||
echo "> Create config directory ..."
|
||||
mkdir -p $CONFIG_DIR
|
||||
|
||||
# normally we would define services in `conffiles` and as separate file, but we like to keep thinks simple.
|
||||
echo "> Install service ..."
|
||||
cat <<EOF >/etc/systemd/system/fastapi-dls.service
|
||||
[Unit]
|
||||
Description=Service for fastapi-dls
|
||||
Documentation=https://git.collinwebdesigns.de/oscar.krause/fastapi-dls
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
@ -37,6 +39,7 @@ EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
# normally we would define configfiles in `conffiles` and as separate file, but we like to keep thinks simple.
|
||||
if [[ ! -f $CONFIG_DIR/env ]]; then
|
||||
echo "> Writing initial config ..."
|
||||
touch $CONFIG_DIR/env
|
||||
|
@ -1,8 +1,8 @@
|
||||
# Maintainer: samicrusader <hi@samicrusader.me>
|
||||
# Maintainer: Oscar Krause <oscar.krause@collinwebdesigns.de>
|
||||
# Contributor: samicrusader <hi@samicrusader.me>
|
||||
|
||||
pkgname=fastapi-dls
|
||||
pkgver=0.0
|
||||
pkgver=1.1
|
||||
pkgrel=1
|
||||
pkgdesc='NVIDIA DLS server implementation with FastAPI'
|
||||
arch=('any')
|
||||
@ -13,10 +13,12 @@ provider=("$pkgname")
|
||||
install="$pkgname.install"
|
||||
source=('git+file:///builds/oscar.krause/fastapi-dls' # https://gitea.publichub.eu/oscar.krause/fastapi-dls.git
|
||||
"$pkgname.default"
|
||||
"$pkgname.service")
|
||||
"$pkgname.service"
|
||||
"$pkgname.tmpfiles")
|
||||
sha256sums=('SKIP'
|
||||
'4c07e9b627853bd4f3a398371912fc72302dac33f43e4cb7e9b79746cc9c9136'
|
||||
'10cb98d64f8bf37b11a60510793c187cc664e63c895d1205781c21fa2e703f32')
|
||||
'fbd015449a30c0ae82733289a56eb98151dcfab66c91b37fe8e202e39f7a5edb'
|
||||
'2719338541104c537453a65261c012dda58e1dbee99154cf4f33b526ee6ca22e'
|
||||
'3dc60140c08122a8ec0e7fa7f0937eb8c1288058890ba09478420fc30ce9e30c')
|
||||
|
||||
pkgver() {
|
||||
source $srcdir/$pkgname/version.env
|
||||
@ -46,4 +48,5 @@ package() {
|
||||
install -Dm755 "$srcdir/$pkgname/app/util.py" "$pkgdir/opt/$pkgname/util.py"
|
||||
install -Dm644 "$srcdir/$pkgname.default" "$pkgdir/etc/default/$pkgname"
|
||||
install -Dm644 "$srcdir/$pkgname.service" "$pkgdir/usr/lib/systemd/system/$pkgname.service"
|
||||
install -Dm644 "$srcdir/$pkgname.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgname.conf"
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ DEBUG=false
|
||||
|
||||
# Where the client can find the DLS server
|
||||
## DLS_URL should be a hostname
|
||||
LISTEN_IP="0.0.0.0"
|
||||
DLS_URL="localhost.localdomain"
|
||||
DLS_PORT=8443
|
||||
CORS_ORIGINS="https://$DLS_URL:$DLS_PORT"
|
||||
@ -21,3 +22,7 @@ INSTANCE_REF="<<instanceref>>"
|
||||
# Site-wide signing keys
|
||||
INSTANCE_KEY_RSA="/var/lib/fastapi-dls/instance.private.pem"
|
||||
INSTANCE_KEY_PUB="/var/lib/fastapi-dls/instance.public.pem"
|
||||
|
||||
# TLS certificate
|
||||
INSTANCE_SSL_CERT="/var/lib/fastapi-dls/cert/webserver.crt"
|
||||
INSTANCE_SSL_KEY="/var/lib/fastapi-dls/cert/webserver.key"
|
||||
|
@ -4,12 +4,13 @@ Documentation=https://git.collinwebdesigns.de/oscar.krause/fastapi-dls
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
Type=simple
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
EnvironmentFile=/etc/default/fastapi-dls
|
||||
ExecStart=/usr/bin/python /opt/fastapi-dls/main.py
|
||||
WorkingDir=/opt/fastapi-dls
|
||||
ExecStart=/usr/bin/uvicorn main:app --proxy-headers --env-file=/etc/default/fastapi-dls --host=${LISTEN_IP} --port=${DLS_PORT} --app-dir=/opt/fastapi-dls --ssl-keyfile=${INSTANCE_SSL_KEY} --ssl-certfile=${INSTANCE_SSL_CERT}
|
||||
Restart=on-abort
|
||||
User=root
|
||||
User=http
|
||||
Group=http
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=multi-user.target
|
2
.PKGBUILD/fastapi-dls.tmpfiles
Normal file
2
.PKGBUILD/fastapi-dls.tmpfiles
Normal file
@ -0,0 +1,2 @@
|
||||
d /var/lib/fastapi-dls 0755 http http
|
||||
d /var/lib/fastapi-dls/cert 0755 http http
|
@ -275,9 +275,12 @@ release:
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
before_script:
|
||||
- set -a # make variables from "source" command available to release-cli
|
||||
- source version.env
|
||||
script:
|
||||
- echo "Running release-job for $VERSION"
|
||||
after_script:
|
||||
- set +a
|
||||
release:
|
||||
name: $CI_PROJECT_TITLE $version
|
||||
description: Release of $CI_PROJECT_TITLE version $VERSION
|
||||
|
12
README.md
12
README.md
@ -287,12 +287,14 @@ After first success you have to replace `--issue` with `--renew`.
|
||||
| `DLS_PORT` | `443` | Used in client-token to tell guest driver where dls instance is reachable |
|
||||
| `LEASE_EXPIRE_DAYS` | `90` | Lease time in days |
|
||||
| `DATABASE` | `sqlite:///db.sqlite` | See [official SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html) |
|
||||
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) |
|
||||
| `CORS_ORIGINS` | `https://{DLS_URL}` | Sets `Access-Control-Allow-Origin` header (comma separated string) \* |
|
||||
| `SITE_KEY_XID` | `00000000-0000-0000-0000-000000000000` | Site identification uuid |
|
||||
| `INSTANCE_REF` | `00000000-0000-0000-0000-000000000000` | Instance identification uuid |
|
||||
| `INSTANCE_KEY_RSA` | `<app-dir>/cert/instance.private.pem` | Site-wide private RSA key for singing JWTs |
|
||||
| `INSTANCE_KEY_PUB` | `<app-dir>/cert/instance.public.pem` | Site-wide public key |
|
||||
|
||||
\* Always use `https`, since guest-drivers only support secure connections!
|
||||
|
||||
# Setup (Client)
|
||||
|
||||
**The token file has to be copied! It's not enough to C&P file contents, because there can be special characters.**
|
||||
@ -316,6 +318,14 @@ nvidia-smi -q | grep "License"
|
||||
Download file and place it into `C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken`.
|
||||
Now restart `NvContainerLocalSystem` service.
|
||||
|
||||
**Power-Shell**
|
||||
|
||||
```Shell
|
||||
curl.exe --insecure -X GET https://<dls-hostname-or-ip>/client-token -o "C:\Program Files\NVIDIA Corporation\vGPU Licensing\ClientConfigToken\client_configuration_token_$($(Get-Date).tostring('dd-MM-yy-hh-mm-ss')).tok"
|
||||
Restart-Service NVDisplay.ContainerLocalSystem
|
||||
'C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe' -q | Select-String "License"
|
||||
```
|
||||
|
||||
# Troubleshoot
|
||||
|
||||
## Linux
|
||||
|
90
app/main.py
90
app/main.py
@ -40,8 +40,7 @@ INSTANCE_KEY_RSA = load_key(str(env('INSTANCE_KEY_RSA', join(dirname(__file__),
|
||||
INSTANCE_KEY_PUB = load_key(str(env('INSTANCE_KEY_PUB', join(dirname(__file__), 'cert/instance.public.pem'))))
|
||||
TOKEN_EXPIRE_DELTA = relativedelta(hours=1) # days=1
|
||||
LEASE_EXPIRE_DELTA = relativedelta(days=int(env('LEASE_EXPIRE_DAYS', 90)))
|
||||
|
||||
CORS_ORIGINS = env('CORS_ORIGINS').split(',') if (env('CORS_ORIGINS')) else f'https://{DLS_URL}' # todo: prevent static https
|
||||
CORS_ORIGINS = str(env('CORS_ORIGINS', '')).split(',') if (env('CORS_ORIGINS')) else [f'https://{DLS_URL}']
|
||||
|
||||
jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
||||
jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
||||
@ -51,29 +50,34 @@ app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=CORS_ORIGINS,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
allow_methods=['*'],
|
||||
allow_headers=['*'],
|
||||
)
|
||||
|
||||
logger.setLevel(logging.DEBUG if DEBUG else logging.INFO)
|
||||
|
||||
|
||||
def get_token(request: Request) -> dict:
|
||||
authorization_header = request.headers['authorization']
|
||||
def __get_token(request: Request) -> dict:
|
||||
authorization_header = request.headers.get('authorization')
|
||||
token = authorization_header.split(' ')[1]
|
||||
return jwt.decode(token=token, key=jwt_decode_key, algorithms=ALGORITHMS.RS256, options={'verify_aud': False})
|
||||
|
||||
|
||||
@app.get('/', summary='* Index')
|
||||
@app.get('/', summary='Index')
|
||||
async def index():
|
||||
return RedirectResponse('/-/readme')
|
||||
|
||||
|
||||
@app.get('/status', summary='* Status', description='Returns current service status, version (incl. git-commit) and some variables.', deprecated=True)
|
||||
@app.get('/status', summary='* Status', description='returns current service status, version (incl. git-commit) and some variables.', deprecated=True)
|
||||
async def status(request: Request):
|
||||
return JSONResponse({'status': 'up', 'version': VERSION, 'commit': COMMIT, 'debug': DEBUG})
|
||||
|
||||
|
||||
@app.get('/-/', summary='* Index')
|
||||
async def _index():
|
||||
return RedirectResponse('/-/readme')
|
||||
|
||||
|
||||
@app.get('/-/health', summary='* Health')
|
||||
async def _health(request: Request):
|
||||
return JSONResponse({'status': 'up', 'version': VERSION, 'commit': COMMIT, 'debug': DEBUG})
|
||||
@ -161,8 +165,8 @@ async def _lease_delete(request: Request, lease_ref: str):
|
||||
|
||||
|
||||
# venv/lib/python3.9/site-packages/nls_core_service_instance/service_instance_token_manager.py
|
||||
@app.get('/client-token', summary='* Client-Token')
|
||||
async def client_token():
|
||||
@app.get('/-/client-token', summary='* Client-Token', description='creates a new messenger token for this service instance')
|
||||
async def _client_token():
|
||||
cur_time = datetime.utcnow()
|
||||
exp_time = cur_time + relativedelta(years=12)
|
||||
|
||||
@ -200,15 +204,20 @@ async def client_token():
|
||||
content = jws.sign(payload, key=jwt_encode_key, headers=None, algorithm=ALGORITHMS.RS256)
|
||||
|
||||
response = StreamingResponse(iter([content]), media_type="text/plain")
|
||||
filename = f'client_configuration_token_{datetime.now().strftime("%d-%m-%y-%H-%M-%S")}'
|
||||
filename = f'client_configuration_token_{datetime.now().strftime("%d-%m-%y-%H-%M-%S")}.tok'
|
||||
response.headers["Content-Disposition"] = f'attachment; filename={filename}'
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@app.get('/client-token', summary='* Client-Token', description='creates a new messenger token for this service instance', deprecated=True)
|
||||
async def client_token():
|
||||
return RedirectResponse('/-/client-token')
|
||||
|
||||
|
||||
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py
|
||||
# {"candidate_origin_ref":"00112233-4455-6677-8899-aabbccddeeff","environment":{"fingerprint":{"mac_address_list":["ff:ff:ff:ff:ff:ff"]},"hostname":"my-hostname","ip_address_list":["192.168.178.123","fe80::","fe80::1%enp6s18"],"guest_driver_version":"510.85.02","os_platform":"Debian GNU/Linux 11 (bullseye) 11","os_version":"11 (bullseye)"},"registration_pending":false,"update_pending":false}
|
||||
@app.post('/auth/v1/origin')
|
||||
@app.post('/auth/v1/origin', description='find or create an origin')
|
||||
async def auth_v1_origin(request: Request):
|
||||
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow()
|
||||
|
||||
@ -239,7 +248,7 @@ async def auth_v1_origin(request: Request):
|
||||
|
||||
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_origins_controller.py
|
||||
# { "environment" : { "guest_driver_version" : "guest_driver_version", "hostname" : "myhost", "ip_address_list" : [ "192.168.1.129" ], "os_version" : "os_version", "os_platform" : "os_platform", "fingerprint" : { "mac_address_list" : [ "e4:b9:7a:e5:7b:ff" ] }, "host_driver_version" : "host_driver_version" }, "origin_ref" : "00112233-4455-6677-8899-aabbccddeeff" }
|
||||
@app.post('/auth/v1/origin/update')
|
||||
@app.post('/auth/v1/origin/update', description='update an origin evidence')
|
||||
async def auth_v1_origin_update(request: Request):
|
||||
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow()
|
||||
|
||||
@ -267,7 +276,7 @@ async def auth_v1_origin_update(request: Request):
|
||||
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_auth_controller.py
|
||||
# venv/lib/python3.9/site-packages/nls_core_auth/auth.py - CodeResponse
|
||||
# {"code_challenge":"...","origin_ref":"00112233-4455-6677-8899-aabbccddeeff"}
|
||||
@app.post('/auth/v1/code')
|
||||
@app.post('/auth/v1/code', description='get an authorization code')
|
||||
async def auth_v1_code(request: Request):
|
||||
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow()
|
||||
|
||||
@ -300,7 +309,7 @@ async def auth_v1_code(request: Request):
|
||||
# venv/lib/python3.9/site-packages/nls_services_auth/test/test_auth_controller.py
|
||||
# venv/lib/python3.9/site-packages/nls_core_auth/auth.py - TokenResponse
|
||||
# {"auth_code":"...","code_verifier":"..."}
|
||||
@app.post('/auth/v1/token')
|
||||
@app.post('/auth/v1/token', description='exchange auth code and verifier for token')
|
||||
async def auth_v1_token(request: Request):
|
||||
j, cur_time = json.loads((await request.body()).decode('utf-8')), datetime.utcnow()
|
||||
payload = jwt.decode(token=j['auth_code'], key=jwt_decode_key)
|
||||
@ -337,11 +346,11 @@ async def auth_v1_token(request: Request):
|
||||
|
||||
|
||||
# {'fulfillment_context': {'fulfillment_class_ref_list': []}, 'lease_proposal_list': [{'license_type_qualifiers': {'count': 1}, 'product': {'name': 'NVIDIA RTX Virtual Workstation'}}], 'proposal_evaluation_mode': 'ALL_OF', 'scope_ref_list': ['00112233-4455-6677-8899-aabbccddeeff']}
|
||||
@app.post('/leasing/v1/lessor')
|
||||
@app.post('/leasing/v1/lessor', description='request multiple leases (borrow) for current origin')
|
||||
async def leasing_v1_lessor(request: Request):
|
||||
j, token, cur_time = json.loads((await request.body()).decode('utf-8')), get_token(request), datetime.utcnow()
|
||||
j, token, cur_time = json.loads((await request.body()).decode('utf-8')), __get_token(request), datetime.utcnow()
|
||||
|
||||
origin_ref = token['origin_ref']
|
||||
origin_ref = token.get('origin_ref')
|
||||
scope_ref_list = j['scope_ref_list']
|
||||
logging.info(f'> [ create ]: {origin_ref}: create leases for scope_ref_list {scope_ref_list}')
|
||||
|
||||
@ -377,11 +386,11 @@ async def leasing_v1_lessor(request: Request):
|
||||
|
||||
# venv/lib/python3.9/site-packages/nls_services_lease/test/test_lease_multi_controller.py
|
||||
# venv/lib/python3.9/site-packages/nls_dal_service_instance_dls/schema/service_instance/V1_0_21__product_mapping.sql
|
||||
@app.get('/leasing/v1/lessor/leases')
|
||||
@app.get('/leasing/v1/lessor/leases', description='get active leases for current origin')
|
||||
async def leasing_v1_lessor_lease(request: Request):
|
||||
token, cur_time = get_token(request), datetime.utcnow()
|
||||
token, cur_time = __get_token(request), datetime.utcnow()
|
||||
|
||||
origin_ref = token['origin_ref']
|
||||
origin_ref = token.get('origin_ref')
|
||||
|
||||
active_lease_list = list(map(lambda x: x.lease_ref, Lease.find_by_origin_ref(db, origin_ref)))
|
||||
logging.info(f'> [ leases ]: {origin_ref}: found {len(active_lease_list)} active leases')
|
||||
@ -396,11 +405,11 @@ async def leasing_v1_lessor_lease(request: Request):
|
||||
|
||||
|
||||
# venv/lib/python3.9/site-packages/nls_core_lease/lease_single.py
|
||||
@app.put('/leasing/v1/lease/{lease_ref}')
|
||||
@app.put('/leasing/v1/lease/{lease_ref}', description='renew a lease')
|
||||
async def leasing_v1_lease_renew(request: Request, lease_ref: str):
|
||||
token, cur_time = get_token(request), datetime.utcnow()
|
||||
token, cur_time = __get_token(request), datetime.utcnow()
|
||||
|
||||
origin_ref = token['origin_ref']
|
||||
origin_ref = token.get('origin_ref')
|
||||
logging.info(f'> [ renew ]: {origin_ref}: renew {lease_ref}')
|
||||
|
||||
entity = Lease.find_by_origin_ref_and_lease_ref(db, origin_ref, lease_ref)
|
||||
@ -422,11 +431,36 @@ async def leasing_v1_lease_renew(request: Request, lease_ref: str):
|
||||
return JSONResponse(response)
|
||||
|
||||
|
||||
@app.delete('/leasing/v1/lessor/leases')
|
||||
async def leasing_v1_lessor_lease_remove(request: Request):
|
||||
token, cur_time = get_token(request), datetime.utcnow()
|
||||
@app.delete('/leasing/v1/lease/{lease_ref}', description='release (return) a lease')
|
||||
async def leasing_v1_lease_delete(request: Request, lease_ref: str):
|
||||
token, cur_time = __get_token(request), datetime.utcnow()
|
||||
|
||||
origin_ref = token['origin_ref']
|
||||
origin_ref = token.get('origin_ref')
|
||||
logging.info(f'> [ return ]: {origin_ref}: return {lease_ref}')
|
||||
|
||||
entity = Lease.find_by_lease_ref(db, lease_ref)
|
||||
if entity.origin_ref != origin_ref:
|
||||
raise HTTPException(status_code=403, detail='access or operation forbidden')
|
||||
if entity is None:
|
||||
raise HTTPException(status_code=404, detail='requested lease not available')
|
||||
|
||||
if Lease.delete(db, lease_ref) == 0:
|
||||
raise HTTPException(status_code=404, detail='lease not found')
|
||||
|
||||
response = {
|
||||
"lease_ref": lease_ref,
|
||||
"prompts": None,
|
||||
"sync_timestamp": cur_time.isoformat(),
|
||||
}
|
||||
|
||||
return JSONResponse(response)
|
||||
|
||||
|
||||
@app.delete('/leasing/v1/lessor/leases', description='release all leases')
|
||||
async def leasing_v1_lessor_lease_remove(request: Request):
|
||||
token, cur_time = __get_token(request), datetime.utcnow()
|
||||
|
||||
origin_ref = token.get('origin_ref')
|
||||
|
||||
released_lease_list = list(map(lambda x: x.lease_ref, Lease.find_by_origin_ref(db, origin_ref)))
|
||||
deletions = Lease.cleanup(db, origin_ref)
|
||||
|
@ -115,6 +115,13 @@ class Lease(Base):
|
||||
session.close()
|
||||
return entities
|
||||
|
||||
@staticmethod
|
||||
def find_by_lease_ref(engine: Engine, lease_ref: str) -> "Lease":
|
||||
session = sessionmaker(bind=engine)()
|
||||
entity = session.query(Lease).filter(Lease.lease_ref == lease_ref).first()
|
||||
session.close()
|
||||
return entity
|
||||
|
||||
@staticmethod
|
||||
def find_by_origin_ref_and_lease_ref(engine: Engine, origin_ref: str, lease_ref: str) -> "Lease":
|
||||
session = sessionmaker(bind=engine)()
|
||||
@ -125,7 +132,7 @@ class Lease(Base):
|
||||
@staticmethod
|
||||
def renew(engine: Engine, lease: "Lease", lease_expires: datetime.datetime, lease_updated: datetime.datetime):
|
||||
session = sessionmaker(bind=engine)()
|
||||
x = dict(lease_expires=lease.lease_expires, lease_updated=lease.lease_updated)
|
||||
x = dict(lease_expires=lease_expires, lease_updated=lease_updated)
|
||||
session.execute(update(Lease).where(and_(Lease.origin_ref == lease.origin_ref, Lease.lease_ref == lease.lease_ref)).values(**x))
|
||||
session.commit()
|
||||
session.close()
|
||||
|
29
app/util.py
29
app/util.py
@ -1,21 +1,28 @@
|
||||
try:
|
||||
# Crypto | Cryptodome on Debian
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.PublicKey.RSA import RsaKey
|
||||
except ModuleNotFoundError:
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.PublicKey.RSA import RsaKey
|
||||
|
||||
|
||||
def load_file(filename) -> bytes:
|
||||
with open(filename, 'rb') as file:
|
||||
content = file.read()
|
||||
return content
|
||||
|
||||
|
||||
def load_key(filename) -> RsaKey:
|
||||
def load_key(filename) -> "RsaKey":
|
||||
try:
|
||||
# Crypto | Cryptodome on Debian
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.PublicKey.RSA import RsaKey
|
||||
except ModuleNotFoundError:
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.PublicKey.RSA import RsaKey
|
||||
|
||||
return RSA.import_key(extern_key=load_file(filename), passphrase=None)
|
||||
|
||||
|
||||
def generate_key() -> RsaKey:
|
||||
def generate_key() -> "RsaKey":
|
||||
try:
|
||||
# Crypto | Cryptodome on Debian
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.PublicKey.RSA import RsaKey
|
||||
except ModuleNotFoundError:
|
||||
from Cryptodome.PublicKey import RSA
|
||||
from Cryptodome.PublicKey.RSA import RsaKey
|
||||
|
||||
return RSA.generate(bits=2048)
|
||||
|
38
test/main.py
38
test/main.py
@ -16,7 +16,7 @@ sys.path.append('../')
|
||||
sys.path.append('../app')
|
||||
|
||||
from app import main
|
||||
from app.util import generate_key, load_key
|
||||
from app.util import load_key
|
||||
|
||||
client = TestClient(main.app)
|
||||
|
||||
@ -33,6 +33,12 @@ jwt_encode_key = jwk.construct(INSTANCE_KEY_RSA.export_key().decode('utf-8'), al
|
||||
jwt_decode_key = jwk.construct(INSTANCE_KEY_PUB.export_key().decode('utf-8'), algorithm=ALGORITHMS.RS256)
|
||||
|
||||
|
||||
def __bearer_token(origin_ref: str) -> str:
|
||||
token = jwt.encode({"origin_ref": origin_ref}, key=jwt_encode_key, algorithm=ALGORITHMS.RS256)
|
||||
token = f'Bearer {token}'
|
||||
return token
|
||||
|
||||
|
||||
def test_index():
|
||||
response = client.get('/')
|
||||
assert response.status_code == 200
|
||||
@ -61,6 +67,11 @@ def test_manage():
|
||||
|
||||
|
||||
def test_client_token():
|
||||
response = client.get('/-/client-token')
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_client_token_deprecated():
|
||||
response = client.get('/client-token')
|
||||
assert response.status_code == 200
|
||||
|
||||
@ -175,9 +186,7 @@ def test_leasing_v1_lessor():
|
||||
'scope_ref_list': [LEASE_REF]
|
||||
}
|
||||
|
||||
bearer_token = jwt.encode({"origin_ref": ORIGIN_REF}, key=jwt_encode_key, algorithm=ALGORITHMS.RS256)
|
||||
bearer_token = f'Bearer {bearer_token}'
|
||||
response = client.post('/leasing/v1/lessor', json=payload, headers={'authorization': bearer_token})
|
||||
response = client.post('/leasing/v1/lessor', json=payload, headers={'authorization': __bearer_token(ORIGIN_REF)})
|
||||
assert response.status_code == 200
|
||||
|
||||
lease_result_list = response.json()['lease_result_list']
|
||||
@ -186,9 +195,7 @@ def test_leasing_v1_lessor():
|
||||
|
||||
|
||||
def test_leasing_v1_lessor_lease():
|
||||
bearer_token = jwt.encode({"origin_ref": ORIGIN_REF}, key=jwt_encode_key, algorithm=ALGORITHMS.RS256)
|
||||
bearer_token = f'Bearer {bearer_token}'
|
||||
response = client.get('/leasing/v1/lessor/leases', headers={'authorization': bearer_token})
|
||||
response = client.get('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)})
|
||||
assert response.status_code == 200
|
||||
|
||||
active_lease_list = response.json()['active_lease_list']
|
||||
@ -197,18 +204,23 @@ def test_leasing_v1_lessor_lease():
|
||||
|
||||
|
||||
def test_leasing_v1_lease_renew():
|
||||
bearer_token = jwt.encode({"origin_ref": ORIGIN_REF}, key=jwt_encode_key, algorithm=ALGORITHMS.RS256)
|
||||
bearer_token = f'Bearer {bearer_token}'
|
||||
response = client.put(f'/leasing/v1/lease/{LEASE_REF}', headers={'authorization': bearer_token})
|
||||
response = client.put(f'/leasing/v1/lease/{LEASE_REF}', headers={'authorization': __bearer_token(ORIGIN_REF)})
|
||||
assert response.status_code == 200
|
||||
|
||||
assert response.json()['lease_ref'] == LEASE_REF
|
||||
|
||||
|
||||
def test_leasing_v1_lease_delete():
|
||||
response = client.delete(f'/leasing/v1/lease/{LEASE_REF}', headers={'authorization': __bearer_token(ORIGIN_REF)})
|
||||
assert response.status_code == 200
|
||||
|
||||
assert response.json()['lease_ref'] == LEASE_REF
|
||||
|
||||
|
||||
def test_leasing_v1_lessor_lease_remove():
|
||||
bearer_token = jwt.encode({"origin_ref": ORIGIN_REF}, key=jwt_encode_key, algorithm=ALGORITHMS.RS256)
|
||||
bearer_token = f'Bearer {bearer_token}'
|
||||
response = client.delete('/leasing/v1/lessor/leases', headers={'authorization': bearer_token})
|
||||
test_leasing_v1_lessor()
|
||||
|
||||
response = client.delete('/leasing/v1/lessor/leases', headers={'authorization': __bearer_token(ORIGIN_REF)})
|
||||
assert response.status_code == 200
|
||||
|
||||
released_lease_list = response.json()['released_lease_list']
|
||||
|
@ -1 +1 @@
|
||||
VERSION=1.1
|
||||
VERSION=1.2
|
||||
|
Loading…
Reference in New Issue
Block a user