From 35e52a8931db326dc9c408596c9eb49e9c51cc9b Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Thu, 13 Jul 2023 11:00:32 +0200 Subject: [PATCH] MT#57855 add apikey commands > root@repoapi2:/usr/share/repoapi# source /var/lib/repoapi/venv_prod/bin/activate > root@repoapi2:/usr/share/repoapi# export DJANGO_SETTINGS_MODULE=repoapi.settings.prod Generate new apikey values, db is not changed!! This is just in order to produce a apikey.json file: > root@repoapi2:/usr/share/repoapi# ./manage.py apikey generate > key:AsAPINOl.D7pq6PRT4hjpnb13LIMmjjafqoUJN8JN prefix:AsAPINOl hashed_key:pbkdf2_sha256$260000$EqQMpCFxh4Bk6nWMApv3PA$+8ZbfG+MXpBSOrXmc33fgBZZ7rUI4ywInOfUry+SKec= Validate if a hash and key matches: > root@repoapi2:/usr/share/repoapi# ./manage.py apikey verify --key AsAPINOl.D7pq6PRT4hjpnb13LIMmjjafqoUJN8JN --value 'pbkdf2_sha256$260000$EqQMpCFxh4Bk6nWMApv3PA$+8ZbfG+MXpBSOrXmc33fgBZZ7rUI4ywInOfUry+SKec=' Generate a hash from key: > root@repoapi2:/usr/share/repoapi# ./manage.py apikey hash --value AsAPINOl.D7pq6PRT4hjpnb13LIMmjjafqoUJN8JN pbkdf2_sha256$260000$i2AeV5mIwaKKAcisHZHTl4$ZvxWMfFJSXfkbf6SDUG2Ilv0MOtXq/Cy0PG6NNA48po= Change-Id: I06bfe2f4e8cf08d3d75066cecf7e3fbf4c39680d --- repoapi/management/commands/apikey.py | 59 +++++++++++++++++++++++++++ repoapi/test/test_commands.py | 40 ++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 repoapi/management/commands/apikey.py diff --git a/repoapi/management/commands/apikey.py b/repoapi/management/commands/apikey.py new file mode 100644 index 0000000..2b27f06 --- /dev/null +++ b/repoapi/management/commands/apikey.py @@ -0,0 +1,59 @@ +# Copyright (C) 2023 The Sipwise Team - http://sipwise.com +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +from django.core.management.base import BaseCommand +from django.core.management.base import CommandError +from rest_framework_api_key.crypto import KeyGenerator + + +class Command(BaseCommand): + help = "apikey helper" + keygen = KeyGenerator() + + def generate(self, *args, **options): + key, prefix, hashed_key = self.keygen.generate() + self.stdout.write( + self.style.SUCCESS( + f"key:{key} prefix:{prefix} hashed_key:{hashed_key}" + ) + ) + + def hash(self, *argc, **options): + if "value" not in options: + raise CommandError("no value parameter found") + res = self.keygen.hash(options["value"]) + self.stdout.write(self.style.SUCCESS(f"{res}")) + + def verify(self, *args, **options): + if "value" not in options: + raise CommandError("no value parameter found") + value = options["value"] + if "key" not in options: + raise CommandError("no key parameter found") + key = options["key"] + res = self.keygen.verify(key, value) + if not res: + raise CommandError( + f"verification failed key:{key} hashed_key:{value}" + ) + + def add_arguments(self, parser): + parser.add_argument( + "action", choices=["generate", "hash", "verify"], default="hash" + ) + parser.add_argument("--key") + parser.add_argument("--value", help="value") + + def handle(self, *args, **options): + return getattr(self, options["action"])(**options) diff --git a/repoapi/test/test_commands.py b/repoapi/test/test_commands.py index 24cb96c..851004a 100644 --- a/repoapi/test/test_commands.py +++ b/repoapi/test/test_commands.py @@ -55,3 +55,43 @@ class exportJBITest(BaseTest): self.cmd.append(fp.name) call_command(*self.cmd) check_output(fp.name, f"{checkfile}") + + +class apikeyTest(BaseTest): + key = "bF5FPwbD.twrKaUDTqYck7gKu7G1EeKUCOSehU5MX" + hashed_key = ( + "pbkdf2_sha256$260000$0r1aVevuWiB53I" + "Mr9dTWOO$oJwAul49UovnNVybhIAisO8gTNiSv/GxDBWo9hfH+Tk=" + ) + + def setUp(self): + self.cmd = [ + "apikey", + ] + + def test_no_params(self): + with self.assertRaises(CommandError): + call_command(*self.cmd) + + def test_verify_ko(self): + self.cmd.append("verify") + self.cmd.append("--value") + self.cmd.append(self.hashed_key) + self.cmd.append("--key") + self.cmd.append("noNo") + with self.assertRaises(CommandError): + call_command(*self.cmd) + + def test_verify_ok(self): + self.cmd.append("verify") + self.cmd.append("--value") + self.cmd.append(self.hashed_key) + self.cmd.append("--key") + self.cmd.append(self.key) + call_command(*self.cmd) + + def test_hash_ok(self): + self.cmd.append("hash") + self.cmd.append("--value") + self.cmd.append(self.key) + call_command(*self.cmd)