public boolean nextAuthenticationStep()

in src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/AuthenticationLdapSaslClientPlugin.java [196:321]


    public boolean nextAuthenticationStep(NativePacketPayload fromServer, List<NativePacketPayload> toServer) {
        toServer.clear();

        if (this.saslClient == null) {
            // First packet: initialize a SASL client for the requested mechanism.
            String authMechId = fromServer.readString(StringSelfDataType.STRING_EOF, "ASCII");
            try {
                this.authMech = AuthenticationMechanisms.fromValue(authMechId);
            } catch (CJException e) {
                if (this.firstPass) {
                    this.firstPass = false;
                    // Payload could be a salt (auth-plugin-data) value instead of an authentication mechanism identifier.
                    // Give it another try in the expectation of receiving a Protocol::AuthSwitchRequest or a Protocol::AuthNextFactor next time.
                    return true;
                }
                throw e;
            }
            this.firstPass = false;

            try {
                switch (this.authMech) {
                    case GSSAPI:
                        // Figure out the LDAP Server hostname.
                        String ldapServerHostname = this.protocol.getPropertySet().getStringProperty(PropertyKey.ldapServerHostname).getValue();
                        if (StringUtils.isNullOrEmpty(ldapServerHostname)) { // Use the default KDC short name instead.
                            String krb5Kdc = System.getProperty("java.security.krb5.kdc");
                            if (!StringUtils.isNullOrEmpty(krb5Kdc)) {
                                ldapServerHostname = krb5Kdc;
                                int dotIndex = krb5Kdc.indexOf('.');
                                if (dotIndex > 0) {
                                    ldapServerHostname = krb5Kdc.substring(0, dotIndex).toLowerCase(Locale.ENGLISH);
                                }
                            }
                        }
                        if (StringUtils.isNullOrEmpty(ldapServerHostname)) {
                            throw ExceptionFactory.createException(Messages.getString("AuthenticationLdapSaslClientPlugin.MissingLdapServerHostname"));
                        }

                        // Validate JAAS login module configuration.
                        boolean validJaasLoginConfig = false;
                        Configuration config = java.security.AccessController.doPrivileged((PrivilegedAction<Configuration>) Configuration::getConfiguration);
                        AppConfigurationEntry[] cfgEntries = config.getAppConfigurationEntry(LOGIN_CONFIG_ENTRY);
                        if (cfgEntries != null && cfgEntries.length > 0) {
                            for (AppConfigurationEntry cfgEntry : cfgEntries) {
                                if (!"com.sun.security.auth.module.Krb5LoginModule".equals(cfgEntry.getLoginModuleName())) {
                                    throw ExceptionFactory.createException(Messages.getString("AuthenticationLdapSaslClientPlugin.InvalidLoginModuleDetected"));
                                }
                            }
                            validJaasLoginConfig = true;
                        }

                        // In-memory login configuration. Used only if no valid JAAS login config was specified by 'java.security.auth.login.config'.
                        Configuration loginConfig = null;
                        if (!validJaasLoginConfig) {
                            final String localUser = this.user;
                            final boolean debug = Boolean.getBoolean("sun.security.jgss.debug");
                            loginConfig = new Configuration() {

                                @Override
                                public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                                    Map<String, String> options = new HashMap<>();
                                    options.put("useTicketCache", "true");
                                    options.put("renewTGT", "false");
                                    options.put("principal", localUser);
                                    options.put("debug", Boolean.toString(debug)); // Hook debugging on system property 'sun.security.jgss.debug'.
                                    return new AppConfigurationEntry[] { new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
                                            AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options) };
                                }

                            };
                        }

                        // Login into Kerberos service and obtain subject/credentials.
                        LoginContext loginContext = new LoginContext(LOGIN_CONFIG_ENTRY, null, this.credentialsCallbackHandler, loginConfig);
                        loginContext.login();
                        this.subject = loginContext.getSubject();

                        // Create a GSSAPI SASL client using the credentials stored in this thread's Subject.
                        try {
                            final String localLdapServerHostname = ldapServerHostname;
                            this.saslClient = Subject.doAs(this.subject,
                                    (PrivilegedExceptionAction<SaslClient>) () -> Sasl.createSaslClient(new String[] { this.authMech.getSaslServiceName() },
                                            null, LDAP_SERVICE_NAME, localLdapServerHostname, null, null));
                        } catch (PrivilegedActionException e) {
                            // SaslException is the only checked exception that can be thrown.
                            throw (SaslException) e.getException();
                        }
                        break;

                    case SCRAM_SHA_1:
                    case SCRAM_SHA_256:
                        this.saslClient = Sasl.createSaslClient(new String[] { this.authMech.getSaslServiceName() }, null, null, null, null,
                                this.credentialsCallbackHandler);
                        break;
                }
            } catch (LoginException | SaslException e) {
                throw ExceptionFactory.createException(
                        Messages.getString("AuthenticationLdapSaslClientPlugin.FailCreateSaslClient", new Object[] { this.authMech.getMechName() }), e);
            }

            if (this.saslClient == null) {
                throw ExceptionFactory.createException(
                        Messages.getString("AuthenticationLdapSaslClientPlugin.FailCreateSaslClient", new Object[] { this.authMech.getMechName() }));
            }
        }

        if (!this.saslClient.isComplete()) {
            // All packets: send payload to the SASL client.
            try {
                Subject.doAs(this.subject, (PrivilegedExceptionAction<Void>) () -> {
                    byte[] response = this.saslClient.evaluateChallenge(fromServer.readBytes(StringSelfDataType.STRING_EOF));
                    if (response != null) {
                        NativePacketPayload packet = new NativePacketPayload(response);
                        packet.setPosition(0);
                        toServer.add(packet);
                    }
                    return null;
                });
            } catch (PrivilegedActionException e) {
                throw ExceptionFactory.createException(
                        Messages.getString("AuthenticationLdapSaslClientPlugin.ErrProcessingAuthIter", new Object[] { this.authMech.getMechName() }),
                        e.getException());
            }
        }
        return true;
    }