From e1c2c17cf6ecf84dfd00d13fb87f696f82a8865f Mon Sep 17 00:00:00 2001 From: Brice Gros Date: Fri, 10 Jan 2020 10:14:52 +0100 Subject: [PATCH 01/15] add http_user field to Host table --- .gitignore | 1 + .vscode/settings.json | 3 + CHANGES.rst | 5 + Pipfile | 27 + Pipfile.lock | 469 ++++++++++++++++++ src/nsupdate/api/views.py | 24 +- .../main/migrations/0013_host_http_user.py | 19 + src/nsupdate/main/models.py | 28 ++ .../includes/tabbed_router_configuration.html | 50 +- 9 files changed, 588 insertions(+), 38 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 src/nsupdate/main/migrations/0013_host_http_user.py diff --git a/.gitignore b/.gitignore index d0abbdd3..be6e9ad1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.venv *.log *.pot *.pyc diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..fa1b4623 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": ".venv\\Scripts\\python.exe" +} \ No newline at end of file diff --git a/CHANGES.rst b/CHANGES.rst index 45c1c8be..bbd5700e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,11 @@ AFTER that, you can upgrade to 0.10.x or any later version (and then run the migrations for that version). For upgrading and migration help, please see the docs that match the version you are upgrading to. +Release 0.13.0-alternative +--------------------------------- + +New Features: + - use a http user different from the fqdn of the host due to limitation in the length of the username from some routers Release 0.13.0 (not released yet) --------------------------------- diff --git a/Pipfile b/Pipfile new file mode 100644 index 00000000..e9c85129 --- /dev/null +++ b/Pipfile @@ -0,0 +1,27 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +dnspython = "*" +netaddr = "*" +django-bootstrap-form = "*" +django-referrer-policy = "*" +django-registration-redux = "*" +django-extensions = "*" +social-auth-app-django = "*" +requests = "*" +setuptools-scm = "*" +django-debug-toolbar = "*" +pytest = ">=3.6" +pytest-django = "*" +pytest-pep8 = "*" +Django = "~=2.2.0" +Sphinx = "*" +nsupdate = {editable = true,path = "."} + +[requires] +python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 00000000..2d3f0018 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,469 @@ +{ + "_meta": { + "hash": { + "sha256": "a1ae78750069722a3b9c6fbdf90f93b55273610657eac2b7abe5ef927b536869" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "alabaster": { + "hashes": [ + "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", + "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + ], + "version": "==0.7.12" + }, + "apipkg": { + "hashes": [ + "sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6", + "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c" + ], + "version": "==1.5" + }, + "atomicwrites": { + "hashes": [ + "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", + "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" + ], + "markers": "sys_platform == 'win32'", + "version": "==1.3.0" + }, + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "version": "==19.3.0" + }, + "babel": { + "hashes": [ + "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38", + "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4" + ], + "version": "==2.8.0" + }, + "certifi": { + "hashes": [ + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + ], + "version": "==2019.11.28" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "colorama": { + "hashes": [ + "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", + "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.3" + }, + "defusedxml": { + "hashes": [ + "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", + "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5" + ], + "markers": "python_version >= '3.0'", + "version": "==0.6.0" + }, + "django": { + "hashes": [ + "sha256:662a1ff78792e3fd77f16f71b1f31149489434de4b62a74895bd5d6534e635a5", + "sha256:687c37153486cf26c3fdcbdd177ef16de38dc3463f094b5f9c9955d91f277b14" + ], + "index": "pypi", + "version": "==2.2.9" + }, + "django-bootstrap-form": { + "hashes": [ + "sha256:de3f7893e515352834d446c441c0cb861637f92cebbe59d8229469c6cd3dc640" + ], + "index": "pypi", + "version": "==3.4" + }, + "django-debug-toolbar": { + "hashes": [ + "sha256:24c157bc6c0e1648e0a6587511ecb1b007a00a354ce716950bff2de12693e7a8", + "sha256:77cfba1d6e91b9bc3d36dc7dc74a9bb80be351948db5f880f2562a0cbf20b6c5" + ], + "index": "pypi", + "version": "==2.1" + }, + "django-extensions": { + "hashes": [ + "sha256:a9db7c56a556d244184f589f2437b4228de86ee45e5ebb837fb20c6d54e95ea5", + "sha256:b58320d3fe3d6ae7d1d8e38959713fa92272f4921e662d689058d942a5b444f7" + ], + "index": "pypi", + "version": "==2.2.5" + }, + "django-referrer-policy": { + "hashes": [ + "sha256:09e134324fa08c10efc12244a4bae7aee5defa7d332b92c603b09258c854615a" + ], + "index": "pypi", + "version": "==1.0" + }, + "django-registration-redux": { + "hashes": [ + "sha256:1aaf08c9c16b7f185ffa36e7251c7a6149fe953f5af21c4f1e01cbe03902520b", + "sha256:5998a8dbee2a84d66cd56a61c4fb6b1a5be801b083fb1ef53ba04939d8a44606" + ], + "index": "pypi", + "version": "==2.7" + }, + "dnspython": { + "hashes": [ + "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01", + "sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d" + ], + "index": "pypi", + "version": "==1.16.0" + }, + "docutils": { + "hashes": [ + "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0", + "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827", + "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99" + ], + "version": "==0.15.2" + }, + "execnet": { + "hashes": [ + "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50", + "sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547" + ], + "version": "==1.7.1" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "version": "==2.8" + }, + "imagesize": { + "hashes": [ + "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1", + "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1" + ], + "version": "==1.2.0" + }, + "importlib-metadata": { + "hashes": [ + "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", + "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f" + ], + "markers": "python_version < '3.8'", + "version": "==1.3.0" + }, + "jinja2": { + "hashes": [ + "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f", + "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de" + ], + "version": "==2.10.3" + }, + "markupsafe": { + "hashes": [ + "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", + "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", + "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", + "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", + "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", + "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", + "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", + "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", + "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", + "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", + "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", + "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", + "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", + "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", + "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", + "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", + "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", + "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", + "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", + "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", + "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", + "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", + "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", + "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", + "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", + "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", + "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", + "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" + ], + "version": "==1.1.1" + }, + "more-itertools": { + "hashes": [ + "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", + "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" + ], + "version": "==8.0.2" + }, + "netaddr": { + "hashes": [ + "sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd", + "sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca" + ], + "index": "pypi", + "version": "==0.7.19" + }, + "nsupdate": { + "editable": true, + "path": "." + }, + "oauthlib": { + "hashes": [ + "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889", + "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea" + ], + "version": "==3.1.0" + }, + "packaging": { + "hashes": [ + "sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb", + "sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8" + ], + "version": "==20.0" + }, + "pep8": { + "hashes": [ + "sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee", + "sha256:fe249b52e20498e59e0b5c5256aa52ee99fc295b26ec9eaa85776ffdb9fe6374" + ], + "version": "==1.7.1" + }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "version": "==0.13.1" + }, + "py": { + "hashes": [ + "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", + "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" + ], + "version": "==1.8.1" + }, + "pygments": { + "hashes": [ + "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b", + "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe" + ], + "version": "==2.5.2" + }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "version": "==1.7.1" + }, + "pyparsing": { + "hashes": [ + "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", + "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" + ], + "version": "==2.4.6" + }, + "pytest": { + "hashes": [ + "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa", + "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4" + ], + "index": "pypi", + "version": "==5.3.2" + }, + "pytest-cache": { + "hashes": [ + "sha256:be7468edd4d3d83f1e844959fd6e3fd28e77a481440a7118d430130ea31b07a9" + ], + "version": "==1.0" + }, + "pytest-django": { + "hashes": [ + "sha256:17592f06d51c2ef4b7a0fb24aa32c8b6998506a03c8439606cb96db160106659", + "sha256:ef3d15b35ed7e46293475e6f282e71a53bcd8c6f87bdc5d5e7ad0f4d49352127" + ], + "index": "pypi", + "version": "==3.7.0" + }, + "pytest-pep8": { + "hashes": [ + "sha256:032ef7e5fa3ac30f4458c73e05bb67b0f036a8a5cb418a534b3170f89f120318" + ], + "index": "pypi", + "version": "==1.0.6" + }, + "python3-openid": { + "hashes": [ + "sha256:0086da6b6ef3161cfe50fb1ee5cceaf2cda1700019fda03c2c5c440ca6abe4fa", + "sha256:628d365d687e12da12d02c6691170f4451db28d6d68d050007e4a40065868502" + ], + "markers": "python_version >= '3.0'", + "version": "==3.1.0" + }, + "pytz": { + "hashes": [ + "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", + "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be" + ], + "version": "==2019.3" + }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "index": "pypi", + "version": "==2.22.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d", + "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a" + ], + "version": "==1.3.0" + }, + "setuptools-scm": { + "hashes": [ + "sha256:1f11cb2eea431346d46589c2dafcafe2e7dc1c7b2c70bc4c3752d2048ad5c148", + "sha256:bd25e1fb5e4d603dcf490f1fde40fb4c595b357795674c3e5cb7f6217ab39ea5" + ], + "index": "pypi", + "version": "==3.3.3" + }, + "six": { + "hashes": [ + "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", + "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + ], + "version": "==1.13.0" + }, + "snowballstemmer": { + "hashes": [ + "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", + "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" + ], + "version": "==2.0.0" + }, + "social-auth-app-django": { + "hashes": [ + "sha256:6d0dd18c2d9e71ca545097d57b44d26f59e624a12833078e8e52f91baf849778", + "sha256:9237e3d7b6f6f59494c3b02e0cce6efc69c9d33ad9d1a064e3b2318bcbe89ae3", + "sha256:f151396e5b16e2eee12cd2e211004257826ece24fc4ae97a147df386c1cd7082" + ], + "index": "pypi", + "version": "==3.1.0" + }, + "social-auth-core": { + "hashes": [ + "sha256:47cd2458c8fefd02466b0c514643e02ad8b61d8b4b69f7573e80882e3a97b0f0", + "sha256:8320666548a532eb158968eda542bbe1863682357c432d8c4e28034a7f1e3b58", + "sha256:d81ed681e3c0722300b61a0792c5db5d21206793f95ca810f010c1cc931c8d89" + ], + "version": "==3.2.0" + }, + "sphinx": { + "hashes": [ + "sha256:298537cb3234578b2d954ff18c5608468229e116a9757af3b831c2b2b4819159", + "sha256:e6e766b74f85f37a5f3e0773a1e1be8db3fcb799deb58ca6d18b70b0b44542a5" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "sphinxcontrib-applehelp": { + "hashes": [ + "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", + "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d" + ], + "version": "==1.0.1" + }, + "sphinxcontrib-devhelp": { + "hashes": [ + "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", + "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981" + ], + "version": "==1.0.1" + }, + "sphinxcontrib-htmlhelp": { + "hashes": [ + "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422", + "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7" + ], + "version": "==1.0.2" + }, + "sphinxcontrib-jsmath": { + "hashes": [ + "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", + "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" + ], + "version": "==1.0.1" + }, + "sphinxcontrib-qthelp": { + "hashes": [ + "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20", + "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f" + ], + "version": "==1.0.2" + }, + "sphinxcontrib-serializinghtml": { + "hashes": [ + "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227", + "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768" + ], + "version": "==1.1.3" + }, + "sqlparse": { + "hashes": [ + "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", + "sha256:7c3dca29c022744e95b547e867cee89f4fce4373f3549ccd8797d8eb52cdb873" + ], + "version": "==0.3.0" + }, + "urllib3": { + "hashes": [ + "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", + "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" + ], + "version": "==1.25.7" + }, + "wcwidth": { + "hashes": [ + "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", + "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" + ], + "version": "==0.1.8" + }, + "zipp": { + "hashes": [ + "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", + "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" + ], + "version": "==0.6.0" + } + }, + "develop": {} +} diff --git a/src/nsupdate/api/views.py b/src/nsupdate/api/views.py index bd7cd6ec..c8f01b06 100644 --- a/src/nsupdate/api/views.py +++ b/src/nsupdate/api/views.py @@ -139,18 +139,18 @@ def check_api_auth(username, password, logger=None): """ Check username and password against our database. - :param username: http basic auth username (== fqdn) + :param username: http basic auth username :param password: update password :return: host object if authenticated, None otherwise. """ - fqdn = username try: - host = Host.get_by_fqdn(fqdn) + host = Host.get_by_http_user(username) except ValueError: # logging this at debug level because otherwise it fills our logs... - logger.debug('%s - received bad credentials (auth username == dyndns hostname not in our hosts DB)' % (fqdn, )) + logger.debug('%s - received bad credentials' % (username, )) return None if host is not None: + fqdn = host.get_fqdn() ok = check_password(password, host.update_secret) success_msg = ('failure', 'success')[ok] msg = "api authentication %s. [hostname: %s (given in basic auth)]" % (success_msg, fqdn, ) @@ -218,19 +218,17 @@ def get(self, request, logger=None, delete=False): logger.debug('%s - received no auth' % (hostname, )) return basic_challenge("authenticate to update DNS", 'badauth') username, password = basic_authenticate(auth) - if '.' not in username: # username MUST be the fqdn - # specifically point to configuration errors on client side - return Response('notfqdn') - if username in settings.BAD_HOSTS: - return Response('abuse', status=403) host = check_api_auth(username, password) if host is None: return basic_challenge("authenticate to update DNS", 'badauth') - logger.info("authenticated by update secret for host %s" % username) + fqdn = str(host.get_fqdn()) + if fqdn in settings.BAD_HOSTS: + return Response('abuse', status=403) + logger.info("authenticated by update secret for host %s" % fqdn) if hostname is None: # as we use update_username == hostname, we can fall back to that: - hostname = username - elif hostname != username: + hostname = fqdn + elif hostname != fqdn: if '.' not in hostname: # specifically point to configuration errors on client side result = 'notfqdn' @@ -238,7 +236,7 @@ def get(self, request, logger=None, delete=False): # maybe this host is owned by same person, but we can't know. result = 'nohost' # or 'badauth'? msg = ("rejecting to update wrong host %s (given in query string) " - "[instead of %s (given in basic auth)]" % (hostname, username)) + "[instead of %s (given in basic auth as user %s)]" % (hostname, fqdn, username)) logger.warning(msg) host.register_client_result(msg, fault=True) return Response(result) diff --git a/src/nsupdate/main/migrations/0013_host_http_user.py b/src/nsupdate/main/migrations/0013_host_http_user.py new file mode 100644 index 00000000..ba52bfbc --- /dev/null +++ b/src/nsupdate/main/migrations/0013_host_http_user.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.9 on 2020-01-10 08:53 + +from django.db import migrations, models +import nsupdate.main.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0012_auto_20191230_1729'), + ] + + operations = [ + migrations.AddField( + model_name='host', + name='http_user', + field=models.CharField(default=nsupdate.main.models._http_user_generator, max_length=30, unique=True, verbose_name='http user'), + ), + ] diff --git a/src/nsupdate/main/models.py b/src/nsupdate/main/models.py index 5cc69cae..5322ff78 100644 --- a/src/nsupdate/main/models.py +++ b/src/nsupdate/main/models.py @@ -5,6 +5,8 @@ import re import time import base64 +from datetime import datetime +import random import dns.resolver import dns.message @@ -153,6 +155,13 @@ class Meta: verbose_name_plural = _('domains') ordering = ('name',) +_HOST_HTTP_USER_MAX_LENGTH=30 # limit comes from an external application not accepting longer username +def _http_user_generator(): + dt = datetime.utcnow().strftime('%Y%m%d%H%m%S%f') + maxrange = pow(10, _HOST_HTTP_USER_MAX_LENGTH-len(dt)) + randvalue = random.randrange(0, maxrange) + return f'{randvalue}{dt}'.zfill(_HOST_HTTP_USER_MAX_LENGTH) + @python_2_unicode_compatible class Host(models.Model): @@ -168,6 +177,13 @@ class Host(models.Model): ], help_text=_("The name of your host.")) domain = models.ForeignKey(Domain, on_delete=models.CASCADE, verbose_name=_("domain")) + http_user = models.CharField( + _("http user"), + max_length=_HOST_HTTP_USER_MAX_LENGTH, # username used for http basic auth + unique=True, + null=False, + default=_http_user_generator + ) update_secret = models.CharField( _("update secret"), max_length=64, # secret gets hashed (on save) to salted sha1, 58 bytes str len @@ -267,6 +283,18 @@ class Meta(object): def get_fqdn(self): return dnstools.FQDN(self.name, self.domain.name) + @classmethod + def get_by_http_user(cls, username, **kwargs): + try: + host = Host.objects.get(http_user=username, **kwargs) + except Host.DoesNotExist: + return None + except Host.MultipleObjectsReturned: + # should not happen, see Host.http_user should have unique=True + raise ValueError("get_by_http_user(%s) found more than 1 host" % fqdn) + else: + return host + @classmethod def get_by_fqdn(cls, fqdn, **kwargs): # Assuming subdomain has no dots (.) the fqdn is split at the first dot diff --git a/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html b/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html index d6eb88b1..51f8fcbf 100644 --- a/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html +++ b/src/nsupdate/main/templates/main/includes/tabbed_router_configuration.html @@ -49,11 +49,11 @@

{% trans "General configuration hints" %}

{% trans "For IPv4 updates:" %}
- https://{{ host.get_fqdn|default:"<your fqdn>" }}:{{ update_secret|default:"<your secret>" }}@{{ WWW_IPV4_HOST }}/nic/update + https://{{ host.http_user|default:"<your fqdn>" }}:{{ update_secret|default:"<your secret>" }}@{{ WWW_IPV4_HOST }}/nic/update
{% trans "For IPv6 updates:" %}
- https://{{ host.get_fqdn|default:'<your fqdn>' }}:{{ update_secret|default:'<your secret>' }}@{{ WWW_IPV6_HOST }}/nic/update + https://{{ host.http_user|default:'<your fqdn>' }}:{{ update_secret|default:'<your secret>' }}@{{ WWW_IPV6_HOST }}/nic/update
{% blocktrans trimmed %} The IPs will be determined automatically using the remote address our service is seeing @@ -75,7 +75,7 @@

{% trans "General configuration hints" %}

  • {% trans "Do HTTP Basic Auth with:" %}
  • @@ -120,7 +120,7 @@
    {% trans "Enter the following data:" %}
    Dynamic DNS providerCustom Update-URLhttps://{{ WWW_IPV4_HOST }}/nic/update Domain Name{{ host.get_fqdn|default:"<your hostname>" }} - User name{{ host.get_fqdn|default:"<your hostname>" }} + User name{{ host.http_user|default:"<your http user>" }} Password{{ update_secret|default:"<your secret>" }}
    {% trans "If you have IPv4 and IPv6" %}
    @@ -146,7 +146,7 @@
    {% trans "Enter the following data:" %}
    SettingValue DDNS ServiceCustom DYNDNS Server{{ WWW_IPV4_HOST }} - Username{{ host.get_fqdn|default:"<your hostname>" }} + Username{{ host.http_user|default:"<your http user>" }} Password{{ update_secret|default:"<your secret>" }} Hostname{{ host.get_fqdn|default:"<your hostname>" }} URL/nic/update? @@ -168,7 +168,7 @@

    ddclient

    use=web, web=http://{{ WWW_IPV4_HOST }}/myip ssl=yes # yes = use https for updates server={{ WWW_IPV4_HOST }} -login={{ host.get_fqdn|default:"<your hostname>" }} +login={{ host.http_user|default:"<your http user>" }} password='{{ update_secret|default:"<your secret>" }}' {{ host.get_fqdn|default:"<your hostname>" }} @@ -181,7 +181,7 @@

    ddclient

    #usev6=if, if=eth0 #ssl=yes # yes = use https for updates #server={{ WWW_IPV6_HOST }} -#login={{ host.get_fqdn|default:"<your hostname>" }} +#login={{ host.http_user|default:"<your http user>" }} #password='{{ update_secret|default:"<your secret>" }}' #{{ host.get_fqdn|default:"<your hostname>" }} @@ -198,7 +198,7 @@

    dyndnsc

    # the detector dnswanip returns: use_preset = nsupdate.info:ipv4 updater-hostname = {{ host.get_fqdn|default:"<your hostname>" }} -updater-userid = {{ host.get_fqdn|default:"<your hostname>" }} +updater-userid = {{ host.http_user|default:"<your http user>" }} updater-password = {{ update_secret|default:"<your secret>" }} detector = webcheck4 @@ -207,7 +207,7 @@

    dyndnsc

    # the detector dnswanip returns: use_preset = nsupdate.info:ipv6 updater-hostname = {{ host.get_fqdn|default:"<your hostname>" }} -updater-userid = {{ host.get_fqdn|default:"<your hostname>" }} +updater-userid = {{ host.http_user|default:"<your http user>" }} updater-password = {{ update_secret|default:"<your secret>" }} detector = webcheck6 @@ -220,7 +220,7 @@

    EdgeOS (ddclient)

    interface pppoe0 { service custom-nsupdate { host-name {{ host.get_fqdn|default:"<your hostname>" }} - login {{ host.get_fqdn|default:"<your hostname>" }} + login {{ host.http_user|default:"<your http user>" }} password {{ update_secret|default:"<your secret>" }} protocol dyndns2 server {{ WWW_IPV4_HOST }} @@ -244,7 +244,7 @@
    {% trans "Enter the following data (and click ADD afterwards):" %}
    Servicensupdate.info Enabled(check) Host Name{{ host.get_fqdn|default:"<your hostname>" }} - User name{{ host.get_fqdn|default:"<your hostname>" }} + User name{{ host.http_user|default:"<your http user>" }} Password{{ update_secret|default:"<your secret>" }} @@ -261,7 +261,7 @@
    {% trans "Enter the following data:" %}
    Service TypeDynDNS Hostname{{ host.get_fqdn|default:"<your hostname>" }} Server{{ WWW_IPV4_HOST }} - Username{{ host.get_fqdn|default:"<your hostname>" }} + Username{{ host.http_user|default:"<your http user>" }} Password{{ update_secret|default:"<your secret>" }} @@ -275,7 +275,7 @@

    inadyn ({% trans "verified with" %} 1.99.11)

    system ipv4@nsupdate.info ssl - username {{ host.get_fqdn|default:"<your hostname>" }} + username {{ host.http_user|default:"<your http user>" }} password {{ update_secret|default:"<your secret>" }} alias {{ host.get_fqdn|default:"<your hostname>" }} @@ -288,7 +288,7 @@

    inadyn ({% trans "verified with" %} 2.1)

    provider ipv4@nsupdate.info { ssl = true - username = {{ host.get_fqdn|default:"<your hostname>" }} + username = {{ host.http_user|default:"<your http user>" }} password = {{ update_secret|default:"<your secret>" }} hostname = {{ host.get_fqdn|default:"<your hostname>" }} } @@ -310,7 +310,7 @@

    OpenWRT ({% trans "verified with" %} "Chaos Calmer")

    option ip_url "http://{{ WWW_IPV4_HOST }}/myip" option domain "{{ host.get_fqdn|default:"<your hostname>" }}" - option username "{{ host.get_fqdn|default:"<your hostname>" }}" + option username "{{ host.http_user|default:"<your http user>" }}" option password "{{ update_secret|default:"<your secret>" }}" # for https support, first install wget with ssl support and @@ -343,7 +343,7 @@
    {% trans "Enter the following data:" %}
    Interface to monitorWAN {% trans "(most likely)" %} Interface to send fromWAN {% trans "(most likely)" %} Verbose logging{% trans "(select this as long as you need it)" %} - Username{{ host.get_fqdn|default:"<your hostname>" }} + Username{{ host.http_user|default:"<your http user>" }} Password{{ update_secret|default:"<your secret>" }} Update URLhttps://{{ WWW_IPV4_HOST }}/nic/update Result Matchgood %IP%|nochg %IP% @@ -357,7 +357,7 @@
    {% trans "Enter the following data:" %}
    SettingValue Providerother Provider Domain name{{ host.get_fqdn|default:"<your hostname>" }} - User name{{ host.get_fqdn|default:"<your hostname>" }} + User name{{ host.http_user|default:"<your http user>" }} Password{{ update_secret|default:"<your secret>" }} Update server addresshttps://{{ WWW_IPV4_HOST }} Protocolhttps @@ -371,9 +371,9 @@

    {% trans "Browser-based update client" %}

    It periodically checks your IP and updates DNS if it changes. {% endblocktrans %}

    {% trans "URLs for browser / http user agent use" %}

    {% trans "Important: Do not send an update if your IP did not change since last update!" %} @@ -391,14 +391,14 @@

    {% trans "URLs for browser / http user agent use" %}

    {% trans "Giving the http basic auth username and password in the URL:" %} {% trans "As above, but manually specifying the IP address:" %} {% trans "Explanation of parameters:" %}