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

Update Python API to support REST API v2 #4900

Merged
merged 1 commit into from
Dec 11, 2024
Merged

Conversation

edewata
Copy link
Contributor

@edewata edewata commented Nov 12, 2024

The PKIClient class has been added to replace PKIConnection as the main access point to PKI services. By default it will use REST API v2, then fall back to v1 if it's not available. Optionally, PKIClient can be configured to use a specific REST API version.

The InfoClient, CertClient, AccountClient, and UserClient classes have been added/updated to construct the proper REST URL according to the REST API version in PKIClient.

The pki-healthcheck has been updated to use PKIClient. Some simple Python scripts have also been added to demonstrate how to use PKIClient.

New tests have been added to run these scripts against the current CA and KRA which support both REST API v1 and v2 and also against an older CA that only supports REST API v1.

@rcritten
Copy link
Contributor

It is unexpected that one has to always pass in port when instantiating PKIClient when using a URL. If no port is provided for an http/https connection the port should default to 80/443.

@rcritten
Copy link
Contributor

list_certs is not working:

import pki.ca
import pki.cert
import pki.client
import pki.systemcert

pki_client = pki.client.PKIClient(url='https://ipa.example.test:443', verify=True)
print("API version %s" % pki_client.get_api_version())

ca_client = pki.ca.CAClient(pki_client)
cert_client = pki.cert.CertClient(ca_client)

print(cert_client.get_cert(1))

print(cert_client.list_certs(size=1))

Fails with a huge traceback but the bottom-line error is:

*** requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://ipa.example.test:443/ca/v2/certs/search?size=1

@edewata
Copy link
Contributor Author

edewata commented Dec 5, 2024

It is unexpected that one has to always pass in port when instantiating PKIClient when using a URL. If no port is provided for an http/https connection the port should default to 80/443.

I've updated the PR to fix this.

@edewata
Copy link
Contributor Author

edewata commented Dec 5, 2024

pki_client = pki.client.PKIClient(url='https://ipa.example.test:443', verify=True)
*** requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://ipa.example.test:443/ca/v2/certs/search?size=1

I think this is because IPA currently doesn't provide a proxy for REST API v2:
https://github.com/freeipa/freeipa/blob/master/install/share/ipa-pki-proxy.conf.template#L29-L35

@rcritten
Copy link
Contributor

rcritten commented Dec 5, 2024

I think this is because IPA currently doesn't provide a proxy for REST API v2: https://github.com/freeipa/freeipa/blob/master/install/share/ipa-pki-proxy.conf.template#L29-L35

I was using the python classes directly and not going through IPA.

@edewata
Copy link
Contributor Author

edewata commented Dec 5, 2024

I think this is because IPA currently doesn't provide a proxy for REST API v2: https://github.com/freeipa/freeipa/blob/master/install/share/ipa-pki-proxy.conf.template#L29-L35

I was using the python classes directly and not going through IPA.

Yes, but port 443 is owned by IPA and with the current proxy configuration it's not forwarding the request to PKI.

@edewata
Copy link
Contributor Author

edewata commented Dec 6, 2024

@fmarco76 @rcritten Please take a look at the updated PR. I think all CI failures are fixed now (except for the known issues), and this change should not affect IPA since IPA is not using it yet. Once this is merged we can update other classes & methods to support REST API v2. Thanks!

Copy link
Member

@fmarco76 fmarco76 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have several concerns but the overall looks good.Feel free to update/merge this so it is possible to continue integrating the other APIs and improve the design.

logger = logging.getLogger(__name__)


class UserClient(object):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

object should not be needed in python3

logger = logging.getLogger(__name__)


class CAClient(object):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else:
self.api_version = 'v1'
self.api_path = 'rest'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some parameters could have different meaning between v1 and v2. As an example: #4672.

Also the output could be different when accessing with v1 or v2 and these difference could increase with the API evolution.

I think the user should be aware of the used API so I would prefer to not automatically revert to v1, or at least a warning should be present.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. do you have some examples? Ideally the Python API is supposed to take params that can be used for both REST API v1 and v2, then call either REST API v1 or v2 depending on the availability and client's requirements, then parse the server's response and put it into objects that can be used by the Python client regardless of which REST API version was actually used.

Copy link
Member

@fmarco76 fmarco76 Dec 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the linked PR the GET parameter start for AgentCertRequestService is an index for v2 and a serial number for v1 so the user could have different results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. In that particular case the REST API v1 and v2 aren't compatible, so we probably need to provide separate Python methods/parameters for them, and if the required API version is not available the call should fail instead of automatically switching to the other version. We'll deal with this when we get there.


class CAClient(object):

def __init__(self, parent):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is almost empty providing only the subsytem name. To access the API, looking in the pki-ca-cert-find.py as example, it is needed to create a PKIClient, then a CAClient and finally a UserClient.

Using inheritance the CAClient could extend the PKIClient so there is no need to create both.
Additionally, with multi inheritance the operation could be invoked on this subsystem object making evident the supported operation. Alternatively, the other clients could create here so instead of
users = user_client.find_users()
it would be
users = ca_client.users.find()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same would be for the other subsystems

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updated Python API is more consistent with the Java API, so the PKIClient serves as the main entry point for the client to set up the connection and the authentication, then the operations are grouped by subsystems (e.g. CA, KRA). Ideally the subsystem classes should inherit from a SubsystemClient class just like in Java API, but that can be added later. Having said that, I'm open to client API redesign as long as it's consistently done in Python and Java API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I did not check the Java version before and they seems consistent. I think there is room for improvement in the design to avoid this multiple clients for the moment I agree it is better to be consistent. We can work on this later.

The PKIClient class has been added to replace PKIConnection
as the main access point to PKI services. By default it will
use REST API v2, then fall back to v1 if it's not available.
Optionally, PKIClient can be configured to use a specific
REST API version.

The InfoClient, CertClient, AccountClient, and UserClient
classes have been added/updated to construct the proper REST
URL according to the REST API version in PKIClient.

The pki-healthcheck has been updated to use PKIClient. Some
simple Python scripts have also been added to demonstrate
how to use PKIClient.

New tests have been added to run these scripts against the
current CA and KRA which support both REST API v1 and v2
and also against an older CA that only supports REST API v1.
@edewata
Copy link
Contributor Author

edewata commented Dec 11, 2024

@fmarco76 Thanks! I've clean up the PR as you suggested and will merge after the CI is done. Feel free to continue the client API design discussion.

@fmarco76
Copy link
Member

CI is done

Python CI is failing for a deprecated library. We should schedule the work to fix this since we are working on the python code

@edewata
Copy link
Contributor Author

edewata commented Dec 11, 2024

Python CI is failing for a deprecated library. We should schedule the work to fix this since we are working on the python code

Looks like the container tests are failing too, but it doesn't seem to be related to this PR. I'll take a look after this.

@edewata edewata merged commit abe49da into dogtagpki:master Dec 11, 2024
153 of 171 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants