Search in sources :

Example 1 with ServerSession

use of com.mysql.cj.protocol.ServerSession in project ABC by RuiPinto96274.

the class NativeAuthenticationProvider method connect.

/**
 * Initialize communications with the MySQL server. Handles logging on, and
 * handling initial connection errors.
 *
 * @param user
 *            user name
 * @param pass
 *            password
 * @param db
 *            database name
 */
@Override
public void connect(String user, String pass, String db) {
    ServerSession sessState = this.protocol.getServerSession();
    this.username = user;
    this.password = pass;
    this.database = db;
    NativeCapabilities capabilities = (NativeCapabilities) sessState.getCapabilities();
    NativePacketPayload buf = capabilities.getInitialHandshakePacket();
    SslMode sslMode = this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue();
    int capabilityFlags = capabilities.getCapabilityFlags();
    if (((capabilityFlags & NativeServerSession.CLIENT_SSL) == 0) && sslMode != SslMode.DISABLED && sslMode != SslMode.PREFERRED) {
        // check SSL availability
        throw ExceptionFactory.createException(UnableToConnectException.class, Messages.getString("MysqlIO.15"), getExceptionInterceptor());
    } else if ((capabilityFlags & NativeServerSession.CLIENT_SECURE_CONNECTION) == 0) {
        // TODO: better messaging
        throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_SECURE_CONNECTION is required", getExceptionInterceptor());
    } else if ((capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH) == 0) {
        // TODO: better messaging
        throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_PLUGIN_AUTH is required", getExceptionInterceptor());
    }
    // read status flags (2 bytes)
    sessState.setStatusFlags(capabilities.getStatusFlags());
    int authPluginDataLength = capabilities.getAuthPluginDataLength();
    StringBuilder fullSeed = new StringBuilder(authPluginDataLength > 0 ? authPluginDataLength : NativeConstants.SEED_LENGTH);
    // read auth-plugin-data-part-1 (string[8])
    fullSeed.append(capabilities.getSeed());
    fullSeed.append(// read string[$len] auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))
    authPluginDataLength > 0 ? buf.readString(StringLengthDataType.STRING_FIXED, "ASCII", authPluginDataLength - 8) : buf.readString(StringSelfDataType.STRING_TERM, "ASCII"));
    this.seed = fullSeed.toString();
    this.useConnectWithDb = (this.database != null) && (this.database.length() > 0) && !this.propertySet.getBooleanProperty(PropertyKey.createDatabaseIfNotExist).getValue();
    long clientParam = NativeServerSession.CLIENT_SECURE_CONNECTION | NativeServerSession.CLIENT_PLUGIN_AUTH | // 
    (capabilityFlags & NativeServerSession.CLIENT_LONG_PASSWORD) | // 
    (capabilityFlags & NativeServerSession.CLIENT_PROTOCOL_41) | // Need this to get server status values
    (capabilityFlags & NativeServerSession.CLIENT_TRANSACTIONS) | // We always allow multiple result sets
    (capabilityFlags & NativeServerSession.CLIENT_MULTI_RESULTS) | // We always allow multiple result sets for SSPS
    (capabilityFlags & NativeServerSession.CLIENT_PS_MULTI_RESULTS) | // 
    (capabilityFlags & NativeServerSession.CLIENT_LONG_FLAG) | // 
    (capabilityFlags & NativeServerSession.CLIENT_DEPRECATE_EOF) | (capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) | (capabilityFlags & NativeServerSession.CLIENT_QUERY_ATTRIBUTES) | (this.propertySet.getBooleanProperty(PropertyKey.useCompression).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_COMPRESS) : 0) | (this.useConnectWithDb ? (capabilityFlags & NativeServerSession.CLIENT_CONNECT_WITH_DB) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.useAffectedRows).getValue() ? 0 : (capabilityFlags & NativeServerSession.CLIENT_FOUND_ROWS)) | (this.propertySet.getBooleanProperty(PropertyKey.allowLoadLocalInfile).getValue() || this.propertySet.getStringProperty(PropertyKey.allowLoadLocalInfileInPath).isExplicitlySet() ? (capabilityFlags & NativeServerSession.CLIENT_LOCAL_FILES) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.interactiveClient).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_INTERACTIVE) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_MULTI_STATEMENTS) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.disconnectOnExpiredPasswords).getValue() ? 0 : (capabilityFlags & NativeServerSession.CLIENT_CAN_HANDLE_EXPIRED_PASSWORD)) | (NONE.equals(this.propertySet.getStringProperty(PropertyKey.connectionAttributes).getValue()) ? 0 : (capabilityFlags & NativeServerSession.CLIENT_CONNECT_ATTRS)) | (this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue() != SslMode.DISABLED ? (capabilityFlags & NativeServerSession.CLIENT_SSL) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.trackSessionState).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK) : 0);
    sessState.setClientParam(clientParam);
    /* First, negotiate SSL connection */
    if ((clientParam & NativeServerSession.CLIENT_SSL) != 0) {
        this.protocol.negotiateSSLConnection();
    }
    if (buf.isOKPacket()) {
        throw ExceptionFactory.createException(Messages.getString("AuthenticationProvider.UnexpectedAuthenticationApproval"), getExceptionInterceptor());
    }
    proceedHandshakeWithPluggableAuthentication(buf);
    this.password = null;
}
Also used : ServerSession(com.mysql.cj.protocol.ServerSession) SslMode(com.mysql.cj.conf.PropertyDefinitions.SslMode) UnableToConnectException(com.mysql.cj.exceptions.UnableToConnectException)

