mirror of
https://gitee.com/TarsCloud/TarsCpp.git
synced 2024-12-22 22:16:38 +08:00
277 lines
8.0 KiB
C++
277 lines
8.0 KiB
C++
/**
|
||
* Tencent is pleased to support the open source community by making Tars available.
|
||
*
|
||
* Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
|
||
*
|
||
* Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
|
||
* in compliance with the License. You may obtain a copy of the License at
|
||
*
|
||
* https://opensource.org/licenses/BSD-3-Clause
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software distributed
|
||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||
* specific language governing permissions and limitations under the License.
|
||
*/
|
||
|
||
#include "util/tc_epoll_server.h"
|
||
#include "util/tc_des.h"
|
||
#include "util/tc_sha.h"
|
||
#include "util/tc_md5.h"
|
||
#include "servant/Application.h"
|
||
#include "servant/AuthLogic.h"
|
||
#include <iostream>
|
||
#include <cassert>
|
||
|
||
|
||
namespace tars
|
||
{
|
||
|
||
bool processAuth(TC_EpollServer::Connection *conn, const shared_ptr<TC_EpollServer::RecvContext> &data)
|
||
{
|
||
conn->tryInitAuthState(AUTH_INIT);
|
||
|
||
if (conn->_authState == AUTH_SUCC)
|
||
return false; // data to be processed
|
||
|
||
TC_EpollServer::BindAdapterPtr adapter = data->adapter();
|
||
|
||
int type = adapter->getEndpoint().getAuthType();
|
||
if (type == AUTH_TYPENONE)
|
||
{
|
||
adapter->getEpollServer()->info("[TARS]processAuth no need auth func, auth succ");
|
||
conn->_authState = AUTH_SUCC;
|
||
return false;
|
||
}
|
||
|
||
// got auth request
|
||
RequestPacket request;
|
||
|
||
if (adapter->isTarsProtocol())
|
||
{
|
||
TarsInputStream<BufferReader> is;
|
||
|
||
is.setBuffer(data->buffer().data(), data->buffer().size());
|
||
|
||
try
|
||
{
|
||
request.readFrom(is);
|
||
}
|
||
catch(...)
|
||
{
|
||
adapter->getEpollServer()->error("[TARS]processAuth tars protocol decode error, close connection.");
|
||
|
||
conn->setClose();
|
||
return true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
request.sBuffer = data->buffer();
|
||
}
|
||
|
||
int currentState = conn->_authState;
|
||
int newstate = tars::defaultProcessAuthReq(request.sBuffer.data(), request.sBuffer.size(), adapter->getName());
|
||
std::string out = tars::etos((tars::AUTH_STATE)newstate);
|
||
|
||
if (newstate < 0)
|
||
{
|
||
// 验证错误,断开连接
|
||
adapter->getEpollServer()->error("authProcess failed with new state [" + out + "]");
|
||
conn->setClose();
|
||
return true;
|
||
}
|
||
|
||
adapter->getEpollServer()->info(TC_Common::tostr(conn->getId()) + "'s auth response[" + out + "], change state from " +
|
||
tars::etos((tars::AUTH_STATE)currentState) + " to " + out);
|
||
conn->_authState = newstate;
|
||
|
||
shared_ptr<TC_EpollServer::SendContext> sData = data->createSendContext();
|
||
|
||
if (adapter->isTarsProtocol())
|
||
{
|
||
TarsOutputStream<BufferWriterVector> os;
|
||
|
||
ResponsePacket response;
|
||
response.iVersion = TARSVERSION;
|
||
response.iRequestId = request.iRequestId;
|
||
response.iMessageType = request.iMessageType;
|
||
response.cPacketType = request.cPacketType;
|
||
response.iRet = 0;
|
||
response.sBuffer.assign(out.begin(), out.end());
|
||
|
||
tars::Int32 iHeaderLen = 0;
|
||
|
||
// 先预留4个字节长度
|
||
os.writeBuf((const char *)&iHeaderLen, sizeof(iHeaderLen));
|
||
|
||
response.writeTo(os);
|
||
|
||
vector<char> buff;
|
||
|
||
buff.swap(os.getByteBuffer());
|
||
|
||
assert(buff.size() >= 4);
|
||
|
||
iHeaderLen = htonl((int)(buff.size()));
|
||
|
||
memcpy((void*)buff.data(), (const char *)&iHeaderLen, sizeof(iHeaderLen));
|
||
|
||
sData->buffer()->swap(buff);
|
||
}
|
||
else
|
||
{
|
||
sData->buffer()->assign(out.c_str(), out.size());
|
||
}
|
||
|
||
adapter->getEpollServer()->send(sData);
|
||
|
||
return true; // processed
|
||
}
|
||
|
||
|
||
int processAuthReqHelper(const BasicAuthPackage& pkg, const BasicAuthInfo& info)
|
||
{
|
||
// 明文:objName, accessKey, time, hashMethod
|
||
// 密文:use TmpKey to enc secret1;
|
||
// and tmpKey = sha1(secret2 | timestamp);
|
||
if (pkg.sObjName != info.sObjName)
|
||
return AUTH_WRONG_OBJ;
|
||
|
||
if (pkg.sAccessKey != info.sAccessKey)
|
||
return AUTH_WRONG_AK;
|
||
|
||
time_t now = TNOW;
|
||
const int range = 60 * 60;
|
||
if (!(pkg.iTime > (now - range) && pkg.iTime < (now + range)))
|
||
return AUTH_WRONG_TIME;
|
||
|
||
if (pkg.sHashMethod != "sha1")
|
||
return AUTH_NOT_SUPPORT_ENC;
|
||
|
||
// 用secret1 = sha1(password); secret2 = sha1(secret1);
|
||
// 1.client create TmpKey use timestamp and secret2;
|
||
// 2.client use TmpKey to enc secret1;
|
||
// 3.server use TmpKey same as client, to dec secret1;
|
||
// 4.server got secret1, then sha1(secret1), to compare secret2;
|
||
// 下面这个是123456的两次sha1值
|
||
//assert (info.sHashSecretKey2 == "69c5fcebaa65b560eaf06c3fbeb481ae44b8d618");
|
||
|
||
string tmpKey;
|
||
string hash2;
|
||
{
|
||
string hash1 = TC_SHA::sha1str(info.sHashSecretKey2.data(), info.sHashSecretKey2.size());
|
||
hash2 = TC_SHA::sha1str(hash1.data(), hash1.size());
|
||
string tmp = hash2;
|
||
const char* pt = (const char* )&pkg.iTime;
|
||
for (size_t i = 0; i < sizeof pkg.iTime; ++ i)
|
||
{
|
||
tmp[i] |= pt[i];
|
||
}
|
||
|
||
tmpKey = TC_MD5::md5str(tmp);
|
||
}
|
||
|
||
string secret1;
|
||
{
|
||
// vector<char> dec;
|
||
try
|
||
{
|
||
secret1 = TC_Des::decrypt3(tmpKey.data(), pkg.sSignature.data(), pkg.sSignature.size());
|
||
// secret1.assign(dec.begin(), dec.end());
|
||
}
|
||
catch (const TC_DES_Exception& )
|
||
{
|
||
return AUTH_DEC_FAIL;
|
||
}
|
||
}
|
||
|
||
// 4.server got secret1, then sha1(secret1), to compare secret2;
|
||
string clientSecret2 = TC_SHA::sha1str(secret1.data(), secret1.size());
|
||
if (clientSecret2.size() != hash2.size() ||
|
||
!std::equal(clientSecret2.begin(), clientSecret2.end(), hash2.begin()))
|
||
{
|
||
return AUTH_ERROR;
|
||
}
|
||
|
||
return AUTH_SUCC;
|
||
}
|
||
|
||
// 只需要传入 expect 的objname;
|
||
// 内部根据obj查找access账号集
|
||
int defaultProcessAuthReq(const char* request, size_t len, const string& expectObj)
|
||
{
|
||
if (len <= 20)
|
||
return AUTH_PROTO_ERR;
|
||
|
||
BasicAuthPackage pkg;
|
||
TarsInputStream<BufferReader> is;
|
||
is.setBuffer(request, len);
|
||
try {
|
||
pkg.readFrom(is);
|
||
}
|
||
catch(...) {
|
||
return AUTH_PROTO_ERR;
|
||
}
|
||
|
||
TC_EpollServer::BindAdapterPtr bap = Application::getEpollServer()->getBindAdapter(expectObj);
|
||
if (!bap)
|
||
return AUTH_WRONG_OBJ;
|
||
|
||
BasicAuthInfo info;
|
||
string expectServantName = ServantHelperManager::getInstance()->getAdapterServant(expectObj);
|
||
info.sObjName = expectServantName;
|
||
info.sAccessKey = pkg.sAccessKey;
|
||
info.sHashSecretKey2 = bap->getSk(info.sAccessKey);
|
||
if (info.sHashSecretKey2.empty())
|
||
return AUTH_WRONG_AK;
|
||
|
||
return processAuthReqHelper(pkg, info);
|
||
}
|
||
|
||
int defaultProcessAuthReq(const string& request, const string& expectObj)
|
||
{
|
||
return defaultProcessAuthReq(request.data(), request.size(), expectObj);
|
||
}
|
||
|
||
string defaultCreateAuthReq(const BasicAuthInfo& info /*, const string& hashMethod*/ )
|
||
{
|
||
// 明文:objName, accessKey, time, hashMethod
|
||
// 密文:use TmpKey to enc secret1;
|
||
TarsOutputStream<BufferWriterString> os;
|
||
BasicAuthPackage pkg;
|
||
pkg.sObjName = info.sObjName;
|
||
pkg.sAccessKey = info.sAccessKey;
|
||
pkg.iTime = TNOW;
|
||
|
||
string secret1 = TC_SHA::sha1str(info.sSecretKey.data(), info.sSecretKey.size());
|
||
string secret2 = TC_SHA::sha1str(secret1.data(), secret1.size());
|
||
|
||
// create tmpKey
|
||
string tmpKey;
|
||
{
|
||
string tmp = secret2;
|
||
const char* pt = (const char* )&pkg.iTime;
|
||
for (size_t i = 0; i < sizeof pkg.iTime; ++ i)
|
||
{
|
||
tmp[i] |= pt[i];
|
||
}
|
||
// 只用了前面24字节
|
||
tmpKey = TC_MD5::md5str(tmp);
|
||
}
|
||
|
||
// then use tmpKey to enc secret1, show server that I know secret1, ie, I know secret.
|
||
// vector<char> secret1Enc;
|
||
|
||
// TC_Tea::encrypt(tmpKey.data(), secret1.data(), secret1.size(), secret1Enc);
|
||
pkg.sSignature = TC_Des::encrypt3(tmpKey.data(), secret1.data(), secret1.size());
|
||
|
||
// pkg.sSignature.assign(secret1Enc.begin(), secret1Enc.end());
|
||
pkg.writeTo(os);
|
||
|
||
return os.getByteBuffer();
|
||
}
|
||
|
||
} // end namespace tars
|
||
|