Skip to content

Commit ab8db41

Browse files
committed
Feat: support authentication
Signed-off-by: Evgeny Malygin <emalygin@bloomberg.net>
1 parent 5b2af47 commit ab8db41

27 files changed

Lines changed: 993 additions & 72 deletions

bmq-examples/src/main/java/com/bloomberg/bmq/examples/InteractiveConsumer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package com.bloomberg.bmq.examples;
1717

1818
import com.bloomberg.bmq.AbstractSession;
19+
import com.bloomberg.bmq.AuthnCredential;
20+
import com.bloomberg.bmq.AuthnCredentialResult;
1921
import com.bloomberg.bmq.BMQException;
2022
import com.bloomberg.bmq.MessageProperty;
2123
import com.bloomberg.bmq.PushMessage;
@@ -178,7 +180,16 @@ public void run() {
178180

179181
session =
180182
new Session(
181-
SessionOptions.builder().setBrokerUri(URI.create(brokerUri)).build(),
183+
SessionOptions.builder()
184+
.setBrokerUri(URI.create(brokerUri))
185+
.setAuthnCredentialCb(
186+
() ->
187+
AuthnCredentialResult.success(
188+
AuthnCredential.builder()
189+
.setMechanism("ANONYMOUS")
190+
.setData(new byte[0])
191+
.build()))
192+
.build(),
182193
this); // SessionEventHandler
183194

184195
logger.info("Starting the session with a timeout of 15 seconds");

bmq-examples/src/main/java/com/bloomberg/bmq/examples/InteractiveProducer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import com.bloomberg.bmq.AbstractSession;
1919
import com.bloomberg.bmq.AckMessage;
2020
import com.bloomberg.bmq.AckMessageHandler;
21+
import com.bloomberg.bmq.AuthnCredential;
22+
import com.bloomberg.bmq.AuthnCredentialResult;
2123
import com.bloomberg.bmq.BMQException;
2224
import com.bloomberg.bmq.CompressionAlgorithm;
2325
import com.bloomberg.bmq.CorrelationId;
@@ -161,7 +163,16 @@ public void run() {
161163

162164
session =
163165
new Session(
164-
SessionOptions.builder().setBrokerUri(URI.create(brokerUri)).build(),
166+
SessionOptions.builder()
167+
.setBrokerUri(URI.create(brokerUri))
168+
.setAuthnCredentialCb(
169+
() ->
170+
AuthnCredentialResult.success(
171+
AuthnCredential.builder()
172+
.setMechanism("ANONYMOUS")
173+
.setData(new byte[0])
174+
.build()))
175+
.build(),
165176
this); // SessionEventHandler
166177

167178
logger.info("Starting the session with a timeout of 15 seconds");

bmq-examples/src/main/java/com/bloomberg/bmq/examples/SimpleConsumer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package com.bloomberg.bmq.examples;
1717

1818
import com.bloomberg.bmq.AbstractSession;
19+
import com.bloomberg.bmq.AuthnCredential;
20+
import com.bloomberg.bmq.AuthnCredentialResult;
1921
import com.bloomberg.bmq.PushMessage;
2022
import com.bloomberg.bmq.Queue;
2123
import com.bloomberg.bmq.QueueFlags;
@@ -97,7 +99,16 @@ public static void main(String[] args) throws InterruptedException {
9799
}
98100

99101
final SessionOptions sessionOptions =
100-
SessionOptions.builder().setBrokerUri(URI.create(brokerUri)).build();
102+
SessionOptions.builder()
103+
.setBrokerUri(URI.create(brokerUri))
104+
.setAuthnCredentialCb(
105+
() ->
106+
AuthnCredentialResult.success(
107+
AuthnCredential.builder()
108+
.setMechanism("ANONYMOUS")
109+
.setData(new byte[0])
110+
.build()))
111+
.build();
101112
final AbstractSession session = new Session(sessionOptions, event -> {});
102113

103114
final BlockingQueue<String> receivedMessages = new LinkedBlockingQueue<>();

bmq-examples/src/main/java/com/bloomberg/bmq/examples/SimpleProducer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package com.bloomberg.bmq.examples;
1717

1818
import com.bloomberg.bmq.AbstractSession;
19+
import com.bloomberg.bmq.AuthnCredential;
20+
import com.bloomberg.bmq.AuthnCredentialResult;
1921
import com.bloomberg.bmq.PutMessage;
2022
import com.bloomberg.bmq.Queue;
2123
import com.bloomberg.bmq.QueueFlags;
@@ -72,7 +74,16 @@ public static void main(String[] args) {
7274
}
7375

7476
final SessionOptions sessionOptions =
75-
SessionOptions.builder().setBrokerUri(URI.create(brokerUri)).build();
77+
SessionOptions.builder()
78+
.setBrokerUri(URI.create(brokerUri))
79+
.setAuthnCredentialCb(
80+
() ->
81+
AuthnCredentialResult.success(
82+
AuthnCredential.builder()
83+
.setMechanism("ANONYMOUS")
84+
.setData(new byte[0])
85+
.build()))
86+
.build();
7687
final AbstractSession session = new Session(sessionOptions, event -> {});
7788

7889
try {

bmq-examples/src/main/java/com/bloomberg/bmq/examples/SubscriptionsConsumer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
package com.bloomberg.bmq.examples;
1717

1818
import com.bloomberg.bmq.AbstractSession;
19+
import com.bloomberg.bmq.AuthnCredential;
20+
import com.bloomberg.bmq.AuthnCredentialResult;
1921
import com.bloomberg.bmq.BMQException;
2022
import com.bloomberg.bmq.MessageProperty;
2123
import com.bloomberg.bmq.PushMessage;
@@ -181,7 +183,16 @@ public void run() {
181183

182184
session =
183185
new Session(
184-
SessionOptions.builder().setBrokerUri(URI.create(brokerUri)).build(),
186+
SessionOptions.builder()
187+
.setBrokerUri(URI.create(brokerUri))
188+
.setAuthnCredentialCb(
189+
() ->
190+
AuthnCredentialResult.success(
191+
AuthnCredential.builder()
192+
.setMechanism("ANONYMOUS")
193+
.setData(new byte[0])
194+
.build()))
195+
.build(),
185196
this); // SessionEventHandler
186197

187198
logger.info("Starting the session with a timeout of 15 seconds");

bmq-examples/src/main/java/com/bloomberg/bmq/examples/SubscriptionsProducer.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import com.bloomberg.bmq.AbstractSession;
1919
import com.bloomberg.bmq.AckMessage;
2020
import com.bloomberg.bmq.AckMessageHandler;
21+
import com.bloomberg.bmq.AuthnCredential;
22+
import com.bloomberg.bmq.AuthnCredentialResult;
2123
import com.bloomberg.bmq.BMQException;
2224
import com.bloomberg.bmq.CompressionAlgorithm;
2325
import com.bloomberg.bmq.CorrelationId;
@@ -168,7 +170,16 @@ public void run() {
168170

169171
session =
170172
new Session(
171-
SessionOptions.builder().setBrokerUri(URI.create(brokerUri)).build(),
173+
SessionOptions.builder()
174+
.setBrokerUri(URI.create(brokerUri))
175+
.setAuthnCredentialCb(
176+
() ->
177+
AuthnCredentialResult.success(
178+
AuthnCredential.builder()
179+
.setMechanism("ANONYMOUS")
180+
.setData(new byte[0])
181+
.build()))
182+
.build(),
172183
this); // SessionEventHandler
173184

174185
logger.info("Starting the session with a timeout of 15 seconds");
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*
2+
* Copyright 2026 Bloomberg Finance L.P.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* 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+
package com.bloomberg.bmq;
17+
18+
import com.bloomberg.bmq.impl.infr.util.Argument;
19+
import java.util.Arrays;
20+
import javax.annotation.concurrent.Immutable;
21+
22+
/**
23+
* A value-semantic type representing authentication credentials for a broker session.
24+
*
25+
* <p>An {@code AuthnCredential} consists of an authentication mechanism name and optional
26+
* authentication data. It is used to configure credentials on a {@link SessionOptions} for
27+
* authenticating with the broker during session initiation.
28+
*
29+
* <H2>Thread Safety</H2>
30+
*
31+
* Once created, an {@code AuthnCredential} object is immutable and thread safe. A {@code Builder}
32+
* is provided for construction.
33+
*
34+
* <H2>Usage Example</H2>
35+
*
36+
* <pre>
37+
*
38+
* AuthnCredential credential = AuthnCredential.builder()
39+
* .setMechanism("OAUTH2")
40+
* .setData(tokenBytes)
41+
* .build();
42+
* </pre>
43+
*/
44+
@Immutable
45+
public final class AuthnCredential {
46+
47+
private final String mechanism;
48+
private final byte[] data;
49+
50+
private AuthnCredential() {
51+
mechanism = "";
52+
data = null;
53+
}
54+
55+
private AuthnCredential(Builder builder) {
56+
mechanism = builder.mechanism;
57+
data = builder.data != null ? Arrays.copyOf(builder.data, builder.data.length) : null;
58+
}
59+
60+
/**
61+
* Creates an {@code AuthnCredential} with default values (empty mechanism, no data).
62+
*
63+
* @return AuthnCredential credential with default values
64+
*/
65+
public static AuthnCredential createDefault() {
66+
return new AuthnCredential();
67+
}
68+
69+
/**
70+
* Returns a helper class object to create an immutable {@code AuthnCredential} with custom
71+
* settings.
72+
*
73+
* @return Builder a helper class object to create an immutable {@code AuthnCredential}
74+
*/
75+
public static Builder builder() {
76+
return new Builder();
77+
}
78+
79+
/**
80+
* Returns a helper class object initialized with values from the specified {@code credential}.
81+
*
82+
* @param credential specifies credential which initializes the builder
83+
* @return Builder a helper class object to create an immutable {@code AuthnCredential}
84+
*/
85+
public static Builder builder(AuthnCredential credential) {
86+
Argument.expectNonNull(credential, "credential");
87+
return new Builder(credential);
88+
}
89+
90+
/**
91+
* Returns the authentication mechanism.
92+
*
93+
* @return String authentication mechanism
94+
*/
95+
public String mechanism() {
96+
return mechanism;
97+
}
98+
99+
/**
100+
* Returns the authentication data, or null if not set.
101+
*
102+
* @return byte array of authentication data, or null
103+
*/
104+
public byte[] data() {
105+
return data != null ? Arrays.copyOf(data, data.length) : null;
106+
}
107+
108+
@Override
109+
public boolean equals(Object obj) {
110+
if (obj == this) return true;
111+
if (!(obj instanceof AuthnCredential)) return false;
112+
AuthnCredential other = (AuthnCredential) obj;
113+
return mechanism.equals(other.mechanism) && Arrays.equals(data, other.data);
114+
}
115+
116+
@Override
117+
public int hashCode() {
118+
int result = mechanism.hashCode();
119+
result = 31 * result + Arrays.hashCode(data);
120+
return result;
121+
}
122+
123+
@Override
124+
public String toString() {
125+
StringBuilder sb = new StringBuilder();
126+
sb.append("[ mechanism: ")
127+
.append(mechanism)
128+
.append(", data: ")
129+
.append(data != null ? "<" + data.length + " bytes>" : "null")
130+
.append(" ]");
131+
return sb.toString();
132+
}
133+
134+
/** A helper class to create an immutable {@code AuthnCredential} with custom settings. */
135+
public static class Builder {
136+
137+
private String mechanism;
138+
private byte[] data;
139+
140+
private Builder() {
141+
mechanism = "";
142+
data = null;
143+
}
144+
145+
private Builder(AuthnCredential credential) {
146+
mechanism = credential.mechanism;
147+
data =
148+
credential.data != null
149+
? Arrays.copyOf(credential.data, credential.data.length)
150+
: null;
151+
}
152+
153+
/**
154+
* Creates an {@code AuthnCredential} object based on this builder's properties.
155+
*
156+
* @return AuthnCredential immutable credential object
157+
*/
158+
public AuthnCredential build() {
159+
return new AuthnCredential(this);
160+
}
161+
162+
/**
163+
* Sets the authentication mechanism.
164+
*
165+
* @param value authentication mechanism
166+
* @return Builder this object
167+
* @throws NullPointerException if the specified value is null
168+
*/
169+
public Builder setMechanism(String value) {
170+
mechanism = Argument.expectNonNull(value, "mechanism");
171+
return this;
172+
}
173+
174+
/**
175+
* Sets the authentication data.
176+
*
177+
* @param value authentication data, may be null
178+
* @return Builder this object
179+
*/
180+
public Builder setData(byte[] value) {
181+
data = value != null ? Arrays.copyOf(value, value.length) : null;
182+
return this;
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)