polardbxengine/plugin/polarx_rpc/secure/auth_challenge_response.h

185 lines
6.5 KiB
C++

/*
* 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 <string>
#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 <Account_verification_interface::Account_type Auth_type,
typename Auth_verificator_t>
class Sasl_challenge_response_auth;
using Sasl_mysql41_auth =
Sasl_challenge_response_auth<Account_verification_interface::Account_native,
Native_verification>;
/**
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 <Account_verification_interface::Account_type Auth_type,
typename Auth_verificator_t>
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 <Account_verification_interface::Account_type Account_type,
typename Auth_verificator_t>
Authentication_interface_ptr
Sasl_challenge_response_auth<Account_type, Auth_verificator_t>::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<Account_type, Auth_verificator_t>(
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 <Account_verification_interface::Account_type Account_type,
typename Auth_verificator_t>
Authentication_interface::Response
Sasl_challenge_response_auth<Account_type, Auth_verificator_t>::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 <Account_verification_interface::Account_type Account_type,
typename Auth_verificator_t>
Authentication_interface::Response
Sasl_challenge_response_auth<Account_type, Auth_verificator_t>::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 <Account_verification_interface::Account_type Account_type,
typename Auth_verificator_t>
err_t Sasl_challenge_response_auth<Account_type, Auth_verificator_t>::
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