/* * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, * as published by the Free Software Foundation. * * This program is also distributed with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, * as designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have included with MySQL. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License, version 2.0, for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once #include #include "../utility/error.h" #include "account_verification_handler.h" #include "authentication_interface.h" #include "native_verification.h" #include "sha256_password_cache_interface.h" namespace polarx_rpc { class CtcpConnection; template class Sasl_challenge_response_auth; using Sasl_mysql41_auth = Sasl_challenge_response_auth; /** Class used for performing challenge response authentication. It is responsible for the following sequence: 'AUTH_METHOD' is either MYSQL41 or SHA256_MEMORY 'HASH' is SHA1 in case of MYSQL41 and SHA256 in case of SHA256_MEMORY C -> S: authenticationStart(AUTH_METHOD) S -> C: authenticationContinue(20 byte salt/scramble) C -> S: authenticationContinue(schema\0user\0HASH(HASH(password))+salt) S -> C: Notice(password expired etc) S -> C: authenticationOk/Error @tparam Auth_type Enum representing account verification type @tparam Auth_verificator_t Class that will be used for performing verification */ template class Sasl_challenge_response_auth : public Authentication_interface { public: explicit Sasl_challenge_response_auth(Account_verification_handler *handler) : m_verification_handler(handler), m_state(S_starting) {} static Authentication_interface_ptr create(CtcpConnection &tcp, SHA256_password_cache_interface *cache); Response handle_start(const std::string &, const std::string &, const std::string &) override; Response handle_continue(const std::string &data) override; err_t authenticate_account(const std::string &user, const std::string &host, const std::string &passwd) override; const Authentication_info &get_authentication_info() const override { return m_auth_info; } private: Account_verification_handler_ptr m_verification_handler; Authentication_info m_auth_info; enum State { S_starting, S_waiting_response, S_done, S_error } m_state; }; /** Create authentication class instance @param[in] session Session instance that will be used by the account verificator @param[in] cache Pointer to password cache used during account verification @return Pointer to authentication class instance */ template Authentication_interface_ptr Sasl_challenge_response_auth::create( CtcpConnection &tcp, SHA256_password_cache_interface *cache) { auto handler = new Account_verification_handler( tcp, Account_type, new Auth_verificator_t(cache)); return Authentication_interface_ptr( new Sasl_challenge_response_auth( handler)); } /** First phase of an authentication - send salt to the client @return Response message containing salt or error if we are on other phase of authentication */ template Authentication_interface::Response Sasl_challenge_response_auth::handle_start( const std::string &, const std::string &, const std::string &) { m_auth_info.reset(); if (m_state != S_starting) { m_state = S_error; return {Error, ER_NET_PACKETS_OUT_OF_ORDER}; } const Account_verification_interface *verificator = m_verification_handler->get_account_verificator(Account_type); DBUG_ASSERT(verificator); m_state = S_waiting_response; return {Ongoing, 0, verificator->get_salt()}; } /** Second phase of an authentication - given the response from the client verify if he is credible to be successfully authenticated @param[in] data Clients response @return Authentication response message @retval Error When called on wrong phase of challenge response authentication @retval Succeeded On successful authentication @retval Failed On unsuccessful authentication */ template Authentication_interface::Response Sasl_challenge_response_auth::handle_continue( const std::string &data) { if (m_state != S_waiting_response) { m_state = S_error; return {Error, ER_NET_PACKETS_OUT_OF_ORDER}; } m_state = S_done; if (err_t error = m_verification_handler->authenticate(*this, &m_auth_info, data)) return {Failed, error.error, error.message}; return {Succeeded}; } /** Authenicate user given his name, hostname and password @param[in] user User name @param[in] host Hostname @param[in] passwd Password provided by the user @return Result of user verification */ template err_t Sasl_challenge_response_auth:: authenticate_account(const std::string &user, const std::string &host, const std::string &passwd) { return m_verification_handler->verify_account(user, host, passwd, &m_auth_info); } } // namespace polarx_rpc