Example 2 with ServerSession

use of com.mysql.cj.protocol.ServerSession in project aws-mysql-jdbc by awslabs.

the class NativeAuthenticationProvider method connect.

/**
 * Initialize communications with the MySQL server. Handles logging on, and
 * handling initial connection errors.
 *
 * @param user
 *            user name
 * @param pass
 *            password
 * @param db
 *            database name
 */
@Override
public void connect(String user, String pass, String db) {
    ServerSession sessState = this.protocol.getServerSession();
    this.username = user;
    this.password = pass;
    this.database = db;
    NativeCapabilities capabilities = (NativeCapabilities) sessState.getCapabilities();
    NativePacketPayload buf = capabilities.getInitialHandshakePacket();
    SslMode sslMode = this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue();
    int capabilityFlags = capabilities.getCapabilityFlags();
    if (((capabilityFlags & NativeServerSession.CLIENT_SSL) == 0) && sslMode != SslMode.DISABLED && sslMode != SslMode.PREFERRED) {
        // check SSL availability
        throw ExceptionFactory.createException(UnableToConnectException.class, Messages.getString("MysqlIO.15"), getExceptionInterceptor());
    } else if ((capabilityFlags & NativeServerSession.CLIENT_SECURE_CONNECTION) == 0) {
        // TODO: better messaging
        throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_SECURE_CONNECTION is required", getExceptionInterceptor());
    } else if ((capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH) == 0) {
        // TODO: better messaging
        throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_PLUGIN_AUTH is required", getExceptionInterceptor());
    }
    // read status flags (2 bytes)
    sessState.setStatusFlags(capabilities.getStatusFlags());
    int authPluginDataLength = capabilities.getAuthPluginDataLength();
    StringBuilder fullSeed = new StringBuilder(authPluginDataLength > 0 ? authPluginDataLength : NativeConstants.SEED_LENGTH);
    // read auth-plugin-data-part-1 (string[8])
    fullSeed.append(capabilities.getSeed());
    fullSeed.append(// read string[$len] auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))
    authPluginDataLength > 0 ? buf.readString(StringLengthDataType.STRING_FIXED, "ASCII", authPluginDataLength - 8) : buf.readString(StringSelfDataType.STRING_TERM, "ASCII"));
    this.seed = fullSeed.toString();
    this.useConnectWithDb = (this.database != null) && (this.database.length() > 0) && !this.propertySet.getBooleanProperty(PropertyKey.createDatabaseIfNotExist).getValue();
    long clientParam = // 
    capabilityFlags & NativeServerSession.CLIENT_LONG_PASSWORD | (// 
    this.propertySet.getBooleanProperty(PropertyKey.useAffectedRows).getValue() ? 0 : // 
    capabilityFlags & NativeServerSession.CLIENT_FOUND_ROWS) | // 
    capabilityFlags & NativeServerSession.CLIENT_LONG_FLAG | // 
    (this.useConnectWithDb ? capabilityFlags & NativeServerSession.CLIENT_CONNECT_WITH_DB : 0) | (// 
    this.propertySet.getBooleanProperty(PropertyKey.useCompression).getValue() ? capabilityFlags & NativeServerSession.CLIENT_COMPRESS : // 
    0) | (this.propertySet.getBooleanProperty(PropertyKey.allowLoadLocalInfile).getValue() || // 
    this.propertySet.getStringProperty(PropertyKey.allowLoadLocalInfileInPath).isExplicitlySet() ? capabilityFlags & NativeServerSession.CLIENT_LOCAL_FILES : // 
    0) | // 
    capabilityFlags & NativeServerSession.CLIENT_PROTOCOL_41 | (// 
    this.propertySet.getBooleanProperty(PropertyKey.interactiveClient).getValue() ? capabilityFlags & NativeServerSession.CLIENT_INTERACTIVE : // 
    0) | (// 
    this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue() != SslMode.DISABLED ? capabilityFlags & NativeServerSession.CLIENT_SSL : // 
    0) | // Required to get server status values.
    capabilityFlags & NativeServerSession.CLIENT_TRANSACTIONS | // 
    NativeServerSession.CLIENT_SECURE_CONNECTION | (// 
    this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue() ? capabilityFlags & NativeServerSession.CLIENT_MULTI_STATEMENTS : // 
    0) | // Always allow multiple result sets.
    capabilityFlags & NativeServerSession.CLIENT_MULTI_RESULTS | // Always allow multiple result sets for SSPS.
    capabilityFlags & NativeServerSession.CLIENT_PS_MULTI_RESULTS | // 
    NativeServerSession.CLIENT_PLUGIN_AUTH | (// 
    NONE.equals(this.propertySet.getStringProperty(PropertyKey.connectionAttributes).getValue()) ? 0 : // 
    capabilityFlags & NativeServerSession.CLIENT_CONNECT_ATTRS) | // 
    capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA | (// 
    this.propertySet.getBooleanProperty(PropertyKey.disconnectOnExpiredPasswords).getValue() ? 0 : // 
    capabilityFlags & NativeServerSession.CLIENT_CAN_HANDLE_EXPIRED_PASSWORD) | (// 
    this.propertySet.getBooleanProperty(PropertyKey.trackSessionState).getValue() ? capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK : // 
    0) | // 
    capabilityFlags & NativeServerSession.CLIENT_DEPRECATE_EOF | // 
    capabilityFlags & NativeServerSession.CLIENT_QUERY_ATTRIBUTES | capabilityFlags & NativeServerSession.CLIENT_MULTI_FACTOR_AUTHENTICATION;
    sessState.setClientParam(clientParam);
    /* First, negotiate SSL connection */
    if ((clientParam & NativeServerSession.CLIENT_SSL) != 0) {
        this.protocol.negotiateSSLConnection();
    }
    if (buf.isOKPacket()) {
        throw ExceptionFactory.createException(Messages.getString("AuthenticationProvider.UnexpectedAuthenticationApproval"), getExceptionInterceptor());
    }
    proceedHandshakeWithPluggableAuthentication(buf);
    this.password = null;
}
Also used : ServerSession(com.mysql.cj.protocol.ServerSession) SslMode(com.mysql.cj.conf.PropertyDefinitions.SslMode) UnableToConnectException(com.mysql.cj.exceptions.UnableToConnectException)

