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

Orders persistence #74

Closed
xnaveira opened this issue Mar 15, 2019 · 20 comments
Closed

Orders persistence #74

xnaveira opened this issue Mar 15, 2019 · 20 comments

Comments

@xnaveira
Copy link

I am trying to implement acme4j on a project that among other things will create new certificates from Let's Encrypt. I am struggling with understanding the Login object and the persistence of the created objects.
In particular, I create a session and use it along with my keys and the account builder to retrieve a create a login object, so far so good. I then go ahead an create a new order, that works fine and I can even fetch my challenges and trigger them etc.
What I don't get is that even if I use the method Login::bindOrder with my order if then I try Login::getAccount::getOrders I get org.shredzone.acme4j.exception.AcmeProtocolException: orders: required, but not set
Also the challenge validation for a particular order seems to be validated only the first time I try, but that I suspect is linked to the fact I don't understand how persistence works.
Could someone shed some light here please? Is LE supposed to save my uncomplete orders by uncomplete I mean orders which don't have validated the challenge or that have validate it but still haven't gotten the CSR)
Thank you!

@shred
Copy link
Owner

shred commented Mar 15, 2019

The problem here is that Login::getAccount::getOrders is defined in the ACME protocol, but not implemented in the Let's Encrypt server. Since acme4j is supposed to be a general ACME client (this is, it's not limited to Let's Encrypt), the getOrders method is present, even if it is not of any use at the moment.

The best way to persist an object is to get its URL (via getLocation()) and store it locally in some kind of database. When you later need to restore the object, use one of the Login::bind* methods and pass the stored URL, to retrieve a working object.

For example, to store your order for later use, use Order::getLocation, and later use Login::bindOrder to get a new Order object.

If you want to persist a Challenge object, you need to persist the Authorization object. After restoring the Authorization, you can then invoke getChallenges() and findChallenge(). (Actually, a Login::bindChallenge method is missing. I'll see if it can be added.)

@xnaveira
Copy link
Author

Oh! I see now, thanks! So the only reference I ever get from LE is the urls that I have to store. I think I understand now.

(Actually, a Login::bindChallenge method is missing. I'll see if it can be added.)

I guess that you can always get your challenge from the authorization object.

@shred
Copy link
Owner

shred commented Mar 15, 2019

Yes, the URLs are the only permanent references we get from LE.

I was just having a look at the ACME specs. There is no documented way to bind a Challenge by its URL. The only way to get a Challenge is via the Authorization object.

@xnaveira
Copy link
Author

Exactly, so if one would be processing multiple certificates what one would do is to persist the URLs at every step of the way and in case the need for restoring state arises (ie service crash or shutdown) one would need to list all the urls and bind them.

@shred
Copy link
Owner

shred commented Mar 15, 2019

You don't necessarily need to store all the URLs, unless you process the validation steps asynchronously, and need to recover the objects for every step.

However, I recommend to store at least the Account URL (even though you could recover it with the AccountBuilder) and the Certificate URL (for revocation, even though you could also revoke a cert without the URL).

@xnaveira
Copy link
Author

I do process the steps asynchronously, also, you need the order object to renew the associate cert, don't you?

@shred
Copy link
Owner

shred commented Mar 15, 2019

For certificate renewal, you must create a new Order via Account::newOrder. You cannot reuse the existing Order object for that.

@xnaveira
Copy link
Author

I see, would you be so kind to point me to a good documentation for the Let's encrypt API? I don't seem to find anything. Thank you again!

@shred
Copy link
Owner

shred commented Mar 15, 2019

Let's Encrypt uses the ACME protocol, which is documented in RFC 8555.

@xnaveira
Copy link
Author

Of course, I thought that they would have some specific docs for their implementation (like the getOrders method not being implemented etc)

Thank you!

@shred
Copy link
Owner

shred commented Mar 15, 2019

The Let's Encrypt server is open source. You can find the missing ACMEv2 features here.

@xnaveira
Copy link
Author

I have some reading to do i guess :)

@cpu
Copy link
Contributor

cpu commented Mar 15, 2019

I thought that they would have some specific docs for their implementation (like the getOrders method not being implemented etc)

We do: docs/acme-divergences.md.

It's a little bit out of date w.r.t references to the RFC (letsencrypt/boulder#4110) but the "ACME v2 divergences" section at the top is up to date and includes a mention of the "orders" field of account objects not being implemented.

@shred
Copy link
Owner

shred commented Mar 15, 2019

More or less... Actually, acme4j should do all the protocol work for you, so all you need to read is the acme4j docs. 😉

@shred
Copy link
Owner

shred commented Mar 15, 2019

We do: docs/acme-divergences.md.

@cpu Thank you... I was looking for that document, but couldn't find it at the moment.

@shred
Copy link
Owner

shred commented Mar 15, 2019

By the way, thank you @xnaveira... You have pointed out some weaknesses in the acme4j docs that I should have explained better.

@xnaveira
Copy link
Author

The fact that i am completely new to ACME and LE and pretty beginner at programming in java for that matter might had something to do with it too :)

@shred
Copy link
Owner

shred commented Mar 15, 2019

If you have questions about or want to give feedback to acme4j, I'd appreciate to hear from you. 😄

@xnaveira
Copy link
Author

That's awesone @shred thank you! I'll see if I can finally make it work and then give you some feedback from a newbie pov. :)

@shred
Copy link
Owner

shred commented Aug 2, 2020

Starting with v2.10, acme4j will now throw a verbose exception if Account.getOrders() is used, but not supported by the CA.

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

No branches or pull requests

3 participants