protected boolean handleUserAuthRequestMessage()

in sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java [206:342]


    protected boolean handleUserAuthRequestMessage(
            ServerSession session, Buffer buffer, AtomicReference<Boolean> authHolder)
            throws Exception {
        boolean debugEnabled = log.isDebugEnabled();
        /*
         * According to RFC4252 section 5.1:
         *
         *
         * When SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication requests received after that SHOULD
         * be silently ignored.
         */
        if (session.isAuthenticated()) {
            String username = buffer.getString();
            String service = buffer.getString();
            String method = buffer.getString();

            if (debugEnabled) {
                log.debug("handleUserAuthRequestMessage({}) ignore user={}, service={}, method={}"
                          + " auth. request since session already authenticated",
                        session, username, service, method);
            }
            return false;
        }

        if (WelcomeBannerPhase.FIRST_REQUEST.equals(getWelcomePhase())) {
            sendWelcomeBanner(session);
        }

        if (currentAuth != null) {
            try {
                currentAuth.destroy();
            } finally {
                currentAuth = null;
            }
        }

        String username = buffer.getString();
        String service = buffer.getString();
        String method = buffer.getString();
        if (debugEnabled) {
            log.debug("handleUserAuthRequestMessage({}) Received SSH_MSG_USERAUTH_REQUEST user={}, service={}, method={}",
                    session, username, service, method);
        }

        if ((this.authUserName == null) || (this.authService == null)) {
            this.authUserName = username;
            this.authService = service;
        } else if (this.authUserName.equals(username) && this.authService.equals(service)) {
            nbAuthRequests++;
            if (nbAuthRequests > maxAuthRequests) {
                boolean disconnectSession = true;
                try {
                    SessionDisconnectHandler handler = session.getSessionDisconnectHandler();
                    disconnectSession = (handler == null)
                            || (!handler.handleAuthCountDisconnectReason(
                                    session, this, service, method, username, nbAuthRequests, maxAuthRequests));
                } catch (IOException | RuntimeException e) {
                    warn("handleUserAuthRequestMessage({}) failed ({}) to invoke disconnect handler due to"
                         + " user={}/{}, service={}/{} - {}/{} auth requests: {}",
                            session, e.getClass().getSimpleName(),
                            this.authUserName, username, this.authService, service,
                            nbAuthRequests, maxAuthRequests, e.getMessage(), e);
                }

                if (disconnectSession) {
                    session.disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
                            "Too many authentication failures: " + nbAuthRequests);
                    return false;
                }

                if (debugEnabled) {
                    log.debug(
                            "handleUserAuthRequestMessage({}) ignore mismatched authentication counts: user={}/{}, service={}/{}: {}/{}",
                            session, this.authUserName, username, this.authService, service, nbAuthRequests, maxAuthRequests);
                }
            }
        } else {
            boolean disconnectSession = true;
            try {
                SessionDisconnectHandler handler = session.getSessionDisconnectHandler();
                disconnectSession = (handler == null)
                        || (!handler.handleAuthParamsDisconnectReason(
                                session, this, this.authUserName, username, this.authService, service));
            } catch (IOException | RuntimeException e) {
                warn("handleUserAuthRequestMessage({}) failed ({}) to invoke disconnect handler due to"
                     + " user={}/{}, service={}/{} mismatched parameters: {}",
                        session, e.getClass().getSimpleName(),
                        this.authUserName, username, this.authService, service, e.getMessage(), e);
            }

            if (disconnectSession) {
                session.disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
                        "Change of username or service is not allowed (" + this.authUserName + ", " + this.authService + ")"
                                                                                + " -> (" + username + ", " + service + ")");
            } else {
                if (debugEnabled) {
                    log.debug(
                            "handleUserAuthRequestMessage({}) ignore mismatched authentication parameters: user={}/{}, service={}/{}",
                            session, this.authUserName, username, this.authService, service);
                }
            }
            return false;
        }

        // TODO: verify that the service is supported
        this.authMethod = method;
        if (debugEnabled) {
            log.debug(
                    "handleUserAuthRequestMessage({}) Authenticating user '{}' with service '{}' and method '{}' (attempt {} / {})",
                    session, username, service, method, nbAuthRequests, maxAuthRequests);
        }

        UserAuthFactory factory = NamedResource.findByName(
                method, String.CASE_INSENSITIVE_ORDER, userAuthFactories);
        if (factory == null) {
            if (debugEnabled) {
                log.debug("handleUserAuthRequestMessage({}) no authentication factory for method={}", session, method);
            }

            return true;
        }

        currentAuth = ValidateUtils.checkNotNull(
                factory.createUserAuth(session), "No authenticator created for method=%s", method);
        try {
            Boolean authed = currentAuth.auth(session, username, service, buffer);
            authHolder.set(authed);
        } catch (AsyncAuthException async) {
            async.addListener(authenticated -> asyncAuth(SshConstants.SSH_MSG_USERAUTH_REQUEST, buffer, authenticated));
            return false;
        } catch (Exception e) {
            warn("handleUserAuthRequestMessage({}) Failed ({}) to authenticate using factory method={}: {}",
                    session, e.getClass().getSimpleName(), method, e.getMessage(), e);
        }

        return true;
    }