use of javax.security.sasl.SaslException in project zookeeper by apache.
the class SecurityUtils method createSaslClient.
/**
* Create an instance of a SaslClient. It will return null if there is an exception.
*
* @param subject subject
* @param servicePrincipal principal
* @param protocol name of the protocol for which the authentication is being performed
* @param serverName name of the server to authenticate to
* @param LOG logger
* @param entity can be either zookeeper client or quorum learner
*
* @return saslclient object
* @throws SaslException
*/
public static SaslClient createSaslClient(final Subject subject, final String servicePrincipal, final String protocol, final String serverName, final Logger LOG, final String entity) throws SaslException {
SaslClient saslClient;
// mechanism to use: if empty, use DIGEST-MD5; otherwise, use GSSAPI.
if (subject.getPrincipals().isEmpty()) {
// no principals: must not be GSSAPI: use DIGEST-MD5 mechanism
// instead.
LOG.info("{} will use DIGEST-MD5 as SASL mechanism.", entity);
String[] mechs = { "DIGEST-MD5" };
String username = (String) (subject.getPublicCredentials().toArray()[0]);
String password = (String) (subject.getPrivateCredentials().toArray()[0]);
// 'domain' parameter is hard-wired between the server and client
saslClient = Sasl.createSaslClient(mechs, username, protocol, serverName, null, new SaslClientCallbackHandler(password, entity));
return saslClient;
} else {
// GSSAPI.
final Object[] principals = subject.getPrincipals().toArray();
// determine client principal from subject.
final Principal clientPrincipal = (Principal) principals[0];
boolean usingNativeJgss = Boolean.getBoolean("sun.security.jgss.native");
if (usingNativeJgss) {
// """
try {
GSSManager manager = GSSManager.getInstance();
Oid krb5Mechanism = new Oid("1.2.840.113554.1.2.2");
GSSCredential cred = manager.createCredential(null, GSSContext.DEFAULT_LIFETIME, krb5Mechanism, GSSCredential.INITIATE_ONLY);
subject.getPrivateCredentials().add(cred);
LOG.debug("Added private credential to {} principal name: '{}'", entity, clientPrincipal);
} catch (GSSException ex) {
LOG.warn("Cannot add private credential to subject; " + "authentication at the server may fail", ex);
}
}
final KerberosName clientKerberosName = new KerberosName(clientPrincipal.getName());
// assume that server and client are in the same realm (by default;
// unless the system property
// "zookeeper.server.realm" is set).
String serverRealm = System.getProperty("zookeeper.server.realm", clientKerberosName.getRealm());
KerberosName serviceKerberosName = new KerberosName(servicePrincipal + "@" + serverRealm);
final String serviceName = serviceKerberosName.getServiceName();
final String serviceHostname = serviceKerberosName.getHostName();
final String clientPrincipalName = clientKerberosName.toString();
try {
saslClient = Subject.doAs(subject, new PrivilegedExceptionAction<SaslClient>() {
public SaslClient run() throws SaslException {
LOG.info("{} will use GSSAPI as SASL mechanism.", entity);
String[] mechs = { "GSSAPI" };
LOG.debug("creating sasl client: {}={};service={};serviceHostname={}", new Object[] { entity, clientPrincipalName, serviceName, serviceHostname });
SaslClient saslClient = Sasl.createSaslClient(mechs, clientPrincipalName, serviceName, serviceHostname, null, new SaslClientCallbackHandler(null, entity));
return saslClient;
}
});
return saslClient;
} catch (Exception e) {
LOG.error("Exception while trying to create SASL client", e);
return null;
}
}
}
use of javax.security.sasl.SaslException in project JGroups by belaban.
the class SASL method up.
@Override
public Object up(Message msg) {
SaslHeader saslHeader = msg.getHeader(SASL_ID);
GmsHeader gmsHeader = msg.getHeader(GMS_ID);
Address remoteAddress = msg.getSrc();
if (needsAuthentication(gmsHeader, remoteAddress)) {
if (saslHeader == null)
throw new IllegalStateException("Found GMS join or merge request but no SASL header");
if (!serverChallenge(gmsHeader, saslHeader, msg))
// failed auth, don't pass up
return null;
} else if (saslHeader != null) {
SaslContext saslContext = sasl_context.get(remoteAddress);
if (saslContext == null) {
throw new IllegalStateException(String.format("Cannot find server context to challenge SASL request from %s", remoteAddress.toString()));
}
switch(saslHeader.getType()) {
case CHALLENGE:
try {
if (log.isTraceEnabled())
log.trace("%s: received CHALLENGE from %s", getAddress(), remoteAddress);
// the response computed can be null if the challenge-response cycle has ended
Message response = saslContext.nextMessage(remoteAddress, saslHeader);
if (response != null) {
if (log.isTraceEnabled())
log.trace("%s: sending RESPONSE to %s", getAddress(), remoteAddress);
down_prot.down(response);
} else {
if (!saslContext.isSuccessful()) {
throw new SaslException("computed response is null but challenge-response cycle not complete!");
}
if (log.isTraceEnabled())
log.trace("%s: authentication complete from %s", getAddress(), remoteAddress);
}
} catch (SaslException e) {
disposeContext(remoteAddress);
if (log.isWarnEnabled()) {
log.warn(getAddress() + ": failed to validate CHALLENGE from " + remoteAddress + ", token", e);
}
}
break;
case RESPONSE:
try {
if (log.isTraceEnabled())
log.trace("%s: received RESPONSE from %s", getAddress(), remoteAddress);
Message challenge = saslContext.nextMessage(remoteAddress, saslHeader);
// the challenge computed can be null if the challenge-response cycle has ended
if (challenge != null) {
if (log.isTraceEnabled())
log.trace("%s: sending CHALLENGE to %s", getAddress(), remoteAddress);
down_prot.down(challenge);
} else {
if (!saslContext.isSuccessful()) {
throw new SaslException("computed challenge is null but challenge-response cycle not complete!");
}
if (log.isTraceEnabled())
log.trace("%s: authentication complete from %s", getAddress(), remoteAddress);
}
} catch (SaslException e) {
disposeContext(remoteAddress);
if (log.isWarnEnabled()) {
log.warn("failed to validate RESPONSE from " + remoteAddress + ", token", e);
}
}
break;
}
return null;
}
return up_prot.up(msg);
}
use of javax.security.sasl.SaslException in project JGroups by belaban.
the class SASL method serverChallenge.
protected boolean serverChallenge(GmsHeader gmsHeader, SaslHeader saslHeader, Message msg) {
switch(gmsHeader.getType()) {
case GmsHeader.JOIN_REQ:
case GmsHeader.JOIN_REQ_WITH_STATE_TRANSFER:
case GmsHeader.MERGE_REQ:
Address remoteAddress = msg.getSrc();
SaslServerContext ctx = null;
try {
ctx = new SaslServerContext(saslServerFactory, mech, server_name != null ? server_name : local_addr.toString(), server_callback_handler, sasl_props, server_subject);
sasl_context.put(remoteAddress, ctx);
this.getDownProtocol().down(ctx.nextMessage(remoteAddress, saslHeader));
ctx.awaitCompletion(timeout);
if (ctx.isSuccessful()) {
if (log.isDebugEnabled()) {
log.debug("Authentication successful for %s", ctx.getAuthorizationID());
}
return true;
} else {
log.warn("failed to validate SaslHeader from %s, header: %s", msg.getSrc(), saslHeader);
sendRejectionMessage(gmsHeader.getType(), msg.getSrc(), "authentication failed");
return false;
}
} catch (SaslException e) {
log.warn("failed to validate SaslHeader from %s, header: %s", msg.getSrc(), saslHeader);
sendRejectionMessage(gmsHeader.getType(), msg.getSrc(), "authentication failed");
} catch (InterruptedException e) {
return false;
} finally {
if (ctx != null && !ctx.needsWrapping()) {
disposeContext(remoteAddress);
}
}
default:
// pass up
return true;
}
}
use of javax.security.sasl.SaslException in project hive by apache.
the class HiveConnection method createBinaryTransport.
/**
* Create transport per the connection options
* Supported transport options are:
* - SASL based transports over
* + Kerberos
* + Delegation token
* + SSL
* + non-SSL
* - Raw (non-SASL) socket
*
* Kerberos and Delegation token supports SASL QOP configurations
* @throws SQLException, TTransportException
*/
private TTransport createBinaryTransport() throws SQLException, TTransportException {
try {
TTransport socketTransport = createUnderlyingTransport();
// handle secure connection if specified
if (!JdbcConnectionParams.AUTH_SIMPLE.equals(sessConfMap.get(JdbcConnectionParams.AUTH_TYPE))) {
// If Kerberos
Map<String, String> saslProps = new HashMap<String, String>();
SaslQOP saslQOP = SaslQOP.AUTH;
if (sessConfMap.containsKey(JdbcConnectionParams.AUTH_QOP)) {
try {
saslQOP = SaslQOP.fromString(sessConfMap.get(JdbcConnectionParams.AUTH_QOP));
} catch (IllegalArgumentException e) {
throw new SQLException("Invalid " + JdbcConnectionParams.AUTH_QOP + " parameter. " + e.getMessage(), "42000", e);
}
saslProps.put(Sasl.QOP, saslQOP.toString());
} else {
// If the client did not specify qop then just negotiate the one supported by server
saslProps.put(Sasl.QOP, "auth-conf,auth-int,auth");
}
saslProps.put(Sasl.SERVER_AUTH, "true");
if (sessConfMap.containsKey(JdbcConnectionParams.AUTH_PRINCIPAL)) {
transport = KerberosSaslHelper.getKerberosTransport(sessConfMap.get(JdbcConnectionParams.AUTH_PRINCIPAL), host, socketTransport, saslProps, assumeSubject);
} else {
// If there's a delegation token available then use token based connection
String tokenStr = getClientDelegationToken(sessConfMap);
if (tokenStr != null) {
transport = KerberosSaslHelper.getTokenTransport(tokenStr, host, socketTransport, saslProps);
} else {
// we are using PLAIN Sasl connection with user/password
String userName = getUserName();
String passwd = getPassword();
// Overlay the SASL transport on top of the base socket transport (SSL or non-SSL)
transport = PlainSaslHelper.getPlainTransport(userName, passwd, socketTransport);
}
}
} else {
// Raw socket connection (non-sasl)
transport = socketTransport;
}
} catch (SaslException e) {
throw new SQLException("Could not create secure connection to " + jdbcUriString + ": " + e.getMessage(), " 08S01", e);
}
return transport;
}
use of javax.security.sasl.SaslException in project Openfire by igniterealtime.
the class SASLAuthentication method handle.
/**
* Handles the SASL authentication packet. The entity may be sending an initial
* authentication request or a response to a challenge made by the server. The returned
* value indicates whether the authentication has finished either successfully or not or
* if the entity is expected to send a response to a challenge.
*
* @param session the session that is authenticating with the server.
* @param doc the stanza sent by the authenticating entity.
* @return value that indicates whether the authentication has finished either successfully
* or not or if the entity is expected to send a response to a challenge.
*/
public static Status handle(LocalSession session, Element doc) {
try {
if (!doc.getNamespaceURI().equals(SASL_NAMESPACE)) {
throw new IllegalStateException("Unexpected data received while negotiating SASL authentication. Name of the offending root element: " + doc.getName() + " Namespace: " + doc.getNamespaceURI());
}
switch(ElementType.valueOfCaseInsensitive(doc.getName())) {
case ABORT:
throw new SaslFailureException(Failure.ABORTED);
case AUTH:
if (doc.attributeValue("mechanism") == null) {
throw new SaslFailureException(Failure.INVALID_MECHANISM, "Peer did not specify a mechanism.");
}
final String mechanismName = doc.attributeValue("mechanism").toUpperCase();
// See if the mechanism is supported by configuration as well as by implementation.
if (!mechanisms.contains(mechanismName)) {
throw new SaslFailureException(Failure.INVALID_MECHANISM, "The configuration of Openfire does not contain or allow the mechanism.");
}
// OF-477: The SASL implementation requires the fully qualified host name (not the domain name!) of this server,
// yet, most of the XMPP implemenations of DIGEST-MD5 will actually use the domain name. To account for that,
// here, we'll use the host name, unless DIGEST-MD5 is being negotiated!
final XMPPServerInfo serverInfo = XMPPServer.getInstance().getServerInfo();
final String serverName = (mechanismName.equals("DIGEST-MD5") ? serverInfo.getXMPPDomain() : serverInfo.getHostname());
// Construct the configuration properties
final Map<String, Object> props = new HashMap<>();
props.put(LocalSession.class.getCanonicalName(), session);
props.put(Sasl.POLICY_NOANONYMOUS, Boolean.toString(!JiveGlobals.getBooleanProperty("xmpp.auth.anonymous")));
props.put("com.sun.security.sasl.digest.realm", serverInfo.getXMPPDomain());
SaslServer saslServer = Sasl.createSaslServer(mechanismName, "xmpp", serverName, props, new XMPPCallbackHandler());
if (saslServer == null) {
throw new SaslFailureException(Failure.INVALID_MECHANISM, "There is no provider that can provide a SASL server for the desired mechanism and properties.");
}
session.setSessionData("SaslServer", saslServer);
if (mechanismName.equals("DIGEST-MD5")) {
// RFC2831 (DIGEST-MD5) says the client MAY provide data in the initial response. Java SASL does
// not (currently) support this and throws an exception. For XMPP, such data violates
// the RFC, so we just strip any initial token.
doc.setText("");
}
// intended fall-through
case RESPONSE:
saslServer = (SaslServer) session.getSessionData("SaslServer");
if (saslServer == null) {
// Client sends response without a preceding auth?
throw new IllegalStateException("A SaslServer instance was not initialized and/or stored on the session.");
}
// Decode any data that is provided in the client response.
final String encoded = doc.getTextTrim();
final byte[] decoded;
if (// java SaslServer cannot handle a null.
encoded == null || encoded.isEmpty() || encoded.equals("=")) {
decoded = new byte[0];
} else {
// TODO: We shouldn't depend on regex-based validation. Instead, use a proper decoder implementation and handle any exceptions that it throws.
if (!BASE64_ENCODED.matcher(encoded).matches()) {
throw new SaslFailureException(Failure.INCORRECT_ENCODING);
}
decoded = StringUtils.decodeBase64(encoded);
}
// Process client response.
// Either a challenge or success data.
final byte[] challenge = saslServer.evaluateResponse(decoded);
if (!saslServer.isComplete()) {
// Not complete: client is challenged for additional steps.
sendChallenge(session, challenge);
return Status.needResponse;
}
// Success!
if (session instanceof IncomingServerSession) {
// Flag that indicates if certificates of the remote server should be validated.
final boolean verify = JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_CERTIFICATE_VERIFY, true);
if (verify) {
if (verifyCertificates(session.getConnection().getPeerCertificates(), saslServer.getAuthorizationID(), true)) {
((LocalIncomingServerSession) session).tlsAuth();
} else {
throw new SaslFailureException(Failure.NOT_AUTHORIZED, "Server-to-Server certificate verification failed.");
}
}
}
authenticationSuccessful(session, saslServer.getAuthorizationID(), challenge);
session.removeSessionData("SaslServer");
return Status.authenticated;
default:
throw new IllegalStateException("Unexpected data received while negotiating SASL authentication. Name of the offending root element: " + doc.getName() + " Namespace: " + doc.getNamespaceURI());
}
} catch (SaslException ex) {
Log.debug("SASL negotiation failed for session: {}", session, ex);
final Failure failure;
if (ex instanceof SaslFailureException && ((SaslFailureException) ex).getFailure() != null) {
failure = ((SaslFailureException) ex).getFailure();
} else {
failure = Failure.NOT_AUTHORIZED;
}
authenticationFailed(session, failure);
session.removeSessionData("SaslServer");
return Status.failed;
} catch (Exception ex) {
Log.warn("An unexpected exception occurred during SASL negotiation. Affected session: {}", session, ex);
authenticationFailed(session, Failure.NOT_AUTHORIZED);
session.removeSessionData("SaslServer");
return Status.failed;
}
}
Aggregations