Skip to content

Commit 4a52c13

Browse files
bitsalbrian-brazil
authored andcommitted
Add basic auth push gateway (#398)
* Added ability to add authentication logic into pushgateway request. Added Basic Auth. implementation. Signed-off-by: bitsal <[email protected]>
1 parent 1140823 commit 4a52c13

File tree

6 files changed

+135
-3
lines changed

6 files changed

+135
-3
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,12 +568,35 @@ void executeBatchJob() throws Exception {
568568
}
569569
```
570570

571-
A separate registry is used, as the default registry may contain other metrics
571+
A separate registry is used, as the default registry may contain other metrics
572572
such as those from the Process Collector. See the
573573
[Pushgateway documentation](https://github.com/prometheus/pushgateway/blob/master/README.md)
574574
for more information.
575575

576576

577+
#### with Basic Auth
578+
```java
579+
PushGateway pushgateway = new PushGateway("127.0.0.1:9091");
580+
pushgateway.setConnectionFactory(new BasicAuthHttpConnectionFactory("my_user", "my_password"));
581+
```
582+
583+
#### with Custom Connection Preparation Logic
584+
```java
585+
PushGateway pushgateway = new PushGateway("127.0.0.1:9091");
586+
pushgateway.setConnectionFactory(new MyHttpConnectionFactory());
587+
```
588+
where
589+
```java
590+
class MyHttpConnectionFactory implements HttpConnectionFactory {
591+
@Override
592+
public HttpURLConnection create(String url) throws IOException {
593+
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
594+
// add any connection preparation logic you need
595+
return connection;
596+
}
597+
}
598+
```
599+
577600
## Bridges
578601

579602
It is also possible to expose metrics to systems other than Prometheus.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.prometheus.client.exporter;
2+
3+
import java.io.IOException;
4+
import java.io.UnsupportedEncodingException;
5+
import java.net.HttpURLConnection;
6+
import javax.xml.bind.DatatypeConverter;
7+
8+
public class BasicAuthHttpConnectionFactory implements HttpConnectionFactory {
9+
private final HttpConnectionFactory originConnectionFactory;
10+
private final String basicAuthHeader;
11+
12+
public BasicAuthHttpConnectionFactory(HttpConnectionFactory connectionFactory, String user, String password) {
13+
this.originConnectionFactory = connectionFactory;
14+
this.basicAuthHeader = encode(user, password);
15+
}
16+
17+
public BasicAuthHttpConnectionFactory(String user, String password) {
18+
this(new DefaultHttpConnectionFactory(), user, password);
19+
}
20+
21+
@Override
22+
public HttpURLConnection create(String url) throws IOException {
23+
HttpURLConnection connection = originConnectionFactory.create(url);
24+
connection.setRequestProperty("Authorization", basicAuthHeader);
25+
return connection;
26+
}
27+
28+
private String encode(String user, String password) {
29+
try {
30+
byte[] credentialsBytes = (user + ":" + password).getBytes("UTF-8");
31+
String encoded = DatatypeConverter.printBase64Binary(credentialsBytes);
32+
return String.format("Basic %s", encoded);
33+
} catch (UnsupportedEncodingException e) {
34+
throw new IllegalArgumentException(e);
35+
}
36+
}
37+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.prometheus.client.exporter;
2+
3+
import java.io.IOException;
4+
import java.net.HttpURLConnection;
5+
import java.net.URL;
6+
7+
public class DefaultHttpConnectionFactory implements HttpConnectionFactory {
8+
@Override
9+
public HttpURLConnection create(String url) throws IOException {
10+
return (HttpURLConnection) new URL(url).openConnection();
11+
}
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.prometheus.client.exporter;
2+
3+
import java.io.IOException;
4+
import java.net.HttpURLConnection;
5+
6+
public interface HttpConnectionFactory {
7+
HttpURLConnection create(String url) throws IOException;
8+
}

simpleclient_pushgateway/src/main/java/io/prometheus/client/exporter/PushGateway.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@
5555
*/
5656
public class PushGateway {
5757

58+
private static final int MILLISECONDS_PER_SECOND = 1000;
59+
5860
// Visible for testing.
5961
protected final String gatewayBaseURL;
6062

61-
private static final int MILLISECONDS_PER_SECOND = 1000;
63+
private HttpConnectionFactory connectionFactory = new DefaultHttpConnectionFactory();
64+
6265
/**
6366
* Construct a Pushgateway, with the given address.
6467
* <p>
@@ -79,6 +82,10 @@ public PushGateway(URL serverBaseURL) {
7982
.toString();
8083
}
8184

85+
public void setConnectionFactory(HttpConnectionFactory connectionFactory) {
86+
this.connectionFactory = connectionFactory;
87+
}
88+
8289
/**
8390
* Creates a URL instance from a String representation of a URL without throwing a checked exception.
8491
* Required because you can't wrap a call to another constructor in a try statement.
@@ -273,7 +280,7 @@ void doRequest(CollectorRegistry registry, String job, Map<String, String> group
273280
url += "/" + entry.getKey() + "/" + URLEncoder.encode(entry.getValue(), "UTF-8");
274281
}
275282
}
276-
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
283+
HttpURLConnection connection = connectionFactory.create(url);
277284
connection.setRequestProperty("Content-Type", TextFormat.CONTENT_TYPE_004);
278285
if (!method.equals("DELETE")) {
279286
connection.setDoOutput(true);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package io.prometheus.client.exporter;
2+
3+
4+
import static org.mockserver.model.HttpRequest.request;
5+
import static org.mockserver.model.HttpResponse.response;
6+
7+
import java.io.IOException;
8+
9+
import io.prometheus.client.CollectorRegistry;
10+
import io.prometheus.client.Gauge;
11+
import org.junit.Before;
12+
import org.junit.Rule;
13+
import org.junit.Test;
14+
import org.mockserver.client.server.MockServerClient;
15+
import org.mockserver.junit.MockServerRule;
16+
17+
public class BasicAuthPushGatewayTest {
18+
19+
@Rule
20+
public MockServerRule mockServerRule = new MockServerRule(this);
21+
private MockServerClient mockServerClient;
22+
23+
CollectorRegistry registry;
24+
Gauge gauge;
25+
PushGateway pushGateway;
26+
27+
@Before
28+
public void setUp() {
29+
registry = new CollectorRegistry();
30+
gauge = Gauge.build().name("g").help("help").create();
31+
pushGateway = new PushGateway("localhost:" + mockServerRule.getHttpPort());
32+
pushGateway.setConnectionFactory(new BasicAuthHttpConnectionFactory("testUser", "testPwd"));
33+
}
34+
35+
@Test
36+
public void testAuthorizedPush() throws IOException {
37+
mockServerClient.when(
38+
request()
39+
.withMethod("PUT")
40+
.withHeader("Authorization", "Basic dGVzdFVzZXI6dGVzdFB3ZA==")
41+
.withPath("/metrics/job/j")
42+
).respond(response().withStatusCode(202));
43+
pushGateway.push(registry, "j");
44+
}
45+
}

0 commit comments

Comments
 (0)