Skip to content

Commit

Permalink
add support for loading a customAuthenticator class #1001 - needs cli…
Browse files Browse the repository at this point in the history
…ent_java 1.4 (#1002)

Signed-off-by: Gary Tully <[email protected]>
  • Loading branch information
gtully authored Oct 20, 2024
1 parent a3b9443 commit 8c99d4a
Show file tree
Hide file tree
Showing 10 changed files with 557 additions and 87 deletions.
22 changes: 22 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,28 @@ httpServer:

---

### Java agent use of a custom com.sun.net.httpserver.Authenticator class
It is possible to provide a custom Authenticator implementation for the Java agent.
The custom class needs to be on the jvm classpath.
The class name to load is provided through `authentication/customAuthenticator` configuration as follows:

```yaml
httpServer:
authentication:
customAuthenticator:
authenticatorClass: my.custom.AuthenticatorWithNoArgConstructor
```
If the custom authenticatorClass needs to provide an authenticated Subject visible to the application, it can set a named attribute on the HttpExchange with that subject. The agent will arrange that subsequent calls occur in a Subject.doAs().
The name of the attributed must be provided through `subjectAttributeName` configuration as follows:
```yaml
httpServer:
authentication:
customAuthenticator:
authenticatorClass: my.custom.AuthenticatorWithNoArgConstructorThatSetsASubjectAttribute
subjectAttributeName: "custom.subject.for.doAs");
```


## HTTPS support (optional)

HTTPS support can be configured using either a JKS or PKCS12 format keystore via two possible methods:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2023 The Prometheus jmx_exporter Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.prometheus.jmx.test.http.authentication;

import io.prometheus.jmx.test.common.AbstractExporterTest;
import io.prometheus.jmx.test.common.ExporterTestEnvironment;
import io.prometheus.jmx.test.support.JmxExporterMode;
import java.util.stream.Stream;
import org.antublue.verifyica.api.Verifyica;

public class AuthenticatorClassTest extends BasicAuthenticationPlaintextTest {

@Verifyica.ArgumentSupplier
public static Stream<ExporterTestEnvironment> arguments() {
// custom authenticator class is only on the agent classpath
return AbstractExporterTest.arguments()
.filter(
exporterTestEnvironment ->
exporterTestEnvironment
.getName()
.contains(JmxExporterMode.JavaAgent.name()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

java \
-Xmx512M \
-javaagent:jmx_prometheus_javaagent.jar=8888:exporter.yaml \
-jar jmx_example_application.jar
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
httpServer:
authentication:
customAuthenticator:
authenticatorClass: io.prometheus.jmx.CustomAuthenticator
subjectAttributeName: io.prometheus.jmx.CustomAuthenticatorSubjectAttribute
rules:
- pattern: ".*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.prometheus.jmx;

import com.sun.net.httpserver.Authenticator;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpPrincipal;
import com.sun.security.auth.UserPrincipal;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.security.auth.Subject;

public class CustomAuthenticator extends Authenticator {

@Override
public Result authenticate(HttpExchange exch) {
// nothing too custom, so the test works, just to demonstrate that it is plug-able
Headers rmap = exch.getRequestHeaders();
String auth = rmap.getFirst("Authorization");
if (auth == null) {
return new Authenticator.Retry(401);
}
int sp = auth.indexOf(' ');
if (sp == -1 || !auth.substring(0, sp).equals("Basic")) {
return new Authenticator.Failure(401);
}
byte[] b = Base64.getDecoder().decode(auth.substring(sp + 1));
String userpass = new String(b, StandardCharsets.UTF_8);
int colon = userpass.indexOf(':');
String uname = userpass.substring(0, colon);
String pass = userpass.substring(colon + 1);

if ("Prometheus".equals(uname) && "secret".equals(pass)) {
Subject subject = new Subject();
subject.getPrincipals().add(new UserPrincipal(uname));
// to communicate an authenticated subject for subsequent handler calls via Subject.doAs
exch.setAttribute("io.prometheus.jmx.CustomAuthenticatorSubjectAttribute", subject);
return new Authenticator.Success(new HttpPrincipal(uname, "/"));
} else {
return new Authenticator.Failure(401);
}
}
}
Loading

0 comments on commit 8c99d4a

Please sign in to comment.