Example 3 with ServerSession

use of com.mysql.cj.protocol.ServerSession in project aws-mysql-jdbc by awslabs.

the class NativeAuthenticationProvider method proceedHandshakeWithPluggableAuthentication.

/**
 * Performs an authentication handshake to authorize connection to a given database as a given MySQL user.
 * This can happen upon initial connection to the server, after receiving Auth Challenge Packet, or
 * at any moment during the connection life-time via a Change User request.
 *
 * This method will use registered authentication plugins as requested by the server.
 *
 * @param challenge
 *            the Auth Challenge Packet received from server if
 *            this method is used during the initial connection.
 *            Otherwise null.
 */
private void proceedHandshakeWithPluggableAuthentication(final NativePacketPayload challenge) {
    ServerSession serverSession = this.protocol.getServerSession();
    if (this.authenticationPlugins == null) {
        loadAuthenticationPlugins();
    }
    boolean forChangeUser = true;
    if (challenge != null) {
        this.serverDefaultAuthenticationPluginName = challenge.readString(StringSelfDataType.STRING_TERM, "ASCII");
        forChangeUser = false;
    }
    serverSession.getCharsetSettings().configurePreHandshake(forChangeUser);
    /*
         * Select the initial plugin:
         * Choose the client-side default authentication plugin, if explicitely specified, otherwise choose the server-side default authentication plugin.
         */
    String pluginName;
    if (this.clientDefaultAuthenticationPluginExplicitelySet) {
        pluginName = this.clientDefaultAuthenticationPluginName;
    } else {
        pluginName = this.serverDefaultAuthenticationPluginName != null ? this.serverDefaultAuthenticationPluginName : this.clientDefaultAuthenticationPluginName;
    }
    AuthenticationPlugin<NativePacketPayload> plugin = getAuthenticationPlugin(pluginName);
    if (plugin == null) {
        /* Use default if there is no plugin for pluginName. */
        pluginName = this.clientDefaultAuthenticationPluginName;
        plugin = getAuthenticationPlugin(pluginName);
    }
    boolean skipPassword = false;
    if (pluginName.equals(Sha256PasswordPlugin.PLUGIN_NAME) && !pluginName.equals(this.clientDefaultAuthenticationPluginName) && !this.protocol.getSocketConnection().isSSLEstablished() && this.propertySet.getStringProperty(PropertyKey.serverRSAPublicKeyFile).getValue() == null && !this.propertySet.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval).getValue()) {
        /*
             * Fall back to client default if plugin is 'sha256_password' but required conditions for this to work aren't met.
             * If client default is other than 'sha256_password', this will result in an immediate authentication switch request, allowing for other plugins to
             * authenticate successfully. If client default is 'sha256_password' then the authentication will fail as expected. In both cases user's password
             * won't be sent to avoid subjecting it to lesser security levels.
             */
        plugin = getAuthenticationPlugin(this.clientDefaultAuthenticationPluginName);
        skipPassword = true;
    }
    checkConfidentiality(plugin);
    // Servers not affected by Bug#70865 expect the Change User Request containing a correct answer to seed sent by the server during the initial handshake,
    // thus we reuse it here. Servers affected by Bug#70865 will just ignore it and send the Auth Switch.
    NativePacketPayload fromServer = new NativePacketPayload(StringUtils.getBytes(this.seed));
    String sourceOfAuthData = this.serverDefaultAuthenticationPluginName;
    NativePacketPayload lastSent = null;
    NativePacketPayload lastReceived = challenge;
    ArrayList<NativePacketPayload> toServer = new ArrayList<>();
    boolean firstPacket = true;
    // MFA authentication factor
    int mfaNthFactor = 1;
    /* Max iterations number */
    int counter = 100;
    while (0 < counter--) {
        /*
             * call plugin
             */
        plugin.setAuthenticationParameters(this.username, skipPassword ? null : getNthFactorPassword(mfaNthFactor));
        plugin.setSourceOfAuthData(sourceOfAuthData);
        plugin.nextAuthenticationStep(fromServer, toServer);
        /*
             * send response to server
             */
        if (firstPacket) {
            NativePacketPayload authData = toServer.isEmpty() ? new NativePacketPayload(0) : toServer.get(0);
            if (forChangeUser) {
                // write COM_CHANGE_USER Packet
                lastSent = createChangeUserPacket(serverSession, plugin.getProtocolPluginName(), authData);
                this.protocol.send(lastSent, lastSent.getPosition());
            } else {
                // write HandshakeResponse packet
                lastSent = createHandshakeResponsePacket(serverSession, plugin.getProtocolPluginName(), authData);
                this.protocol.send(lastSent, lastSent.getPosition());
            }
            firstPacket = false;
        } else if (!toServer.isEmpty()) {
            // write AuthSwitchResponse packet or raw packet(s)
            toServer.forEach(b -> this.protocol.send(b, b.getPayloadLength()));
        }
        /*
             * read packet from server
             */
        lastReceived = this.protocol.checkErrorMessage();
        if (lastReceived.isOKPacket()) {
            // read OK packet
            OkPacket ok = OkPacket.parse(lastReceived, null);
            serverSession.setStatusFlags(ok.getStatusFlags(), true);
            serverSession.getServerSessionStateController().setSessionStateChanges(ok.getSessionStateChanges());
            // authentication complete
            plugin.destroy();
            break;
        } else if (lastReceived.isAuthMethodSwitchRequestPacket()) {
            // read AuthSwitchRequest Packet
            skipPassword = false;
            pluginName = lastReceived.readString(StringSelfDataType.STRING_TERM, "ASCII");
            if (plugin.getProtocolPluginName().equals(pluginName)) {
                // just reset the current one
                plugin.reset();
            } else {
                // get new plugin
                plugin.destroy();
                plugin = getAuthenticationPlugin(pluginName);
                if (plugin == null) {
                    throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.BadAuthenticationPlugin", new Object[] { pluginName }), getExceptionInterceptor());
                }
            }
            checkConfidentiality(plugin);
            fromServer = new NativePacketPayload(lastReceived.readBytes(StringSelfDataType.STRING_EOF));
        } else if (lastReceived.isAuthNextFactorPacket()) {
            // authentication not done yet, there's another MFA iteration
            mfaNthFactor++;
            skipPassword = false;
            pluginName = lastReceived.readString(StringSelfDataType.STRING_TERM, "ASCII");
            if (plugin.getProtocolPluginName().equals(pluginName)) {
                // just reset the current one
                plugin.reset();
            } else {
                // get new plugin
                plugin.destroy();
                plugin = getAuthenticationPlugin(pluginName);
                if (plugin == null) {
                    throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.BadAuthenticationPlugin", new Object[] { pluginName }), getExceptionInterceptor());
                }
            }
            checkConfidentiality(plugin);
            fromServer = new NativePacketPayload(lastReceived.readBytes(StringSelfDataType.STRING_EOF));
        } else {
            // read raw (from AuthMoreData) packet
            if (!this.protocol.versionMeetsMinimum(5, 5, 16)) {
                lastReceived.setPosition(lastReceived.getPosition() - 1);
            }
            fromServer = new NativePacketPayload(lastReceived.readBytes(StringSelfDataType.STRING_EOF));
        }
        sourceOfAuthData = pluginName;
    }
    if (counter == 0) {
        throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("CommunicationsException.TooManyAuthenticationPluginNegotiations"), getExceptionInterceptor());
    }
    this.protocol.afterHandshake();
    if (!this.useConnectWithDb) {
        this.protocol.changeDatabase(this.database);
    }
}
Also used : StringSelfDataType(com.mysql.cj.protocol.a.NativeConstants.StringSelfDataType) ExceptionFactory(com.mysql.cj.exceptions.ExceptionFactory) StringLengthDataType(com.mysql.cj.protocol.a.NativeConstants.StringLengthDataType) HashMap(java.util.HashMap) MysqlNativePasswordPlugin(com.mysql.cj.protocol.a.authentication.MysqlNativePasswordPlugin) UnableToConnectException(com.mysql.cj.exceptions.UnableToConnectException) UsernameCallback(com.mysql.cj.callback.UsernameCallback) ArrayList(java.util.ArrayList) Constants(com.mysql.cj.Constants) AuthenticationPlugin(com.mysql.cj.protocol.AuthenticationPlugin) Protocol(com.mysql.cj.protocol.Protocol) AuthenticationProvider(com.mysql.cj.protocol.AuthenticationProvider) CachingSha2PasswordPlugin(com.mysql.cj.protocol.a.authentication.CachingSha2PasswordPlugin) Sha256PasswordPlugin(com.mysql.cj.protocol.a.authentication.Sha256PasswordPlugin) Map(java.util.Map) SslMode(com.mysql.cj.conf.PropertyDefinitions.SslMode) LinkedList(java.util.LinkedList) RuntimeProperty(com.mysql.cj.conf.RuntimeProperty) AuthenticationKerberosClient(com.mysql.cj.protocol.a.authentication.AuthenticationKerberosClient) WrongArgumentException(com.mysql.cj.exceptions.WrongArgumentException) PropertySet(com.mysql.cj.conf.PropertySet) ServerSession(com.mysql.cj.protocol.ServerSession) Messages(com.mysql.cj.Messages) AuthenticationLdapSaslClientPlugin(com.mysql.cj.protocol.a.authentication.AuthenticationLdapSaslClientPlugin) MysqlCallbackHandler(com.mysql.cj.callback.MysqlCallbackHandler) AuthenticationOciClient(com.mysql.cj.protocol.a.authentication.AuthenticationOciClient) AwsIamAuthenticationTokenHelper(com.mysql.cj.protocol.a.authentication.AwsIamAuthenticationTokenHelper) MysqlOldPasswordPlugin(com.mysql.cj.protocol.a.authentication.MysqlOldPasswordPlugin) OkPacket(com.mysql.cj.protocol.a.result.OkPacket) List(java.util.List) IntegerDataType(com.mysql.cj.protocol.a.NativeConstants.IntegerDataType) ExceptionInterceptor(com.mysql.cj.exceptions.ExceptionInterceptor) StringUtils(com.mysql.cj.util.StringUtils) MysqlClearPasswordPlugin(com.mysql.cj.protocol.a.authentication.MysqlClearPasswordPlugin) AwsIamClearAuthenticationPlugin(com.mysql.cj.protocol.a.authentication.AwsIamClearAuthenticationPlugin) Collections(java.util.Collections) PropertyKey(com.mysql.cj.conf.PropertyKey) AwsIamAuthenticationPlugin(com.mysql.cj.protocol.a.authentication.AwsIamAuthenticationPlugin) ServerSession(com.mysql.cj.protocol.ServerSession) OkPacket(com.mysql.cj.protocol.a.result.OkPacket) ArrayList(java.util.ArrayList) WrongArgumentException(com.mysql.cj.exceptions.WrongArgumentException)

