Skip to content

Commit 46927cc

Browse files
committed
login
1 parent 8d7d40f commit 46927cc

File tree

5 files changed

+187
-1
lines changed

5 files changed

+187
-1
lines changed

src/main/java/org/apache/skywalking/banyandb/v1/client/BanyanDBClient.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.common.base.Strings;
2424
import com.google.protobuf.Timestamp;
2525
import io.grpc.Channel;
26+
import io.grpc.ClientInterceptors;
2627
import io.grpc.ManagedChannel;
2728
import io.grpc.Status;
2829
import io.grpc.stub.StreamObserver;
@@ -51,6 +52,7 @@
5152
import org.apache.skywalking.banyandb.measure.v1.MeasureServiceGrpc;
5253
import org.apache.skywalking.banyandb.stream.v1.BanyandbStream;
5354
import org.apache.skywalking.banyandb.stream.v1.StreamServiceGrpc;
55+
import org.apache.skywalking.banyandb.v1.client.auth.AuthInterceptor;
5456
import org.apache.skywalking.banyandb.v1.client.grpc.HandleExceptionsWith;
5557
import org.apache.skywalking.banyandb.v1.client.grpc.channel.ChannelManager;
5658
import org.apache.skywalking.banyandb.v1.client.grpc.channel.DefaultChannelFactory;
@@ -183,8 +185,18 @@ public void connect() throws IOException {
183185
for (int i = 0; i < this.targets.length; i++) {
184186
addresses[i] = URI.create("//" + this.targets[i]);
185187
}
186-
this.channel = ChannelManager.create(this.options.buildChannelManagerSettings(),
188+
Channel rawChannel = ChannelManager.create(this.options.buildChannelManagerSettings(),
187189
new DefaultChannelFactory(addresses, this.options));
190+
Channel interceptedChannel = rawChannel;
191+
// register auth interceptor
192+
String username = options.getUsername();
193+
String password = options.getPassword();
194+
if (!"".equals(username) && !"".equals(password)) {
195+
interceptedChannel = ClientInterceptors.intercept(rawChannel,
196+
new AuthInterceptor(options.getUsername(), options.getPassword()));
197+
}
198+
// Ensure this.channel is assigned only once.
199+
this.channel = interceptedChannel;
188200
streamServiceBlockingStub = StreamServiceGrpc.newBlockingStub(this.channel);
189201
measureServiceBlockingStub = MeasureServiceGrpc.newBlockingStub(this.channel);
190202
streamServiceStub = StreamServiceGrpc.newStub(this.channel);

src/main/java/org/apache/skywalking/banyandb/v1/client/Options.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ public class Options {
6363
* SSL: Cert Key Path, BanyanDB server not support mTLS yet
6464
*/
6565
private String sslKeyPath = "";
66+
/**
67+
* Basic Auth: username of BanyanDB server
68+
*/
69+
private String username = "";
70+
/**
71+
* Basic Auth: password of BanyanDB server
72+
*/
73+
private String password = "";
6674

6775
public Options() {
6876
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.banyandb.v1.client.auth;
20+
21+
import io.grpc.CallOptions;
22+
import io.grpc.Channel;
23+
import io.grpc.ClientCall;
24+
import io.grpc.ClientInterceptor;
25+
import io.grpc.ForwardingClientCall;
26+
import io.grpc.Metadata;
27+
import io.grpc.MethodDescriptor;
28+
29+
public class AuthInterceptor implements ClientInterceptor {
30+
private final String username;
31+
private final String password;
32+
33+
public AuthInterceptor(String username, String password) {
34+
this.username = username;
35+
this.password = password;
36+
}
37+
38+
@Override
39+
public <REQ_T, RESP_T> ClientCall<REQ_T, RESP_T> interceptCall(
40+
MethodDescriptor<REQ_T, RESP_T> method,
41+
CallOptions callOptions,
42+
Channel next) {
43+
44+
return new ForwardingClientCall.SimpleForwardingClientCall<REQ_T, RESP_T>(
45+
next.newCall(method, callOptions)) {
46+
@Override
47+
public void start(Listener<RESP_T> responseListener, Metadata headers) {
48+
Metadata.Key<String> usernameKey = Metadata.Key.of("username", Metadata.ASCII_STRING_MARSHALLER);
49+
Metadata.Key<String> passwordKey = Metadata.Key.of("password", Metadata.ASCII_STRING_MARSHALLER);
50+
51+
headers.put(usernameKey, username);
52+
headers.put(passwordKey, password);
53+
54+
super.start(responseListener, headers);
55+
}
56+
};
57+
}
58+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.banyandb.v1.client;
20+
21+
import lombok.extern.slf4j.Slf4j;
22+
import org.apache.skywalking.banyandb.common.v1.BanyandbCommon;
23+
import org.apache.skywalking.banyandb.v1.client.grpc.exception.BanyanDBException;
24+
import org.apache.skywalking.banyandb.v1.client.grpc.exception.UnauthenticatedException;
25+
import org.junit.Assert;
26+
import org.junit.Rule;
27+
import org.junit.Test;
28+
import org.testcontainers.containers.GenericContainer;
29+
import org.testcontainers.containers.wait.strategy.Wait;
30+
import org.testcontainers.utility.DockerImageName;
31+
import org.testcontainers.utility.MountableFile;
32+
33+
import java.io.IOException;
34+
import java.util.List;
35+
36+
import static org.junit.Assert.assertThrows;
37+
38+
@Slf4j
39+
public class BanyanDBAuthTest {
40+
private static final String REGISTRY = "ghcr.io";
41+
private static final String IMAGE_NAME = "apache/skywalking-banyandb";
42+
private static final String TAG = "42ec9df7457868926eb80157b36355d94fcd6bba";
43+
44+
private static final String IMAGE = REGISTRY + "/" + IMAGE_NAME + ":" + TAG;
45+
46+
protected static final int GRPC_PORT = 17912;
47+
protected static final int HTTP_PORT = 17913;
48+
49+
@Rule
50+
public GenericContainer<?> banyanDB = new GenericContainer<>(DockerImageName.parse(IMAGE))
51+
.withCopyFileToContainer(
52+
MountableFile.forClasspathResource("config.yaml"),
53+
"/tmp/bydb_server_config.yaml"
54+
)
55+
.withCommand("standalone",
56+
"--auth-config-file", "/tmp/bydb_server_config.yaml",
57+
"--enable-health-auth", "true"
58+
)
59+
.withExposedPorts(GRPC_PORT, HTTP_PORT)
60+
.waitingFor(Wait.forLogMessage(".*\"message\":\"Listening to\".*", 1));
61+
62+
@Test
63+
public void testAuthWithCorrect() throws BanyanDBException, IOException {
64+
BanyanDBClient client = createClient("admin", "123456");
65+
client.connect();
66+
// list all groups
67+
List<BanyandbCommon.Group> groupList = client.findGroups();
68+
Assert.assertEquals(1, groupList.size());
69+
Assert.assertEquals("_monitoring", groupList.get(0).getMetadata().getName());
70+
client.close();
71+
}
72+
73+
@Test
74+
public void testAuthWithWrong() throws IOException {
75+
BanyanDBClient client = createClient("admin", "123456" + "wrong");
76+
client.connect();
77+
assertThrows(UnauthenticatedException.class, client::getAPIVersion);
78+
client.close();
79+
}
80+
81+
private BanyanDBClient createClient(String username, String password) {
82+
Options options = new Options();
83+
options.setUsername(username);
84+
options.setPassword(password);
85+
String url = String.format("%s:%d", banyanDB.getHost(), banyanDB.getMappedPort(GRPC_PORT));
86+
return new BanyanDBClient(new String[]{url}, options);
87+
}
88+
}

src/test/resources/config.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
users:
17+
- username: admin
18+
password: 123456
19+
- username: test
20+
password: 123456

0 commit comments

Comments
 (0)