tobiasschuerg / InfluxDB-Client-for-Arduino

Simple library for sending measurements to an InfluxDB with a single network request. Supports ESP8266 and ESP32.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot pass HTTP Basic Auth

danepowell opened this issue · comments

Steps to reproduce:

  1. Put your InfluxDB HTTP API behind basic auth with u/n "username" and p/w "p@ssword"
  2. #define INFLUXDB_URL "https://username:p%40ssword@influxdb.example.com"

Expected behavior:
Arduino client successfully connects to InfluxDB

Actual behavior:
Arduino client receives 401 Unauthorized

However, if I curl https://username:p%40ssword@influxdb.example.com from any other device it works fine.

I suspect that the special characters encoded in the basic auth creds are the problem, but I haven't tried a password without special chars, it's possible that http basic auth doesn't work at all.

Specifications:

  • Library Version: 3.10.0
  • InfluxDB Version: 2.0.9
  • Board/ESP chip: Wemos D1 Mini
  • Device Arduino SDK version:

I don't have such a setup available, so I cannot reproduce this. Could you, please, enable debug in src/InfluxDbClient.cpp and src/HTTPService.cpp and paste log here?

Just for information, why HTTP basic on a proxy? InfluxDB server has its own authentication.

Debug logs, not very interesting I'm afraid:

15.448 [D] Init
15.448 [D]  Library version: 3.10.0
15.448 [D]  Device : ESP8266
15.449 [D]  SDK version: 3.0.2
15.480 [D]  Server url: https://username:p%40ssword@influxdb.example.com
15.573 [D]  Org: example.com
15.615 [D]  Bucket: iot
15.640 [D]  Token: [snip]
15.753 [D]  DB version: 2
15.868 [D] probeMaxFragmentLength to influxdb.example.com:443
16.001 [D]  MFLN:no
16.002 [D] setUrls
16.003 [D]  writeUrl: https://username:p%40ssword@influxdb.example.com/api/v2/write?org=example.com&bucket=iot
16.054 [D]  queryUrl: https://username:p%40ssword@influxdb.example.com/api/v2/query?org=example.com
16.188 [D] Validating connection to https://username:p%40ssword@influxdb.example.com/health
16.300 [D] GET request - https://username:p%40ssword@influxdb.example.com/health
19.151 [D] Response:
Unauthorized

19.152 [D] error 401: Unauthorized

InfluxDB connection failed: Unauthorized

As to why HTTP auth, it's defense in depth. As a matter of policy, I keep all public-facing services behind HTTP auth using a Traefik middleware.

Interesting, if I remove the special characters from the password the error changes from a 401 to a 302, and also notice that the u/n and p/w have been stripped from the URL, indicating (I suppose) that it passed authentication but choked on the 302.

Looking at HTTPClient, I see what might be happening... I think the client is taking my authToken and setting it as the Authorization header, even though InfluxDB itself doesn't use HTTP auth. I need a way to make the Authorization header different from the authToken.

16.765 [D] Init
16.766 [D] Library version: 3.10.0
16.766 [D] Device : ESP8266
16.766 [D] SDK version: 3.0.2
16.798 [D] Server url: https://username:password@influxdb.example.com
16.905 [D] Org: example.com
16.948 [D] Bucket: iot
16.973 [D] Token: [snip]
17.085 [D] DB version: 2
17.200 [D] probeMaxFragmentLength to influxdb.example.com:443
17.305 [D] MFLN:no
17.306 [D] setUrls
17.307 [D] writeUrl: https://username:password@influxdb.example.com/api/v2/write?org=example.com&bucket=iot
17.390 [D] queryUrl: https://username:password@influxdb.example.com/api/v2/query?org=example.com
17.537 [D] Validating connection to https://username:password@influxdb.daenerys.danepowell.com/health
17.664 [D] GET request - https://username:password@influxdb.example.com/health
20.568 [D] Response:
<a href="https://influxdb.example.com:443/health">Found</a>.

20.570 [D] error 302: <a href="https://influxdb.example.com:443/health">Found</a>.

InfluxDB connection failed: <a href="https://influxdb.example.com:443/health">Found</a>.

Exactly. HTTPClient rewrites the authorization header set by the library using provided token, which is required by InfluxDB.

You can set multiple comma separated values for the authorization header. That's what curl does, and it works great with InfluxDB behind basic auth.

Ok, It should be done in the HTTPClient. For a quick fix, it will require workaround in this library. Any PR is welcome :-)

Any PR is welcome

Understood, I'll try to carve out some time for this

I've tried curl, Go and NodeJS (axios) and no one of those write two values of Authorization header. If curl command contains Authorization header, it ignores HTTP basic credentials in the URL.

Go and NodeJS(axios) behave the same as ESP HTTP Client, which means it rewrites Authorization header with basic credentials.

So, passing more Authorization values doesn't seem it should be supported.

The solution could be either allowing custom pre-request callback or setting custom headers.

Given the complexities, I've decided to accept this as a risk for now and just disable the ForwardAuth (HTTP basic auth) middleware. I might circle back to this in the future if I have time. Thanks for the help.

Have you tried if two Authorizations values work ok in your setup? E.g. using curl? I'm open to adding a feature to allow customization of the HTTP requests. This is part of most communication libraries.

Thanks for prodding me on this, I've been doing some digging and learned a lot in the process.

I think multiple headers would work, especially since one is a Basic auth and the other is Token auth, so they shouldn't conflict from the server's point of view. I've been able to verify this in curl, e.g.:

curl https://influxdb.example.com/api/v2/query?org=example.com -H "authorization: Token <influx-token>" -H "authorization: Basic <http-auth-token>"

Here's the problem though: I still doubt this would work for me because of a new problem I discovered. My basic auth provider relies on setting a cookie for SSO. If the InfluxDB client can't accept that cookie, it will endlessly redirect. I assume the InfluxDB client doesn't handle cookies?

No. InfluxDB Client is implemented to communicate directly with an InfluxDB Server or InfluxDB Cloud, which doesn't send cookies.

This could be solved by the customization of HTTP requests and responses. However, there is no cookie-related API in the ESPxx HTTP Client, so it would need to be handled manually by setting and reading HTTP headers and custom cookie storage.

Makes sense, I wouldn't expect an embedded HTTP client to be stateful or support cookies. So there's no value to me in pursuing this issue. But hopefully if anyone else comes along needing HTTP auth support, we have this research as reference 😄 Thanks again for your time and great library.