Example 4 with ServerSession

use of com.mysql.cj.protocol.ServerSession in project JavaSegundasQuintas by ecteruel.

the class NativeAuthenticationProvider method proceedHandshakeWithPluggableAuthentication.

/**
 * Performs an authentication handshake to authorize connection to a given database as a given MySQL user.
 * This can happen upon initial connection to the server, after receiving Auth Challenge Packet, or
 * at any moment during the connection life-time via a Change User request.
 *
 * This method will use registered authentication plugins as requested by the server.
 *
 * @param challenge
 *            the Auth Challenge Packet received from server if
 *            this method is used during the initial connection.
 *            Otherwise null.
 */
private void proceedHandshakeWithPluggableAuthentication(final NativePacketPayload challenge) {
    ServerSession serverSession = this.protocol.getServerSession();
    if (this.authenticationPlugins == null) {
        loadAuthenticationPlugins();
    }
    boolean forChangeUser = true;
    if (challenge != null) {
        this.serverDefaultAuthenticationPluginName = challenge.readString(StringSelfDataType.STRING_TERM, "ASCII");
        forChangeUser = false;
    }
    serverSession.getCharsetSettings().configurePreHandshake(forChangeUser);
    /*
         * Select the initial plugin:
         * Choose the client-side default authentication plugin, if explicitely specified, otherwise choose the server-side default authentication plugin.
         */
    String pluginName;
    if (this.clientDefaultAuthenticationPluginExplicitelySet) {
        pluginName = this.clientDefaultAuthenticationPluginName;
    } else {
        pluginName = this.serverDefaultAuthenticationPluginName != null ? this.serverDefaultAuthenticationPluginName : this.clientDefaultAuthenticationPluginName;
    }
    AuthenticationPlugin<NativePacketPayload> plugin = getAuthenticationPlugin(pluginName);
    if (plugin == null) {
        /* Use default if there is no plugin for pluginName. */
        pluginName = this.clientDefaultAuthenticationPluginName;
        plugin = getAuthenticationPlugin(pluginName);
    }
    boolean skipPassword = false;
    if (pluginName.equals(Sha256PasswordPlugin.PLUGIN_NAME) && !pluginName.equals(this.clientDefaultAuthenticationPluginName) && !this.protocol.getSocketConnection().isSSLEstablished() && this.propertySet.getStringProperty(PropertyKey.serverRSAPublicKeyFile).getValue() == null && !this.propertySet.getBooleanProperty(PropertyKey.allowPublicKeyRetrieval).getValue()) {
        /*
             * Fall back to client default if plugin is 'sha256_password' but required conditions for this to work aren't met.
             * If client default is other than 'sha256_password', this will result in an immediate authentication switch request, allowing for other plugins to
             * authenticate successfully. If client default is 'sha256_password' then the authentication will fail as expected. In both cases user's password
             * won't be sent to avoid subjecting it to lesser security levels.
             */
        plugin = getAuthenticationPlugin(this.clientDefaultAuthenticationPluginName);
        skipPassword = true;
    }
    checkConfidentiality(plugin);
    // Servers not affected by Bug#70865 expect the Change User Request containing a correct answer to seed sent by the server during the initial handshake,
    // thus we reuse it here. Servers affected by Bug#70865 will just ignore it and send the Auth Switch.
    NativePacketPayload fromServer = new NativePacketPayload(StringUtils.getBytes(this.seed));
    String sourceOfAuthData = this.serverDefaultAuthenticationPluginName;
    boolean old_raw_challenge = false;
    NativePacketPayload last_sent = null;
    NativePacketPayload last_received = challenge;
    ArrayList<NativePacketPayload> toServer = new ArrayList<>();
    /* Max iterations number */
    int counter = 100;
    while (0 < counter--) {
        /*
             * call plugin
             */
        plugin.setAuthenticationParameters(this.username, skipPassword ? null : this.password);
        plugin.setSourceOfAuthData(sourceOfAuthData);
        plugin.nextAuthenticationStep(fromServer, toServer);
        /*
             * send response to server
             */
        if (toServer.size() > 0) {
            if (forChangeUser) {
                // write COM_CHANGE_USER Packet
                last_sent = createChangeUserPacket(serverSession, plugin.getProtocolPluginName(), toServer);
                this.protocol.send(last_sent, last_sent.getPosition());
                // this branch should be executed only once
                forChangeUser = false;
            } else if (last_received.isAuthMethodSwitchRequestPacket() || last_received.isAuthMoreData() || old_raw_challenge) {
                // write AuthSwitchResponse packet or raw packet(s)
                for (NativePacketPayload buffer : toServer) {
                    this.protocol.send(buffer, buffer.getPayloadLength());
                }
            } else {
                // write HandshakeResponse packet
                last_sent = createHandshakeResponsePacket(serverSession, plugin.getProtocolPluginName(), toServer);
                this.protocol.send(last_sent, last_sent.getPosition());
            }
        }
        /*
             * read packet from server
             */
        last_received = this.protocol.checkErrorMessage();
        old_raw_challenge = false;
        if (last_received.isOKPacket()) {
            // read OK packet
            OkPacket ok = OkPacket.parse(last_received, null);
            serverSession.setStatusFlags(ok.getStatusFlags(), true);
            serverSession.getServerSessionStateController().setSessionStateChanges(ok.getSessionStateChanges());
            // if OK packet then finish handshake
            plugin.destroy();
            break;
        } else if (last_received.isAuthMethodSwitchRequestPacket()) {
            // read AuthSwitchRequest Packet
            skipPassword = false;
            pluginName = last_received.readString(StringSelfDataType.STRING_TERM, "ASCII");
            if (plugin.getProtocolPluginName().equals(pluginName)) {
                // just reset the current one
                plugin.reset();
            } else {
                // get new plugin
                plugin.destroy();
                plugin = getAuthenticationPlugin(pluginName);
                if (plugin == null) {
                    throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.BadAuthenticationPlugin", new Object[] { pluginName }), getExceptionInterceptor());
                }
            }
            checkConfidentiality(plugin);
            fromServer = new NativePacketPayload(last_received.readBytes(StringSelfDataType.STRING_EOF));
        } else {
            // read raw packet
            if (!this.protocol.versionMeetsMinimum(5, 5, 16)) {
                old_raw_challenge = true;
                last_received.setPosition(last_received.getPosition() - 1);
            }
            fromServer = new NativePacketPayload(last_received.readBytes(StringSelfDataType.STRING_EOF));
        }
        sourceOfAuthData = pluginName;
    }
    if (counter == 0) {
        throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("CommunicationsException.TooManyAuthenticationPluginNegotiations"), getExceptionInterceptor());
    }
    this.protocol.afterHandshake();
    if (!this.useConnectWithDb) {
        this.protocol.changeDatabase(this.database);
    }
}
Also used : ServerSession(com.mysql.cj.protocol.ServerSession) OkPacket(com.mysql.cj.protocol.a.result.OkPacket) ArrayList(java.util.ArrayList) WrongArgumentException(com.mysql.cj.exceptions.WrongArgumentException)

