[GH-ISSUE #26] Status 401 (Unauthorized) when trying to post update request #6

Closed
opened 2026-03-13 15:19:35 +03:00 by kerem · 5 comments
Owner

Originally created by @eknori on GitHub (Dec 2, 2017).
Original GitHub issue: https://github.com/acme-dns/acme-dns/issues/26

I am trying to update a DNS record using Java.
I always get an 401 status response, but I cannot see anything wrong in my code.

` private void contactAcmeDnsServer(String digest) {
Console.out("Digest: " + digest);

	try {
		Content content = Request.Post("http://localhost:9443/register").execute().returnContent();

		JSONParser parser = new JSONParser();
		JSONObject json = (JSONObject) parser.parse(content.asString());

		String fulldomain = (String) json.get("fulldomain");
		String subdomain = (String) json.get("subdomain");
		String username = (String) json.get("username");
		String password = (String) json.get("password");
		
		String url = "http://localhost:9443/update";

		@SuppressWarnings("resource")
		HttpClient client = new DefaultHttpClient();
		HttpPost request = new HttpPost(url);
		request.addHeader("X-Api-Key", password);
		request.addHeader("X-Api-User", username);

		String JSON_STRING = "{\r\n" + "\"subdomain\": \"_acme-challenge." + subdomain + "\",\r\n" + "\"txt\": \""
				+ digest + "\"\r\n" + "}";

		StringEntity stringEntity = new StringEntity(JSON_STRING, "UTF-8");

		request.setEntity(stringEntity);

		HttpResponse response = client.execute(request);

		Console.out("rc: " + String.valueOf(response.getStatusLine().getStatusCode()));

		BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

		StringBuffer result = new StringBuffer();
		String line = "";
		while ((line = rd.readLine()) != null) {
			result.append(line);
		}

		Console.out(result.toString());

	} catch (IOException e) {
		e.printStackTrace();
	} catch (ParseException e) {
		e.printStackTrace();
	}`

Aside from this, am I supposed to do the POST /register every time before the POST /update?
Is the "_acme-challenge." part automatically added in the POST /update or is my JSON_STRING object correct?

Originally created by @eknori on GitHub (Dec 2, 2017). Original GitHub issue: https://github.com/acme-dns/acme-dns/issues/26 I am trying to update a DNS record using Java. I always get an 401 status response, but I cannot see anything wrong in my code. ` private void contactAcmeDnsServer(String digest) { Console.out("Digest: " + digest); try { Content content = Request.Post("http://localhost:9443/register").execute().returnContent(); JSONParser parser = new JSONParser(); JSONObject json = (JSONObject) parser.parse(content.asString()); String fulldomain = (String) json.get("fulldomain"); String subdomain = (String) json.get("subdomain"); String username = (String) json.get("username"); String password = (String) json.get("password"); String url = "http://localhost:9443/update"; @SuppressWarnings("resource") HttpClient client = new DefaultHttpClient(); HttpPost request = new HttpPost(url); request.addHeader("X-Api-Key", password); request.addHeader("X-Api-User", username); String JSON_STRING = "{\r\n" + "\"subdomain\": \"_acme-challenge." + subdomain + "\",\r\n" + "\"txt\": \"" + digest + "\"\r\n" + "}"; StringEntity stringEntity = new StringEntity(JSON_STRING, "UTF-8"); request.setEntity(stringEntity); HttpResponse response = client.execute(request); Console.out("rc: " + String.valueOf(response.getStatusLine().getStatusCode())); BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } Console.out(result.toString()); } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); }` Aside from this, am I supposed to do the POST /register every time before the POST /update? Is the "_acme-challenge." part automatically added in the POST /update or is my JSON_STRING object correct?
kerem closed this issue 2026-03-13 15:19:40 +03:00
Author
Owner

@joohoi commented on GitHub (Dec 2, 2017):

This should work:
String JSON_STRING = "{\"subdomain\": \" + subdomain + "\", \"txt\": \"" + digest + "\"}";

So you are not supposed to add the _acme-challenge to the acme-dns subdomain, but instead point the CNAME record of _acme-challenge.example.org in your original DNS zone to the fulldomain from acme-dns registration (where example.org is the domain you want the certificate for).

<!-- gh-comment-id:348692680 --> @joohoi commented on GitHub (Dec 2, 2017): This should work: `String JSON_STRING = "{\"subdomain\": \" + subdomain + "\", \"txt\": \"" + digest + "\"}";` So you are not supposed to add the _acme-challenge to the acme-dns subdomain, but instead point the CNAME record of `_acme-challenge.example.org` in your original DNS zone to the `fulldomain` from acme-dns registration (where example.org is the domain you want the certificate for).
Author
Owner

@eknori commented on GitHub (Dec 2, 2017):

Thx. And the POST /register is done only once and I will then reuse the values in each POST / update ?

<!-- gh-comment-id:348693178 --> @eknori commented on GitHub (Dec 2, 2017): Thx. And the POST /register is done only once and I will then reuse the values in each POST / update ?
Author
Owner

@joohoi commented on GitHub (Dec 2, 2017):

Thx. And the POST /register is done only once and I will then reuse the values in each POST / update ?

Exactly, these are the values you will store on the box itself!

<!-- gh-comment-id:348693221 --> @joohoi commented on GitHub (Dec 2, 2017): >Thx. And the POST /register is done only once and I will then reuse the values in each POST / update ? Exactly, these are the values you will store on the box itself!
Author
Owner

@eknori commented on GitHub (Dec 3, 2017):

OK, got it working so far , but still struggeling with the configuration.

acme-dns server is accessible via port 53 on eknori.blogsite.org. I want to create certs also for eknori.spdns.org.
How do I have to configure acme-dns and put the CNAME record into it. This part is missing in the video.

I have registered with POST/ http://eknori.blogsite.org:9443/register
and stored the returned values in a .ini file where I can the retrieve them when doing the POST/ update

Here is my config.

listen = ":53"
protocol = "udp"
domain = "eknori.blogsite.org"
nsname = "ns1.eknori.blogsite.org"
nsadmin = "admin.eknori.blogsite.org"
records = [
"eknori.blogsite.org. A 192.168.178.33",
"eknori.spdns.org. A 192.168.178.33",
"_acme-challenge.eknori.spdns.org. CNAME b82313ea-b4c2-4ea3-bd96-8d5429402160.eknori.blogsite.org.",
"ns1.eknori.blogsite.org. A 192.168.178.33",
"ns2.eknori.blogsite.org. A 192.168.178.33",
"eknori.blogsite.org. NS ns1.eknori.blogsite.org.",
"eknori.blogsite.org. NS ns2.eknori.blogsite.org.",
]

Full- /Subdomains are the following

LE4D_DNS_FULLDOMAIN=15776d6a-ad4a-4674-8b49-d47e6bf90dc4.eknori.blogsite.org
LE4D_DNS_SUBDOMAIN=15776d6a-ad4a-4674-8b49-d47e6bf90dc4

DIG returns:

; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> _acme-challenge.eknori.spdns.org CNAME @eknori.blogsite.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63110
;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;_acme-challenge.eknori.spdns.org. IN CNAME

;; ANSWER SECTION:
_acme-challenge.eknori.spdns.org. 3600 IN CNAME 15776d6a-ad4a-4674-8b49-d47e6bf90dc4.eknori.blogsite.org.

;; Query time: 5 msec
;; SERVER: 80.134.211.28#53(80.134.211.28)
;; WHEN: Sun Dec 03 08:12:38 CET 2017
;; MSG SIZE rcvd: 152

The TXT record is written
[DOTS] midpoints.le4d - Digest: LOCoIvrX3lSt6jVQUtr9kHWFitaZO-1sr0LQkXa5fb0
[DOTS] midpoints.le4d - Fulldomain: 15776d6a-ad4a-4674-8b49-d47e6bf90dc4.eknori.blogsite.org
[DOTS] midpoints.le4d - Subdomain: 15776d6a-ad4a-4674-8b49-d47e6bf90dc4
[DOTS] midpoints.le4d - rc: 200
[DOTS] midpoints.le4d - {"txt": "LOCoIvrX3lSt6jVQUtr9kHWFitaZO-1sr0LQkXa5fb0"}

but

dig _acme-challenge.eknori.spdns.org txt @eknori.blogsite.org

; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> _acme-challenge.eknori.spdns.org txt @eknori.blogsite.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 24155
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;_acme-challenge.eknori.spdns.org. IN TXT

;; Query time: 6 msec
;; SERVER: 80.134.211.28#53(80.134.211.28)
;; WHEN: Sun Dec 03 08:14:25 CET 2017
;; MSG SIZE rcvd: 50

and finally the challenge fails.

Anything that I am missing ?

<!-- gh-comment-id:348743496 --> @eknori commented on GitHub (Dec 3, 2017): OK, got it working so far , but still struggeling with the configuration. acme-dns server is accessible via port 53 on eknori.blogsite.org. I want to create certs also for eknori.spdns.org. How do I have to configure acme-dns and put the CNAME record into it. This part is missing in the video. I have registered with POST/ http://eknori.blogsite.org:9443/register and stored the returned values in a .ini file where I can the retrieve them when doing the POST/ update Here is my config. listen = ":53" protocol = "udp" domain = "eknori.blogsite.org" nsname = "ns1.eknori.blogsite.org" nsadmin = "admin.eknori.blogsite.org" records = [ "eknori.blogsite.org. A 192.168.178.33", "eknori.spdns.org. A 192.168.178.33", "_acme-challenge.eknori.spdns.org. CNAME b82313ea-b4c2-4ea3-bd96-8d5429402160.eknori.blogsite.org.", "ns1.eknori.blogsite.org. A 192.168.178.33", "ns2.eknori.blogsite.org. A 192.168.178.33", "eknori.blogsite.org. NS ns1.eknori.blogsite.org.", "eknori.blogsite.org. NS ns2.eknori.blogsite.org.", ] Full- /Subdomains are the following LE4D_DNS_FULLDOMAIN=15776d6a-ad4a-4674-8b49-d47e6bf90dc4.eknori.blogsite.org LE4D_DNS_SUBDOMAIN=15776d6a-ad4a-4674-8b49-d47e6bf90dc4 DIG returns: ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> _acme-challenge.eknori.spdns.org CNAME @eknori.blogsite.org ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63110 ;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;_acme-challenge.eknori.spdns.org. IN CNAME ;; ANSWER SECTION: _acme-challenge.eknori.spdns.org. 3600 IN CNAME 15776d6a-ad4a-4674-8b49-d47e6bf90dc4.eknori.blogsite.org. ;; Query time: 5 msec ;; SERVER: 80.134.211.28#53(80.134.211.28) ;; WHEN: Sun Dec 03 08:12:38 CET 2017 ;; MSG SIZE rcvd: 152 The TXT record is written [DOTS] midpoints.le4d - Digest: LOCoIvrX3lSt6jVQUtr9kHWFitaZO-1sr0LQkXa5fb0 [DOTS] midpoints.le4d - Fulldomain: 15776d6a-ad4a-4674-8b49-d47e6bf90dc4.eknori.blogsite.org [DOTS] midpoints.le4d - Subdomain: 15776d6a-ad4a-4674-8b49-d47e6bf90dc4 [DOTS] midpoints.le4d - rc: 200 [DOTS] midpoints.le4d - {"txt": "LOCoIvrX3lSt6jVQUtr9kHWFitaZO-1sr0LQkXa5fb0"} but **dig _acme-challenge.eknori.spdns.org txt @eknori.blogsite.org** ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> _acme-challenge.eknori.spdns.org txt @eknori.blogsite.org ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 24155 ;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;_acme-challenge.eknori.spdns.org. IN TXT ;; Query time: 6 msec ;; SERVER: 80.134.211.28#53(80.134.211.28) ;; WHEN: Sun Dec 03 08:14:25 CET 2017 ;; MSG SIZE rcvd: 50 and finally the challenge fails. Anything that I am missing ?
Author
Owner

@joohoi commented on GitHub (Dec 3, 2017):

You will need to make acme-dns the authoritative name server for eknori.blogsite.org in order to make DNS requests go to the correct server. This is done by adding NS record to blogsite.org DNS zone.

Then you should create a CNAME record for _acme-challenge.eknori.spdns.org pointing to the fulldomain returned by acme-dns registration. After this, when Let's Encrypt sends DNS request for _acme-challenge.eknori.spdns.org it will follow the CNAME to fulldomain, of which acme-dns will be the authoritative DNS server for. So the TXT record request will be resolved by acme-dns.

<!-- gh-comment-id:348769435 --> @joohoi commented on GitHub (Dec 3, 2017): You will need to make acme-dns the authoritative name server for `eknori.blogsite.org` in order to make DNS requests go to the correct server. This is done by adding `NS` record to blogsite.org DNS zone. Then you should create a `CNAME` record for `_acme-challenge.eknori.spdns.org` pointing to the `fulldomain` returned by acme-dns registration. After this, when Let's Encrypt sends DNS request for `_acme-challenge.eknori.spdns.org` it will follow the CNAME to `fulldomain`, of which acme-dns will be the authoritative DNS server for. So the `TXT` record request will be resolved by acme-dns.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/acme-dns#6
No description provided.