use of com.couchbase.client.core.env.SaslMechanism in project couchbase-jvm-clients by couchbase.
the class SaslListMechanismsHandlerTest method decodesSuccessfulSaslMechsList.
@Test
void decodesSuccessfulSaslMechsList() {
SaslListMechanismsHandler handler = new SaslListMechanismsHandler(endpointContext);
channel.pipeline().addLast(handler);
assertEquals(handler, channel.pipeline().get(SaslListMechanismsHandler.class));
ChannelFuture connectFuture = channel.connect(new InetSocketAddress("1.2.3.4", 1234));
assertFalse(connectFuture.isDone());
channel.pipeline().fireChannelActive();
channel.runPendingTasks();
ByteBuf writtenRequest = channel.readOutbound();
verifyRequest(writtenRequest, MemcacheProtocol.Opcode.SASL_LIST_MECHS.opcode(), false, false, false);
assertNotNull(channel.pipeline().get(SaslListMechanismsHandler.class));
ReferenceCountUtil.release(writtenRequest);
ByteBuf response = decodeHexDump(readResource("success_sasl_list_mechs_response.txt", ErrorMapLoadingHandlerTest.class));
channel.writeInbound(response);
channel.runPendingTasks();
assertTrue(connectFuture.isSuccess());
Set<SaslMechanism> saslMechanisms = channel.attr(ChannelAttributes.SASL_MECHS_KEY).get();
assertEquals(saslMechanisms, EnumSet.of(SaslMechanism.PLAIN, SaslMechanism.SCRAM_SHA1, SaslMechanism.SCRAM_SHA256, SaslMechanism.SCRAM_SHA512));
assertTrue(eventBus.publishedEvents().get(0) instanceof SaslMechanismsListedEvent);
}
use of com.couchbase.client.core.env.SaslMechanism in project couchbase-jvm-clients by couchbase.
the class SaslAuthenticationHandler method maybeFailConnect.
/**
* Check if we need to do an auth retry with different mechs instead of giving up immediately.
* <p>
* The method performs the logic roughly as follows: we know that the current authentication attempt failed, but
* because we are pipelining the original auth request with our allowed list it could be that they do not overlap
* (i.e. only PLAIN is allowed because the server has LDAP enabled but we do not negotiate it by default), so give
* it another chance to run with the updated and merged mechs list. If it still fails the next time it will terminate
* eventually.
* <p>
* Most of the time though it will fail immediately since the mechs are aligned and the user just entered the
* wrong credentials.
*/
private void maybeFailConnect(final ChannelHandlerContext ctx, final String message, final ByteBuf lastPacket, final Throwable cause, final short status) {
final SaslMechanism currentlyUsedMech = SaslMechanism.from(saslClient.getMechanismName());
final Set<SaslMechanism> negotiatedMechs = ctx.channel().attr(ChannelAttributes.SASL_MECHS_KEY).get();
if (negotiatedMechs.contains(currentlyUsedMech)) {
failConnect(ctx, message, lastPacket, cause, status);
} else {
Set<SaslMechanism> mergedMechs = allowedMechanisms.stream().filter(negotiatedMechs::contains).collect(Collectors.toSet());
if (mergedMechs.isEmpty()) {
failConnect(ctx, "Could not negotiate SASL mechanism with server. If you are using LDAP you must either" + "connect via TLS (recommended), or ONLY enable PLAIN in the allowed SASL mechanisms list on the PasswordAuthenticator" + "(this is insecure and will present the user credentials in plain-text over the wire).", lastPacket, cause, status);
} else {
ioContext.environment().eventBus().publish(new SaslAuthenticationRestartedEvent(ioContext));
startAuthSequence(ctx, mergedMechs);
}
}
}
use of com.couchbase.client.core.env.SaslMechanism in project couchbase-jvm-clients by couchbase.
the class SaslAuthenticationHandler method startAuthSequence.
/**
* Starts the SASL auth sequence with the set of mechanisms that are valid for this specific run.
*
* @param ctx the channel handler context
* @param usedMechanisms the mechanisms that can be used during this run
*/
private void startAuthSequence(final ChannelHandlerContext ctx, final Set<SaslMechanism> usedMechanisms) {
try {
saslClient = createSaslClient(usedMechanisms);
SaslMechanism selectedMechanism = SaslMechanism.from(saslClient.getMechanismName());
roundtripsToGo = selectedMechanism.roundtrips();
endpointContext.environment().eventBus().publish(new SaslMechanismsSelectedEvent(ioContext, usedMechanisms, selectedMechanism));
ctx.writeAndFlush(buildAuthRequest(ctx));
maybePropagateChannelActive(ctx);
} catch (SaslException e) {
failConnect(ctx, "SASL Client could not be constructed", null, e, (short) 0);
}
}
use of com.couchbase.client.core.env.SaslMechanism in project couchbase-jvm-clients by couchbase.
the class SaslListMechanismsHandler method channelRead.
/**
* As soon as we get a response, turn it into a list of SASL mechanisms the server supports.
* <p>
* If the server responds with an empty list this is an issue and as a result we need to fail the connection
* immediately.
*
* @param ctx the {@link ChannelHandlerContext} for which the channel read operation is made.
* @param msg the incoming msg that needs to be parsed.
*/
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
if (msg instanceof ByteBuf) {
Optional<Duration> latency = ConnectTimings.stop(ctx.channel(), this.getClass(), false);
if (successful((ByteBuf) msg)) {
String[] rawMechansisms = body((ByteBuf) msg).orElse(Unpooled.EMPTY_BUFFER).toString(UTF_8).split(" ");
boolean isEmpty = rawMechansisms.length == 1 && rawMechansisms[0].isEmpty();
if (rawMechansisms.length > 0 && !isEmpty) {
final Set<SaslMechanism> serverMechanisms = decodeMechanisms(rawMechansisms);
ioContext.environment().eventBus().publish(new SaslMechanismsListedEvent(ioContext, serverMechanisms, latency.orElse(Duration.ZERO)));
ctx.channel().attr(ChannelAttributes.SASL_MECHS_KEY).set(serverMechanisms);
interceptedConnectPromise.trySuccess();
ctx.pipeline().remove(this);
} else {
failConnection("Received empty mechanism list from server", status((ByteBuf) msg), latency);
}
} else {
failConnection("Received non-success status from server", status((ByteBuf) msg), latency);
}
} else {
interceptedConnectPromise.tryFailure(new CouchbaseException("Unexpected response " + "type on channel read, this is a bug - please report. " + msg));
}
ReferenceCountUtil.release(msg);
}
use of com.couchbase.client.core.env.SaslMechanism in project couchbase-jvm-clients by couchbase.
the class SaslListMechanismsHandlerTest method ignoresUnknownSaslMech.
@Test
void ignoresUnknownSaslMech() {
SaslListMechanismsHandler handler = new SaslListMechanismsHandler(endpointContext);
channel.pipeline().addLast(handler);
assertEquals(handler, channel.pipeline().get(SaslListMechanismsHandler.class));
ChannelFuture connectFuture = channel.connect(new InetSocketAddress("1.2.3.4", 1234));
assertFalse(connectFuture.isDone());
channel.pipeline().fireChannelActive();
channel.runPendingTasks();
ByteBuf writtenRequest = channel.readOutbound();
verifyRequest(writtenRequest, MemcacheProtocol.Opcode.SASL_LIST_MECHS.opcode(), false, false, false);
assertNotNull(channel.pipeline().get(SaslListMechanismsHandler.class));
ReferenceCountUtil.release(writtenRequest);
ByteBuf response = decodeHexDump(readResource("success_sasl_list_mechs_unknown_mech_response.txt", ErrorMapLoadingHandlerTest.class));
channel.writeInbound(response);
channel.runPendingTasks();
assertTrue(connectFuture.isSuccess());
Set<SaslMechanism> saslMechanisms = channel.attr(ChannelAttributes.SASL_MECHS_KEY).get();
assertEquals(saslMechanisms, EnumSet.of(SaslMechanism.SCRAM_SHA1, SaslMechanism.SCRAM_SHA256, SaslMechanism.SCRAM_SHA512));
UnknownSaslMechanismDetectedEvent event = (UnknownSaslMechanismDetectedEvent) eventBus.publishedEvents().get(0);
assertEquals("FLAUN", event.mechanism());
}
Aggregations