Example 5 with ServerSession

use of com.mysql.cj.protocol.ServerSession in project JavaSegundasQuintas by ecteruel.

the class NativeAuthenticationProvider method connect.

/**
 * Initialize communications with the MySQL server. Handles logging on, and
 * handling initial connection errors.
 *
 * @param user
 *            user name
 * @param pass
 *            password
 * @param db
 *            database name
 */
@Override
public void connect(String user, String pass, String db) {
    ServerSession sessState = this.protocol.getServerSession();
    this.username = user;
    this.password = pass;
    this.database = db;
    NativeCapabilities capabilities = (NativeCapabilities) sessState.getCapabilities();
    NativePacketPayload buf = capabilities.getInitialHandshakePacket();
    SslMode sslMode = this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue();
    int capabilityFlags = capabilities.getCapabilityFlags();
    if (((capabilityFlags & NativeServerSession.CLIENT_SSL) == 0) && sslMode != SslMode.DISABLED && sslMode != SslMode.PREFERRED) {
        // check SSL availability
        throw ExceptionFactory.createException(UnableToConnectException.class, Messages.getString("MysqlIO.15"), getExceptionInterceptor());
    } else if ((capabilityFlags & NativeServerSession.CLIENT_SECURE_CONNECTION) == 0) {
        // TODO: better messaging
        throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_SECURE_CONNECTION is required", getExceptionInterceptor());
    } else if ((capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH) == 0) {
        // TODO: better messaging
        throw ExceptionFactory.createException(UnableToConnectException.class, "CLIENT_PLUGIN_AUTH is required", getExceptionInterceptor());
    }
    // read status flags (2 bytes)
    sessState.setStatusFlags(capabilities.getStatusFlags());
    int authPluginDataLength = capabilities.getAuthPluginDataLength();
    StringBuilder fullSeed = new StringBuilder(authPluginDataLength > 0 ? authPluginDataLength : NativeConstants.SEED_LENGTH);
    // read auth-plugin-data-part-1 (string[8])
    fullSeed.append(capabilities.getSeed());
    fullSeed.append(// read string[$len] auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))
    authPluginDataLength > 0 ? buf.readString(StringLengthDataType.STRING_FIXED, "ASCII", authPluginDataLength - 8) : buf.readString(StringSelfDataType.STRING_TERM, "ASCII"));
    this.seed = fullSeed.toString();
    this.useConnectWithDb = (this.database != null) && (this.database.length() > 0) && !this.propertySet.getBooleanProperty(PropertyKey.createDatabaseIfNotExist).getValue();
    long clientParam = NativeServerSession.CLIENT_SECURE_CONNECTION | NativeServerSession.CLIENT_PLUGIN_AUTH | // 
    (capabilityFlags & NativeServerSession.CLIENT_LONG_PASSWORD) | // 
    (capabilityFlags & NativeServerSession.CLIENT_PROTOCOL_41) | // Need this to get server status values
    (capabilityFlags & NativeServerSession.CLIENT_TRANSACTIONS) | // We always allow multiple result sets
    (capabilityFlags & NativeServerSession.CLIENT_MULTI_RESULTS) | // We always allow multiple result sets for SSPS
    (capabilityFlags & NativeServerSession.CLIENT_PS_MULTI_RESULTS) | // 
    (capabilityFlags & NativeServerSession.CLIENT_LONG_FLAG) | // 
    (capabilityFlags & NativeServerSession.CLIENT_DEPRECATE_EOF) | (capabilityFlags & NativeServerSession.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) | (capabilityFlags & NativeServerSession.CLIENT_QUERY_ATTRIBUTES) | (this.propertySet.getBooleanProperty(PropertyKey.useCompression).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_COMPRESS) : 0) | (this.useConnectWithDb ? (capabilityFlags & NativeServerSession.CLIENT_CONNECT_WITH_DB) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.useAffectedRows).getValue() ? 0 : (capabilityFlags & NativeServerSession.CLIENT_FOUND_ROWS)) | (this.propertySet.getBooleanProperty(PropertyKey.allowLoadLocalInfile).getValue() || this.propertySet.getStringProperty(PropertyKey.allowLoadLocalInfileInPath).isExplicitlySet() ? (capabilityFlags & NativeServerSession.CLIENT_LOCAL_FILES) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.interactiveClient).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_INTERACTIVE) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.allowMultiQueries).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_MULTI_STATEMENTS) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.disconnectOnExpiredPasswords).getValue() ? 0 : (capabilityFlags & NativeServerSession.CLIENT_CAN_HANDLE_EXPIRED_PASSWORD)) | (NONE.equals(this.propertySet.getStringProperty(PropertyKey.connectionAttributes).getValue()) ? 0 : (capabilityFlags & NativeServerSession.CLIENT_CONNECT_ATTRS)) | (this.propertySet.<SslMode>getEnumProperty(PropertyKey.sslMode).getValue() != SslMode.DISABLED ? (capabilityFlags & NativeServerSession.CLIENT_SSL) : 0) | (this.propertySet.getBooleanProperty(PropertyKey.trackSessionState).getValue() ? (capabilityFlags & NativeServerSession.CLIENT_SESSION_TRACK) : 0);
    sessState.setClientParam(clientParam);
    /* First, negotiate SSL connection */
    if ((clientParam & NativeServerSession.CLIENT_SSL) != 0) {
        this.protocol.negotiateSSLConnection();
    }
    if (buf.isOKPacket()) {
        throw ExceptionFactory.createException(Messages.getString("AuthenticationProvider.UnexpectedAuthenticationApproval"), getExceptionInterceptor());
    }
    proceedHandshakeWithPluggableAuthentication(buf);
    this.password = null;
}
Also used : ServerSession(com.mysql.cj.protocol.ServerSession) SslMode(com.mysql.cj.conf.PropertyDefinitions.SslMode) UnableToConnectException(com.mysql.cj.exceptions.UnableToConnectException)

