Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move credentials to API V2 #554

Merged
merged 4 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions camayoc/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

from camayoc import exceptions
from camayoc.config import settings
from camayoc.constants import QPC_API_VERSION
from camayoc.constants import QPC_API_ROOT
from camayoc.constants import QPC_CURRENT_USER_PATH
from camayoc.constants import QPC_LOGOUT_PATH
from camayoc.constants import QPC_TOKEN_PATH


Expand Down Expand Up @@ -136,7 +138,7 @@ def __init__(
scheme = "https" if self.config.https else "http"
port = str(self.config.port)
netloc = hostname + ":{}".format(port) if port else hostname
self.url = urlunparse((scheme, netloc, QPC_API_VERSION, "", "", ""))
self.url = urlunparse((scheme, netloc, QPC_API_ROOT, "", "", ""))

if not self.url:
raise exceptions.QPCBaseUrlNotFound(
Expand Down Expand Up @@ -170,7 +172,7 @@ def logout(self, **kwargs):
Send a PUT request /api/v1/users/logout to make
current token invalid.
"""
url = urljoin(self.url, "users/logout/")
url = urljoin(self.url, QPC_LOGOUT_PATH)
self.request("PUT", url, **kwargs)
self.token = None

Expand All @@ -179,7 +181,7 @@ def get_user(self, **kwargs):

Send a GET request ot /api/v1/users/current/' and return the response.
"""
url = urljoin(self.url, "users/current/")
url = urljoin(self.url, QPC_CURRENT_USER_PATH)
return self.request("GET", url, **kwargs)

def default_headers(self):
Expand Down
20 changes: 13 additions & 7 deletions camayoc/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,22 @@
VAULT_PASSWORD = utils.uuid4()
"""Vault password will be unique across Python sessions."""

QPC_API_VERSION = "api/v1/"
QPC_API_ROOT = "api/"
"""The root path to access the QPC server API."""

QPC_CREDENTIALS_PATH = "credentials/"
QPC_CREDENTIALS_PATH = "v2/credentials/"
"""The path to the credentials endpoint for CRUD tasks."""

QPC_SOURCE_PATH = "sources/"
QPC_SOURCE_PATH = "v1/sources/"
"""The path to the profiles endpoint for CRUD tasks."""

QPC_SCAN_PATH = "scans/"
QPC_SCAN_PATH = "v1/scans/"
"""The path to the scans endpoint for CRUD tasks."""

QPC_SCANJOB_PATH = "jobs/"
QPC_SCANJOB_PATH = "v1/jobs/"
"""The path to the scanjob endpoint for CRUD tasks."""

QPC_REPORTS_PATH = "reports/"
QPC_REPORTS_PATH = "v1/reports/"
"""The path to the endpoint used for obtaining reports."""

QPC_SCAN_TERMINAL_STATES = ("completed", "failed", "canceled")
Expand All @@ -57,9 +57,15 @@
QPC_SCAN_STATES = QPC_SCAN_TERMINAL_STATES + ("running",)
"""All the states that a quipucords scan can take."""

QPC_TOKEN_PATH = "token/"
QPC_TOKEN_PATH = "v1/token/"
"""The path to the endpoint used for obtaining an authentication token."""

QPC_LOGOUT_PATH = "v1/users/logout/"
"""The path to the endpoint used to log user out."""

QPC_CURRENT_USER_PATH = "v1/users/current/"
"""The path to the endpoint that has information about current user."""

QPC_SOURCE_TYPES = (
"vcenter",
"network",
Expand Down
11 changes: 7 additions & 4 deletions camayoc/qpc_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from camayoc.types.settings import CredentialOptions
from camayoc.types.settings import ScanOptions
from camayoc.types.settings import SourceOptions
from camayoc.utils import server_container_ssh_key_content
from camayoc.utils import uuid4

OPTIONAL_PROD_KEY = "disabled_optional_products"
Expand Down Expand Up @@ -176,7 +177,7 @@ class Credential(QPCObject, QPCObjectBulkDeleteMixin):
Host credentials can be created by instantiating a Credential
object. A unique name and username are provided by default.
In order to create a valid host credential you must specify either a
password or ssh_keyfile or auth_token.
password or ssh_key or auth_token.

Example::
>>> from camayoc import api
Expand All @@ -195,7 +196,7 @@ def __init__(
name=None,
username=None,
password=None,
ssh_keyfile=None,
ssh_key=None,
auth_token=None,
cred_type=None,
become_method=None,
Expand All @@ -215,7 +216,7 @@ def __init__(
username = uuid4()
self.username = username
self.password = password
self.ssh_keyfile = ssh_keyfile
self.ssh_key = ssh_key
self.auth_token = auth_token
self.cred_type = cred_type
if become_method is not None:
Expand All @@ -230,7 +231,7 @@ def from_definition(
cls, definition: CredentialOptions, dependencies: Optional[list[int]] = None
):
attrs_translation_map = {
"sshkeyfile": "ssh_keyfile",
"sshkeyfile": "ssh_key",
"type": "cred_type",
}
definition_data = {}
Expand All @@ -239,6 +240,8 @@ def from_definition(
continue
if new_definition_key := attrs_translation_map.get(definition_key):
definition_key = new_definition_key
if definition_key == "ssh_key":
definition_value = server_container_ssh_key_content(definition_value)
definition_data[definition_key] = definition_value
return cls(**definition_data)

Expand Down
86 changes: 57 additions & 29 deletions camayoc/tests/qpc/cli/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,17 @@ def generate_show_output(data):
auth_type = data.get("auth_type", "(auth_token|password|ssh_key|ssh_keyfile|unknown)")
output = "{\r\n"
output += ' "auth_type": "{}",\r\n'.format(auth_type)
if cred_type == "network":
output += ' "become_method": "{}",\r\n'.format(data.get("become_method", "sudo"))
if "become_password" in data:
output += ' "become_password": "{}",\r\n'.format(data["become_password"])
output += ' "become_user": "{}",\r\n'.format(data.get("become_user", "root"))
output += ' "become_method": {},\r\n'.format(data.get("become_method", "null"))
output += ' "become_user": {},\r\n'.format(data.get("become_user", "null"))
output += ' "created_at": {},\r\n'.format(data.get("created_at", ".*"))
output += ' "cred_type": "{}",\r\n'.format(cred_type)
for field in ("auth_token", "become_password", "password", "ssh_key", "ssh_passphrase"):
value = field in data
output += ' "has_{}": {},\r\n'.format(field, str(value).lower())
output += ' "id": {},\r\n'.format(data.get("id", "\\d+"))
output += ' "name": "{}",\r\n'.format(data["name"])
if "password" in data:
output += ' "password": "{}",\r\n'.format(data["password"])
if "ssh_keyfile" in data:
output += ' "ssh_keyfile": "{}",\r\n'.format(data["ssh_keyfile"])
output += ' "sources": \\[.*\\],\r\n'
output += ' "ssh_keyfile": {},\r\n'.format(data.get("ssh_keyfile", "null"))
output += ' "updated_at": {},\r\n'.format(data.get("updated_at", ".*"))
output += ' "username": "{}"\r\n'.format(data["username"])
output += "}\r\n"
Expand All @@ -69,6 +67,10 @@ def test_add_with_username_password(isolated_filesystem, qpc_server_config, sour
[(CONNECTION_PASSWORD_INPUT, utils.uuid4())],
)

extra_output_args = {}
if source_type == "network":
extra_output_args["become_method"] = '"sudo"'
extra_output_args["become_user"] = '"root"'
cred_show_and_check(
{"name": name},
generate_show_output(
Expand All @@ -78,6 +80,7 @@ def test_add_with_username_password(isolated_filesystem, qpc_server_config, sour
"password": MASKED_PASSWORD_OUTPUT,
"username": username,
"auth_type": "password",
**extra_output_args,
}
),
)
Expand Down Expand Up @@ -108,6 +111,8 @@ def test_add_with_username_password_become_password(isolated_filesystem, qpc_ser
{"name": name},
generate_show_output(
{
"become_method": '"sudo"',
"become_user": '"root"',
"become_password": MASKED_PASSWORD_OUTPUT,
"name": name,
"password": MASKED_PASSWORD_OUTPUT,
Expand All @@ -125,8 +130,7 @@ def test_add_with_username_sshkeyfile(data_provider, qpc_server_config):
:id: 9bfb16a2-5a10-4a01-9f9d-b29445c1f4bf
:description: Add an auth entry providing the ``--name``, ``--username``
and ``--sshkeyfile`` options.
:steps: Run ``qpc cred add --name <name> --username <username> --sshkeyfile
<sshkeyfile>``
:steps: Run ``qpc cred add --name <name> --username <username> --sshkey``
:expectedresults: A new auth entry is created with the data provided as
input.
"""
Expand All @@ -138,17 +142,20 @@ def test_add_with_username_sshkeyfile(data_provider, qpc_server_config):
)

cred_add_and_check(
{"name": name, "username": username, "sshkeyfile": sshkeyfile_cred.ssh_keyfile}
{"name": name, "username": username, "sshkey": None},
inputs=[("Private SSH Key:", sshkeyfile_cred.ssh_key)],
)

cred_show_and_check(
{"name": name},
generate_show_output(
{
"name": name,
"ssh_keyfile": sshkeyfile_cred.ssh_keyfile,
"ssh_key": True,
"username": username,
"auth_type": "ssh_keyfile",
"auth_type": "ssh_key",
"become_method": '"sudo"',
"become_user": '"root"',
}
),
)
Expand All @@ -160,9 +167,9 @@ def test_add_with_username_sshkeyfile_become_password(data_provider, qpc_server_

:id: 94a45a9b-cda7-41e7-8be5-caf598917ebb
:description: Add an auth entry providing the ``--name``, ``--username``,
``--sshkeyfile`` and ``--become-password`` options.
:steps: Run ``qpc cred add --name <name> --username <username> --sshkeyfile
<sshkeyfile> --become-password``
``--sshkey`` and ``--become-password`` options.
:steps: Run ``qpc cred add --name <name> --username <username> --sshkey
--become-password``
:expectedresults: A new auth entry is created with the data provided as
input.
"""
Expand All @@ -177,22 +184,27 @@ def test_add_with_username_sshkeyfile_become_password(data_provider, qpc_server_
{
"name": name,
"username": username,
"sshkeyfile": sshkeyfile_cred.ssh_keyfile,
"sshkey": None,
"become-password": None,
},
[(BECOME_PASSWORD_INPUT, utils.uuid4())],
inputs=[
("Private SSH Key:", sshkeyfile_cred.ssh_key),
(BECOME_PASSWORD_INPUT, utils.uuid4()),
],
)

cred_show_and_check(
{"name": name},
generate_show_output(
{
"cred_type": "network",
"become_method": '"sudo"',
"become_user": '"root"',
"become_password": MASKED_PASSWORD_OUTPUT,
"name": name,
"ssh_keyfile": sshkeyfile_cred.ssh_keyfile,
"ssh_key": True,
"username": username,
"auth_type": "ssh_keyfile",
"auth_type": "ssh_key",
}
),
)
Expand All @@ -215,6 +227,10 @@ def test_edit_username(isolated_filesystem, qpc_server_config, source_type):
[(CONNECTION_PASSWORD_INPUT, utils.uuid4())],
)

extra_output_args = {}
if source_type == "network":
extra_output_args["become_method"] = '"sudo"'
extra_output_args["become_user"] = '"root"'
cred_show_and_check(
{"name": name},
generate_show_output(
Expand All @@ -224,6 +240,7 @@ def test_edit_username(isolated_filesystem, qpc_server_config, source_type):
"password": MASKED_PASSWORD_OUTPUT,
"username": username,
"auth_type": "password",
**extra_output_args,
}
),
)
Expand All @@ -246,6 +263,7 @@ def test_edit_username(isolated_filesystem, qpc_server_config, source_type):
"password": MASKED_PASSWORD_OUTPUT,
"username": new_username,
"auth_type": "password",
**extra_output_args,
}
),
)
Expand Down Expand Up @@ -296,6 +314,10 @@ def test_edit_password(isolated_filesystem, qpc_server_config, source_type):
[(CONNECTION_PASSWORD_INPUT, password)],
)

extra_output_args = {}
if source_type == "network":
extra_output_args["become_method"] = '"sudo"'
extra_output_args["become_user"] = '"root"'
cred_show_and_check(
{"name": name},
generate_show_output(
Expand All @@ -305,6 +327,7 @@ def test_edit_password(isolated_filesystem, qpc_server_config, source_type):
"password": MASKED_PASSWORD_OUTPUT,
"username": username,
"auth_type": "password",
**extra_output_args,
}
),
)
Expand All @@ -326,6 +349,7 @@ def test_edit_password(isolated_filesystem, qpc_server_config, source_type):
"password": MASKED_PASSWORD_OUTPUT,
"username": username,
"auth_type": "password",
**extra_output_args,
}
),
)
Expand Down Expand Up @@ -362,8 +386,7 @@ def test_edit_sshkeyfile_negative(data_provider, qpc_server_config):

