From 8a77ca637739766655b1d3be0e7d7ddedaa26eab Mon Sep 17 00:00:00 2001 From: Lukas Garberg Date: Wed, 14 Aug 2024 21:59:51 +0200 Subject: [PATCH 1/3] Replaced flask-restful with flask-restx Replaced flask-restful with flask-restx as the former seems abandoned. --- nipap/nipap/rest.py | 34 +++++++++++++++++++++------------- nipap/requirements.txt | 8 ++++---- tests/test_rest.py | 2 ++ 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/nipap/nipap/rest.py b/nipap/nipap/rest.py index 0f3593cd3..d763b6908 100644 --- a/nipap/nipap/rest.py +++ b/nipap/nipap/rest.py @@ -7,22 +7,22 @@ import datetime import logging -import time import pytz -import json from functools import wraps -from flask import Flask, request, Response, got_request_exception, jsonify -from flask_restful import Resource, Api, abort +from flask import request, Response, jsonify +from flask_restx import Resource, Api, Namespace, abort from .backend import Nipap, NipapError, prefix_search_options_spec -import nipap from .authlib import AuthFactory, AuthError from .tracing import create_span_rest +logger = logging.getLogger(__name__) + +prefix_ns = Namespace(name="prefixes", description="Prefix operations", validate=True) def setup(app): api = Api(app, prefix="/rest/v1") - api.add_resource(NipapPrefixRest, "/prefixes") + api.add_namespace(prefix_ns, path="/prefixes") return app @@ -34,7 +34,10 @@ def combine_request_args(): request_nipap_username = request.headers.get('NIPAP-Username') request_nipap_fullname = request.headers.get('NIPAP-Full-Name') - request_body = request.json + if request.method in ("POST", "PUT"): + request_body = request.json + else: + request_body = None request_queries = request.args.to_dict() if request_authoritative_source: @@ -112,6 +115,7 @@ def requires_auth(f): def decorated(self, *args, **kwargs): """ """ + # small hack args = args + (combine_request_args(),) @@ -126,7 +130,7 @@ def decorated(self, *args, **kwargs): self.logger.debug("Malformed request: got %d parameters" % len(args)) abort(401, error={"code": 401, "message": "Malformed request: got %d parameters" % len(args)}) - if type(nipap_args) != dict: + if type(nipap_args) is not dict: self.logger.debug("Function argument is not struct") abort(401, error={"code": 401, "message": "Function argument is not struct"}) @@ -153,7 +157,8 @@ def decorated(self, *args, **kwargs): if auth_header and auth_header.startswith("Bearer"): bearer_token = auth_header.split(" ")[1] if not bearer_token: - return authenticate() + logger.info("Authentication failed, missing auth method") + abort(authenticate()) # init AuthFacory() af = AuthFactory() @@ -164,7 +169,6 @@ def decorated(self, *args, **kwargs): # authenticated? if not auth.authenticate(): - self.logger.debug("Invalid bearer token") abort(401, error={"code": 401, "message": "Invalid bearer token"}) else: @@ -173,7 +177,6 @@ def decorated(self, *args, **kwargs): # authenticated? if not auth.authenticate(): - self.logger.debug("Incorrect username or password.") abort(401, error={"code": 401, "message": "Incorrect username or password"}) # Replace auth options in API call arguments with auth object @@ -207,9 +210,12 @@ def get_query_for_field(field, search_value): } -class NipapPrefixRest(Resource): +@prefix_ns.route("") +class NipapPrefix(Resource): + + def __init__(self, *args, **kwargs): + super().__init__(self, *args, **kwargs) - def __init__(self): self.nip = Nipap() self.logger = logging.getLogger(self.__class__.__name__) @@ -273,6 +279,7 @@ def post(self, args): self.logger.error(str(err)) abort(500, error={"code": 500, "message": "Internal error"}) + @requires_auth @create_span_rest def put(self, args): @@ -293,6 +300,7 @@ def put(self, args): self.logger.error(str(err)) abort(500, error={"code": 500, "message": "Internal error"}) + @requires_auth @create_span_rest def delete(self, args): diff --git a/nipap/requirements.txt b/nipap/requirements.txt index 9b4c79a96..c0e590664 100644 --- a/nipap/requirements.txt +++ b/nipap/requirements.txt @@ -1,14 +1,14 @@ zipp==3.21.0 importlib_metadata==8.5.0 -Flask==2.1.3 -Flask-Compress==1.9.0 +Flask==3.0.3 +Flask-Compress==1.17 flask-xml-rpc-re==0.1.4 -Flask-RESTful==0.3.10 +flask-restx==1.3.0 requests==2.32.3 IPy==1.01 Jinja2==3.1.4 MarkupSafe==3.0.2 -Werkzeug==2.0.3 +Werkzeug==3.1.3 backports.ssl-match-hostname==3.7.0.1 certifi==2024.12.14 itsdangerous==2.2.0 diff --git a/tests/test_rest.py b/tests/test_rest.py index 2c796c38a..f7b3b0164 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -179,6 +179,8 @@ def _convert_list_of_unicode_to_str(self, list_of_items): def _add_prefix(self, attr): request = requests.post(self.server_url, headers=self.headers, json = attr) + self.assertEqual(request.status_code, 200, + msg=f"Result status code {request.status_code} != 200, response: {request.text}") text = request.text result = json.loads(text) result = dict([(str(k), str(v)) for k, v in list(result.items())]) From e466e54201a530deaf133137a05869d563834f29 Mon Sep 17 00:00:00 2001 From: Lukas Garberg Date: Wed, 15 Jan 2025 10:49:26 +0100 Subject: [PATCH 2/3] nipap: Add dependency to flask-restx --- nipap/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipap/debian/control b/nipap/debian/control index d1bdf2322..73394ed5d 100644 --- a/nipap/debian/control +++ b/nipap/debian/control @@ -17,7 +17,7 @@ Description: Neat IP Address Planner Package: nipapd Architecture: all -Depends: debconf, nipap-common, python3 (>= 3.6), ${misc:Depends}, python3-psycopg2, python3-flask, python3-flask-xml-rpc-re, python3-flask-restful, python3-flask-compress, python3-tornado, python3-parsedatetime, python3-tz, python3-dateutil, python3-psutil, python3-pyparsing, python3-jwt, python3-requests +Depends: debconf, nipap-common, python3 (>= 3.6), ${misc:Depends}, python3-psycopg2, python3-flask, python3-flask-xml-rpc-re, python3-flask-restx, python3-flask-compress, python3-tornado, python3-parsedatetime, python3-tz, python3-dateutil, python3-psutil, python3-pyparsing, python3-jwt, python3-requests Description: Neat IP Address Planner XML-RPC daemon The Neat IP Address Planner, NIPAP, is a system built for efficiently managing large amounts of IP addresses. This is the XML-RPC daemon. From 677978dfa436041cb58630f707e0a67f901c486b Mon Sep 17 00:00:00 2001 From: Lukas Garberg Date: Wed, 15 Jan 2025 11:21:41 +0100 Subject: [PATCH 3/3] www: Bump Flask dep ver --- nipap-www/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipap-www/requirements.txt b/nipap-www/requirements.txt index b36bdbb8a..da9a7ff34 100644 --- a/nipap-www/requirements.txt +++ b/nipap-www/requirements.txt @@ -1,4 +1,4 @@ -Flask==2.1.3 +Flask==3.0.3 Jinja2==3.1.4 pynipap nipap