Aggregations

ServerSession (com.mysql.cj.protocol.ServerSession)6 SslMode (com.mysql.cj.conf.PropertyDefinitions.SslMode)4 UnableToConnectException (com.mysql.cj.exceptions.UnableToConnectException)4 WrongArgumentException (com.mysql.cj.exceptions.WrongArgumentException)3 OkPacket (com.mysql.cj.protocol.a.result.OkPacket)3 ArrayList (java.util.ArrayList)3 Constants (com.mysql.cj.Constants)1 Messages (com.mysql.cj.Messages)1 MysqlCallbackHandler (com.mysql.cj.callback.MysqlCallbackHandler)1 UsernameCallback (com.mysql.cj.callback.UsernameCallback)1 PropertyKey (com.mysql.cj.conf.PropertyKey)1 PropertySet (com.mysql.cj.conf.PropertySet)1 RuntimeProperty (com.mysql.cj.conf.RuntimeProperty)1 ExceptionFactory (com.mysql.cj.exceptions.ExceptionFactory)1 ExceptionInterceptor (com.mysql.cj.exceptions.ExceptionInterceptor)1 AuthenticationPlugin (com.mysql.cj.protocol.AuthenticationPlugin)1 AuthenticationProvider (com.mysql.cj.protocol.AuthenticationProvider)1 Protocol (com.mysql.cj.protocol.Protocol)1 IntegerDataType (com.mysql.cj.protocol.a.NativeConstants.IntegerDataType)1 StringLengthDataType (com.mysql.cj.protocol.a.NativeConstants.StringLengthDataType)1