host/cxpslib/authentication.h (506 lines of code) (raw):
///
/// \file authentication.h
///
/// \brief authenticating login and requests
///
/// uses a slightly modified version http authentication.
///
/// the main differences are
///
/// \li \c does not use http headers to transmit the authentication
/// information. Instead it uses a login request to do that.
/// \li \c the client creates the "cnonce" and sends it as part of the login
/// request.
/// \li \c the session number is used as the count and will remains the same for
/// the entire session
/// \li \c once logged in, only the digest is sent with requests as both sides retain
/// all the data needed to generate the ids for validation.
///
#ifndef AUTHENTICATION_H
#define AUTHENTICATION_H
#include <sstream>
#include <iomanip>
#include <cstdlib>
#include <sys/timeb.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <boost/algorithm/string.hpp>
#include "scopeguard.h"
#include "cxps.h"
#include "securityutils.h"
/// \brief handles building and verifying authentication ids
class Authentication {
public:
/// \brief verifies the id sent with a login request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyLoginId(std::string const& hostId, ///< host id sent with the login request
std::string const& fingerprint, ///< server certificate fingerprint
std::string const& password, ///< connection passphrase
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& version, ///< request api version being used
std::string const& idToVerify) ///< digest sent by the requester
{
return (idsEqual(password, idToVerify, buildLoginId(hostId, fingerprint, password, method, request, cnonce, version)));
}
/// \brief builds the login id to be sent with a login request
///
/// \return string containing the id generated from the given params
static std::string buildLoginId(std::string const& hostId, ///< host id sent with the login request
std::string const& fingerprint, ///< server certificate fingerprint
std::string const& password, ///< connection passphrase
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& version)
{
std::stringstream a1;
a1 << hostId << ':' << fingerprint;
std::stringstream a2;
a2 << method << ':' << request << ':' << version;
std::stringstream a3;
a3 << cnonce << ':' << securitylib::genHmac(password.c_str(), password.size(), a1.str()) << ':' << securitylib::genHmac(password.c_str(), password.size(), a2.str());
return securitylib::genHmac(password.c_str(), password.size(), a3.str());
}
/// \brief verifies the id returned in response to a successful login
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyLoginResponseId(std::string const& hostId, ///< host id sent with the login request
std::string const& fingerprint, ///< server certificate fingerprint
std::string const& password, ///< connection passphrase
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& idToVerify) ///< digest to verify
{
return (idsEqual(password, idToVerify, buildLoginResponseId(hostId, fingerprint, password, method, request, cnonce, sessionId, snonce)));
}
/// \brief builds the login response id to be sent back to the requester in response
/// to a successful login
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildLoginResponseId(std::string const& hostId, ///< host id sent with the login request
std::string const& fingerprint, ///< server certificate fingerprint
std::string const& password, ///< connection passphrase
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce) ///< server generated snonce
{
std::stringstream a1;
a1 << hostId << ':' << fingerprint;
std::stringstream a2;
a2 << method << ':' << request;
std::stringstream a3;
a3 << cnonce << ':' << securitylib::genHmac(password.c_str(), password.size(), a1.str())
<< ':' << securitylib::genHmac(password.c_str(), password.size(), a2.str()) << sessionId << snonce;
return securitylib::genHmac(password.c_str(), password.size(), a3.str());
}
/// \brief builds the id that should be sent with a logout request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildLogoutId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::string params;
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId);
}
/// \brief verifies id sent with a logout request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyLogoutId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
std::string params;
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId, idToVerify);
}
/// \brief verifies id sent with a put file request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyPutFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& name, ///< name of file being put
char moreData, ///< more data to be sent in another putrequest 1i: yes, 0: no)
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
std::string params(name);
params += moreData;
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a put file request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildPutFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& name, ///< name of file being put
char moreData, ///< more data to be sent in another putrequest 1i: yes, 0: no)
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::string params(name);
params += moreData;
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId);
}
/// \brief verifies id sent with a get file request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyGetFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& name, ///< name of file to get
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, name, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a get file request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildGetFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& name, ///< name of file to get
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, name, version, reqId);
}
/// \brief verifies id sent with a rename file request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyRenameFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& oldName, ///< name of file to reanme
std::string const& newName, ///< new name to give the file
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
std::string params(oldName + newName);
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a rename file request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildRenameFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& oldName, ///< name of file to reanme
std::string const& newName, ///< new name to give the file
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::string params(oldName + newName);
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId);
}
/// \brief verifies id sent with a delete file request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyDeleteFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& names, ///< semi-colon seprated list of files and/or dirs to delete
std::string fileSpec, ///< file spec to use to match file/dir names when name in names is a dir
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
std::string params(names);
params += fileSpec;
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a delete file request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildDeleteFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& names, ///< semi-colon seprated list of files and/or dirs to delete
std::string fileSpec, ///< file spec to use to match file/dir names when name in names is a dir
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::string params(names);
params += fileSpec;
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId);
}
/// \brief verifies id sent with a list file request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyListFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& fileSpec, ///< file specification to list. Use stnadard glob syntax
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, fileSpec, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a list file request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildListFileId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& fileSpec, ///< file specification to list. Use stnadard glob syntax
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, fileSpec, version, reqId);
}
/// \brief verifies id sent with a cfs connect request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyCfsConnectBack(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< user password (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& cfsSessionId, ///< cfs session id
std::string const& secure, ///< secure mode yes|no
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
std::string params(cfsSessionId + secure);
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a cfs connect request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildCfsConnectBackId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< user password (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& cfsSessionId, ///< cfs session id
std::string const& secure, ///< secure mode yes|no
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::string params(cfsSessionId + secure);
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId);
}
/// \brief verifies id sent with a cfs connect request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
// NOTE: cfs connect is special as it does not require a valid login
// we really only want the connected native socket to pass back to the calling client
// that client will then re-establish a valid session using that connected native socket
// this is part of the CFS connect back that allows cxps to initiate connections to host machines
// so some of the normal params are not used, but with the hidden password, still secure enough
static bool verifyCfsConnect(std::string const& password, ///< user password (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cfsSessionId, ///< cfs session id
std::string const& secure, ///< secure mode yes|no
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
std::string notPresent("notpresent");
std::string params(cfsSessionId + secure);
return verifyId(notPresent, password, method, request, notPresent, notPresent, notPresent, params, version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a cfs connect request
///
/// \return
/// \li \c string containing the id generated from the given params
// NOTE: cfs connect is special as it does not require a valid login
// we really only want the connected native socket to pass back to the calling client
// that client will then re-establish a valid session using that connected native socket
// this is part of the CFS connect back that allows cxps to initiate connections to host machines
// so some of the normal params are not used, but with the hidden password, still secure enough
static std::string buildCfsConnectId(std::string const& password, ///< user password (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cfsSessionId, ///< cfs session id
std::string const& secure, ///< secure mode yes|no
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::string notPresent("notpresent");
std::string params(cfsSessionId + secure);
return buildId(notPresent, password, method, request, notPresent, notPresent, notPresent, params, version, reqId);
}
/// \brief verifies id sent with a heartbeat request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyHeartbeatId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
return verifyId(hostId, password, method, request, cnonce, sessionId, snonce, std::string(), version, reqId, idToVerify);
}
/// \brief builds the id that should be sent with a heartbeat request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildHeartbeatId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
return buildId(hostId, password, method, request, cnonce, sessionId, snonce, std::string(), version, reqId);
}
/// \brief verifies id sent with a getCfsConnectInfoId reply
///
/// \return
/// \li \c true: if digest matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyGetCfsConnectInfoId(std::string const& digest, ///< digest to be checked
std::string const& strToSign, ///< str to sign and verify
std::string const& password) ///< cxps password
{
std::string passphraseHash = securitylib::genSha256Mac(password.c_str(), password.size());
return idsEqual(passphraseHash, digest, securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), strToSign));
}
/// \brief builds the id that should be sent with a getCfsConnectInfoId request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildGetCfsConnectInfoId(char const* method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action being requested (see protocolhandler.h CS_ACTION_*)
std::string const& password, ///< cxps password
std::string const& version, ///< request api version being used
std::string const& nonce, ///< nonce
std::string const& id) ///< cxps id
{
std::string params(nonce + id);
return buildCsId(password, std::string(), method, url, action, params, version);
}
/// \brief verifies id sent with a cfsHeartbeat
///
/// \return
/// \li \c true: if digest matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyCfsHeartbeatId(std::string const& digest, ///< digest to be checked
char const* method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action being requested (see protocolhandler.h CS_ACTION_*)
std::string const& password, ///< cxps password
std::string const& version, ///< request api version being used
std::string const& nonce, ///< nonce
std::string const& id) ///< cxps id
{
std::string params(nonce + id);
return idsEqual(password, digest, buildCsId(password, std::string(), method, url, action, params, version));
}
/// \brief builds the id that should be sent with a cfsError
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildCfsHeartbeatId(char const* method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action being requested (see protocolhandler.h CS_ACTION_*)
std::string const& password, ///< cxps password
std::string const& version, ///< request api version being used
std::string const& nonce, ///< nonce
std::string const& id) ///< cxps id
{
std::string params(nonce + id);
return buildCsId(password, std::string(), method, url, action, params, version);
}
/// \brief verifies id sent with a cfsError request
///
/// \return
/// \li \c true: if digest matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyCfsErrorId(std::string const& digest, ///< digest to be checked
char const* method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action being requested (see protocolhandler.h CS_ACTION_*)
std::string const& password, ///< cxps password
std::string const& version, ///< request api version being used
std::string const& nonce, ///< nonce
std::string const& id, ///< cxps id
std::string const& msg) ///< message being sent
{
std::string params(nonce + id + msg);
return idsEqual(password, digest, buildCsId(password, std::string(), method, url, action, params, version));
}
/// \brief builds the id that should be sent with a getCfsConnectInfoId request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildCfsErrorId(char const* method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action being requested (see protocolhandler.h CS_ACTION_*)
std::string const& password, ///< cxps password
std::string const& version, ///< request api version being used
std::string const& nonce, ///< nonce
std::string const& id, ///< cxps id
std::string const& msg) ///< message being sent
{
std::string params(nonce + id + msg);
return buildCsId(password, std::string(), method, url, action, params, version);
}
/// \brief checks if version is pre 2014-08-01 and current version is 2014-08-01
///
/// \return bool true: if pre version is OK
// will support no version number to
// allow previous versions that do not use version to still
// work after that will require version to be present (i.e. require
// clients to upgrade once cxps is at version after 2014-08-01
static bool versionRequired(std::string const& version)
{
return (!(version.empty() || boost::algorithm::equals(REQUEST_VER_CURRENT, REQUEST_VER_2014_08_01)));
}
/// \brief builds the id that should be sent with a cslogin request
///
/// \return
/// \li \c string containing the id generated from the given params
static bool verifyCsLoginReplyId(std::string const& id, ///< id sent with csLogin
std::string const& status, ///< status returned with csLogin reply
std::string const& action, ///< action returned with csLogin reply
std::string const& passphrase, ///< passphrase
std::string const& fingerprint, ///< cs cert fingerprint
std::string const& nonce, ///< nonce returned in csLogin reply
std::string const& version, ///< request api version being used
std::string const& verifyId) ///< digest to verify
{
std::string passphraseHash = securitylib::genSha256Mac(passphrase.c_str(), passphrase.size());
std::stringstream a1;
if (!fingerprint.empty()) {
a1 << securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), boost::algorithm::to_lower_copy(fingerprint));
}
std::stringstream a2;
a2 << id << ':' << status << ':' << action << ':' << nonce << ':' << version;
std::stringstream a3;
a3 << a1.str() << ':' << securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), a2.str());
return idsEqual(passphraseHash, verifyId, securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), a3.str()));
}
/// \brief builds the id that should be sent with a csLogin request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildCsLoginId(char const* method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action being requested (see protocolhandler.h CS_ACTION_*)
std::string const& passphrase, ///< passphrase
std::string const& fingerprint, ///< cs cert fingerprint
std::string nonce, ///< nonce
std::string const& version) ///< request api version being used
{
return buildCsId(passphrase, fingerprint, method, url, action, nonce, version);
}
protected:
/// \brief helper function to verify an id for a given request
///
/// \return
/// \li \c true: if idToVerify matches the id genereted from the given params
/// \li \c false: otherwise
static bool verifyId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& params, ///< the given request parameters concatenated together
std::string const& version, ///< request api version being used
boost::uint32_t reqId, ///< request id
std::string const& idToVerify) ///< digest to verify
{
return idsEqual(password, idToVerify, buildId(hostId, password, method, request, cnonce, sessionId, snonce, params, version, reqId));
}
/// \brief helper function to build the id that should be sent with the given request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildId(std::string const& hostId, ///< host id sent with the login request
std::string const& password, ///< connection passphrase (stored locally, not sent)
std::string const& method, ///< http method
std::string const& request, ///< login request
std::string const& cnonce, ///< cnonce sent by requester
std::string const& sessionId, ///< session id of the current connection
std::string const& snonce, ///< server generated snonce
std::string const& params, ///< the given request parameters concatenated together
std::string const& version, ///< request api version being used
boost::uint32_t reqId) ///< request id
{
std::stringstream a1;
a1 << hostId;
std::stringstream a2;
a2 << method << ':' << request << ':' << params << ':' << version;
std::stringstream a3;
a3 << cnonce << ':' << securitylib::genHmac(password.c_str(), password.size(), a1.str()) << ':' << securitylib::genHmac(password.c_str(), password.size(), a2.str()) << sessionId << snonce;
if (0 != reqId) {
a3 << reqId;
}
return securitylib::genHmac(password.c_str(), password.size(), a3.str());
}
/// \brief generates an md5 digest from the given string
///
/// \return
/// \li \c string containing the digest
static std::string genDigest(std::string const& str) ///< string holding data used to genereate md5 hash
{
unsigned char digest[MD5_DIGEST_LENGTH];
MD5((unsigned char const *)str.c_str(), str.length(), digest);
std::stringstream digestStr;
for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
digestStr << std::hex << std::setw(2) << std::setfill('0') << (unsigned short)(digest[i]);
}
return digestStr.str();
}
/// \brief helper function to build the cs id that should be sent with the given request
///
/// \return
/// \li \c string containing the id generated from the given params
static std::string buildCsId(std::string const& passphrase, ///< connection passphrase
std::string const& fingerprint, ///< server certificate fingerprint
std::string const& method, ///< HTTP method (GET, POST, etc.)
std::string const& url, ///< url (technically the php script with out params)
char const* action, ///< action (one of the CS_ACTION_*)
std::string const& params, ///< the given request parameters concatenated together
std::string const& version) ///< request api version being used
{
std::string passphraseHash = securitylib::genSha256Mac(passphrase.c_str(), passphrase.size());
std::stringstream a1;
if (!fingerprint.empty()) {
a1 << securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), boost::algorithm::to_lower_copy(fingerprint));
}
std::stringstream a2;
a2 << method << ':';
if (!url.empty())
a2 << url << ':';
a2 << action << ':' << params << ':' << version;
std::stringstream a3;
a3 << a1.str() << ':' << securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), a2.str());
return securitylib::genHmac(passphraseHash.c_str(), passphraseHash.size(), a3.str());
}
static bool idsEqual(std::string const& password, std::string const& lhsId, std::string const& rhsId)
{
// NOTE: case does not matter as we always convert to hex so binary 10 converted to hex can be either 0xa or 0xA
return boost::algorithm::iequals(securitylib::genHmac(password.c_str(), password.size(), lhsId), securitylib::genHmac(password.c_str(), password.size(), rhsId));
}
private:
};
#endif // AUTHENTICATION_H