:id: 97734b67-3d5e-4add-9282-22844fd436d1
:description: Edit the sshkeyfile of a not created auth entry.
:steps: Run ``qpc cred edit --name <invalidname> --sshkeyfile
<newsshkeyfile>``
:steps: Run ``qpc cred edit --name <invalidname> --sshkey``
:expectedresults: The command should fail with a proper message.
"""
name = utils.uuid4()
Expand All @@ -373,15 +396,12 @@ def test_edit_sshkeyfile_negative(data_provider, qpc_server_config):
data_only=True,
)
cred_add_and_check(
{"name": name, "username": username, "sshkeyfile": sshkeyfile_cred.ssh_keyfile}
{"name": name, "username": username, "sshkey": None},
inputs=[("Private SSH Key:", sshkeyfile_cred.ssh_key)],
)

name = utils.uuid4()
qpc_cred_edit = pexpect.spawn(
"{} -v cred edit --name={} --sshkeyfile {}".format(
client_cmd, name, sshkeyfile_cred.ssh_keyfile
)
)
qpc_cred_edit = pexpect.spawn("{} -v cred edit --name={} --sshkey".format(client_cmd, name))
qpc_cred_edit.logfile = BytesIO()
assert qpc_cred_edit.expect('Credential "{}" does not exist'.format(name)) == 0
assert qpc_cred_edit.expect(pexpect.EOF) == 0
Expand Down Expand Up @@ -417,6 +437,8 @@ def test_edit_become_password(isolated_filesystem, qpc_server_config):
{"name": name},
generate_show_output(
{
"become_method": '"sudo"',
"become_user": '"root"',
"become_password": MASKED_PASSWORD_OUTPUT,
"name": name,
"password": MASKED_PASSWORD_OUTPUT,
Expand All @@ -440,6 +462,8 @@ def test_edit_become_password(isolated_filesystem, qpc_server_config):
{"name": name},
generate_show_output(
{
"become_method": '"sudo"',
"become_user": '"root"',
"become_password": MASKED_PASSWORD_OUTPUT,
"name": name,
"password": MASKED_PASSWORD_OUTPUT,
Expand Down Expand Up @@ -521,6 +545,8 @@ def test_clear(isolated_filesystem, qpc_server_config):
"password": MASKED_PASSWORD_OUTPUT,
"username": username,
"auth_type": "password",
"become_method": '"sudo"',
"become_user": '"root"',
}
),
)
Expand Down Expand Up @@ -582,6 +608,8 @@ def test_clear_with_source(isolated_filesystem, qpc_server_config):
"password": MASKED_PASSWORD_OUTPUT,
"username": username,
"auth_type": "password",
"become_method": '"sudo"',
"become_user": '"root"',
}
),
)
Expand Down
Loading
Loading