use of org.apache.pulsar.common.api.AuthData in project incubator-pulsar by apache.
the class ServerCnx method handleAuthResponse.
@Override
protected void handleAuthResponse(CommandAuthResponse authResponse) {
checkArgument(authResponse.hasResponse());
checkArgument(authResponse.getResponse().hasAuthData() && authResponse.getResponse().hasAuthMethodName());
pendingAuthChallengeResponse = false;
if (log.isDebugEnabled()) {
log.debug("Received AuthResponse from {}, auth method: {}", remoteAddress, authResponse.getResponse().getAuthMethodName());
}
try {
AuthData clientData = AuthData.of(authResponse.getResponse().getAuthData());
doAuthentication(clientData, authResponse.getProtocolVersion(), authResponse.getClientVersion());
} catch (AuthenticationException e) {
service.getPulsarStats().recordConnectionCreateFail();
log.warn("[{}] Authentication failed: {} ", remoteAddress, e.getMessage());
ctx.writeAndFlush(Commands.newError(-1, ServerError.AuthenticationError, e.getMessage()));
close();
} catch (Exception e) {
service.getPulsarStats().recordConnectionCreateFail();
String msg = "Unable to handleAuthResponse";
log.warn("[{}] {} ", remoteAddress, msg, e);
ctx.writeAndFlush(Commands.newError(-1, ServerError.UnknownError, msg));
close();
}
}
use of org.apache.pulsar.common.api.AuthData in project incubator-pulsar by apache.
the class ServerCnx method doAuthentication.
// According to auth result, send newConnected or newAuthChallenge command.
private State doAuthentication(AuthData clientData, int clientProtocolVersion, String clientVersion) throws Exception {
// The original auth state can only be set on subsequent auth attempts (and only
// in presence of a proxy and if the proxy is forwarding the credentials).
// In this case, the re-validation needs to be done against the original client
// credentials.
boolean useOriginalAuthState = (originalAuthState != null);
AuthenticationState authState = useOriginalAuthState ? originalAuthState : this.authState;
String authRole = useOriginalAuthState ? originalPrincipal : this.authRole;
AuthData brokerData = authState.authenticate(clientData);
if (log.isDebugEnabled()) {
log.debug("Authenticate using original auth state : {}, role = {}", useOriginalAuthState, authRole);
}
if (authState.isComplete()) {
// Authentication has completed. It was either:
// 1. the 1st time the authentication process was done, in which case we'll send
// a `CommandConnected` response
// 2. an authentication refresh, in which case we need to refresh authenticationData
String newAuthRole = authState.getAuthRole();
// Refresh the auth data.
this.authenticationData = authState.getAuthDataSource();
if (log.isDebugEnabled()) {
log.debug("[{}] Auth data refreshed for role={}", remoteAddress, this.authRole);
}
if (!useOriginalAuthState) {
this.authRole = newAuthRole;
}
if (log.isDebugEnabled()) {
log.debug("[{}] Client successfully authenticated with {} role {} and originalPrincipal {}", remoteAddress, authMethod, this.authRole, originalPrincipal);
}
if (state != State.Connected) {
// First time authentication is done
completeConnect(clientProtocolVersion, clientVersion);
} else {
// If the connection was already ready, it means we're doing a refresh
if (!StringUtils.isEmpty(authRole)) {
if (!authRole.equals(newAuthRole)) {
log.warn("[{}] Principal cannot change during an authentication refresh expected={} got={}", remoteAddress, authRole, newAuthRole);
ctx.close();
} else {
log.info("[{}] Refreshed authentication credentials for role {}", remoteAddress, authRole);
}
}
}
return State.Connected;
}
// auth not complete, continue auth with client side.
ctx.writeAndFlush(Commands.newAuthChallenge(authMethod, brokerData, clientProtocolVersion));
if (log.isDebugEnabled()) {
log.debug("[{}] Authentication in progress client by method {}.", remoteAddress, authMethod);
log.debug("[{}] connect state change to : [{}]", remoteAddress, State.Connecting.name());
}
return State.Connecting;
}
use of org.apache.pulsar.common.api.AuthData in project incubator-pulsar by apache.
the class ServerCnx method refreshAuthenticationCredentials.
public void refreshAuthenticationCredentials() {
AuthenticationState authState = this.originalAuthState != null ? originalAuthState : this.authState;
if (authState == null) {
// Authentication is disabled or there's no local state to refresh
return;
} else if (getState() != State.Connected || !isActive) {
// Connection is either still being established or already closed.
return;
} else if (!authState.isExpired()) {
// Credentials are still valid. Nothing to do at this point
return;
} else if (originalPrincipal != null && originalAuthState == null) {
log.info("[{}] Cannot revalidate user credential when using proxy and" + " not forwarding the credentials. Closing connection", remoteAddress);
return;
}
ctx.executor().execute(SafeRun.safeRun(() -> {
log.info("[{}] Refreshing authentication credentials for originalPrincipal {} and authRole {}", remoteAddress, originalPrincipal, this.authRole);
if (!supportsAuthenticationRefresh()) {
log.warn("[{}] Closing connection because client doesn't support auth credentials refresh", remoteAddress);
ctx.close();
return;
}
if (pendingAuthChallengeResponse) {
log.warn("[{}] Closing connection after timeout on refreshing auth credentials", remoteAddress);
ctx.close();
return;
}
try {
AuthData brokerData = authState.refreshAuthentication();
ctx.writeAndFlush(Commands.newAuthChallenge(authMethod, brokerData, getRemoteEndpointProtocolVersion()));
if (log.isDebugEnabled()) {
log.debug("[{}] Sent auth challenge to client to refresh credentials with method: {}.", remoteAddress, authMethod);
}
pendingAuthChallengeResponse = true;
} catch (AuthenticationException e) {
log.warn("[{}] Failed to refresh authentication: {}", remoteAddress, e);
ctx.close();
}
}));
}
use of org.apache.pulsar.common.api.AuthData in project incubator-pulsar by apache.
the class ProxyConnection method handleConnect.
@Override
protected void handleConnect(CommandConnect connect) {
checkArgument(state == State.Init);
this.setRemoteEndpointProtocolVersion(connect.getProtocolVersion());
this.hasProxyToBrokerUrl = connect.hasProxyToBrokerUrl();
this.protocolVersionToAdvertise = getProtocolVersionToAdvertise(connect);
this.proxyToBrokerUrl = connect.hasProxyToBrokerUrl() ? connect.getProxyToBrokerUrl() : "null";
if (LOG.isDebugEnabled()) {
LOG.debug("Received CONNECT from {} proxyToBroker={}", remoteAddress, proxyToBrokerUrl);
LOG.debug("[{}] Protocol version to advertise to broker is {}, clientProtocolVersion={}, proxyProtocolVersion={}", remoteAddress, protocolVersionToAdvertise, getRemoteEndpointProtocolVersion(), Commands.getCurrentProtocolVersion());
}
if (getRemoteEndpointProtocolVersion() < ProtocolVersion.v10.getValue()) {
LOG.warn("[{}] Client doesn't support connecting through proxy", remoteAddress);
state = State.Closing;
ctx.close();
return;
}
try {
// init authn
this.clientConf = createClientConfiguration();
// authn not enabled, complete
if (!service.getConfiguration().isAuthenticationEnabled()) {
completeConnect(null);
return;
}
AuthData clientData = AuthData.of(connect.hasAuthData() ? connect.getAuthData() : EMPTY_CREDENTIALS);
if (connect.hasAuthMethodName()) {
authMethod = connect.getAuthMethodName();
} else if (connect.hasAuthMethod()) {
// Legacy client is passing enum
authMethod = connect.getAuthMethod().name().substring(10).toLowerCase();
} else {
authMethod = "none";
}
authenticationProvider = service.getAuthenticationService().getAuthenticationProvider(authMethod);
// In AuthenticationDisabled, it will set authMethod "none".
if (authenticationProvider == null) {
clientAuthRole = service.getAuthenticationService().getAnonymousUserRole().orElseThrow(() -> new AuthenticationException("No anonymous role, and no authentication provider configured"));
completeConnect(clientData);
return;
}
// init authState and other var
ChannelHandler sslHandler = ctx.channel().pipeline().get(PulsarChannelInitializer.TLS_HANDLER);
SSLSession sslSession = null;
if (sslHandler != null) {
sslSession = ((SslHandler) sslHandler).engine().getSession();
}
authState = authenticationProvider.newAuthState(clientData, remoteAddress, sslSession);
authenticationData = authState.getAuthDataSource();
doAuthentication(clientData);
} catch (Exception e) {
LOG.warn("[{}] Unable to authenticate: ", remoteAddress, e);
ctx.writeAndFlush(Commands.newError(-1, ServerError.AuthenticationError, "Failed to authenticate")).addListener(ChannelFutureListener.CLOSE);
}
}
use of org.apache.pulsar.common.api.AuthData in project incubator-pulsar by apache.
the class SaslAuthenticateTest method testSaslServerAndClientAuth.
// Test sasl server/client auth.
@Test
public void testSaslServerAndClientAuth() throws Exception {
log.info("-- {} -- start", methodName);
String hostName = "localhost";
// prepare client and server side resource
AuthenticationDataProvider dataProvider = authSasl.getAuthData(hostName);
AuthenticationProviderList providerList = (AuthenticationProviderList) (pulsar.getBrokerService().getAuthenticationService().getAuthenticationProvider(SaslConstants.AUTH_METHOD_NAME));
AuthenticationProviderSasl saslServer = (AuthenticationProviderSasl) providerList.getProviders().get(0);
AuthenticationState authState = saslServer.newAuthState(null, null, null);
// auth between server and client.
// first time auth
AuthData initData1 = dataProvider.authenticate(AuthData.INIT_AUTH_DATA);
AuthData serverData1 = authState.authenticate(initData1);
boolean complete = authState.isComplete();
assertFalse(complete);
// second time auth, completed
AuthData initData2 = dataProvider.authenticate(serverData1);
AuthData serverData2 = authState.authenticate(initData2);
complete = authState.isComplete();
assertTrue(complete);
assertNull(serverData2.getBytes());
// if completed, server could not auth again.
try {
authState.authenticate(initData2);
fail("Expected fail because auth completed for authState");
} catch (Exception e) {
// expected
}
// another server could not serve old client
try {
AuthenticationState authState2 = saslServer.newAuthState(null, null, null);
AuthData serverData3 = authState2.authenticate(initData1);
fail("Expected fail. server is auth old client data");
} catch (Exception e) {
// expected
}
log.info("-- {} -- end", methodName);
}
Aggregations