📄 httpcommon.cc
字号:
version = HVER_1_1; } else { return HE_PROTOCOL; } std::string sverb(line, vend); if (!FromString(verb, sverb.c_str())) { return HE_PROTOCOL; // !?! HC_METHOD_NOT_SUPPORTED? } path.assign(line + dstart, line + dend); return HE_NONE;}//// HttpResponseData//voidHttpResponseData::clear(bool release_document) { HttpData::clear(release_document); scode = HC_INTERNAL_SERVER_ERROR; message.clear();}voidHttpResponseData::set_success(uint32 scode) { this->scode = scode; message.clear(); setHeader(HH_CONTENT_LENGTH, "0");}voidHttpResponseData::set_success(const std::string& content_type, StreamInterface* document, uint32 scode) { this->scode = scode; message.erase(message.begin(), message.end()); setContent(content_type, document);}voidHttpResponseData::set_redirect(const std::string& location, uint32 scode) { this->scode = scode; message.clear(); setHeader(HH_LOCATION, location); setHeader(HH_CONTENT_LENGTH, "0");}voidHttpResponseData::set_error(uint32 scode) { this->scode = scode; message.clear(); setHeader(HH_CONTENT_LENGTH, "0");}size_tHttpResponseData::formatLeader(char* buffer, size_t size) { size_t len = sprintfn(buffer, size, "HTTP/%s %lu", ToString(version), scode); if (!message.empty()) { len += sprintfn(buffer + len, size - len, " %.*s", message.size(), message.data()); } return len;}HttpErrorHttpResponseData::parseLeader(const char* line, size_t len) { size_t pos = 0; uint32 vmajor, vminor; if ((sscanf(line, "HTTP/%lu.%lu %lu%n", &vmajor, &vminor, &scode, &pos) != 3) || (vmajor != 1)) { return HE_PROTOCOL; } if (vminor == 0) { version = HVER_1_0; } else if (vminor == 1) { version = HVER_1_1; } else { return HE_PROTOCOL; } while ((pos < len) && isspace(static_cast<unsigned char>(line[pos]))) ++pos; message.assign(line + pos, len - pos); return HE_NONE;}//////////////////////////////////////////////////////////////////////// Http Authentication//////////////////////////////////////////////////////////////////////#define TEST_DIGEST 0#if TEST_DIGEST/*const char * const DIGEST_CHALLENGE = "Digest realm=\"testrealm@host.com\"," " qop=\"auth,auth-int\"," " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\"," " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";const char * const DIGEST_METHOD = "GET";const char * const DIGEST_URI = "/dir/index.html";;const char * const DIGEST_CNONCE = "0a4f113b";const char * const DIGEST_RESPONSE = "6629fae49393a05397450978507c4ef1";//user_ = "Mufasa";//pass_ = "Circle Of Life";*/const char * const DIGEST_CHALLENGE = "Digest realm=\"Squid proxy-caching web server\"," " nonce=\"Nny4QuC5PwiSDixJ\"," " qop=\"auth\"," " stale=false";const char * const DIGEST_URI = "/";const char * const DIGEST_CNONCE = "6501d58e9a21cee1e7b5fec894ded024";const char * const DIGEST_RESPONSE = "edffcb0829e755838b073a4a42de06bc";#endifstatic std::string quote(const std::string& str) { std::string result; result.push_back('"'); for (size_t i=0; i<str.size(); ++i) { if ((str[i] == '"') || (str[i] == '\\')) result.push_back('\\'); result.push_back(str[i]); } result.push_back('"'); return result;}#ifdef WIN32struct NegotiateAuthContext : public HttpAuthContext { CredHandle cred; CtxtHandle ctx; size_t steps; bool specified_credentials; NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2) : HttpAuthContext(auth), cred(c1), ctx(c2), steps(0), specified_credentials(false) { } virtual ~NegotiateAuthContext() { DeleteSecurityContext(&ctx); FreeCredentialsHandle(&cred); }};#endif // WIN32HttpAuthResult HttpAuthenticate( const char * challenge, size_t len, const SocketAddress& server, const std::string& method, const std::string& uri, const std::string& username, const CryptString& password, HttpAuthContext *& context, std::string& response, std::string& auth_method){#if TEST_DIGEST challenge = DIGEST_CHALLENGE; len = strlen(challenge);#endif HttpAttributeList args; HttpParseAttributes(challenge, len, args); HttpHasNthAttribute(args, 0, &auth_method, NULL); if (context && (context->auth_method != auth_method)) return HAR_IGNORE; // BASIC if (_stricmp(auth_method.c_str(), "basic") == 0) { if (context) return HAR_CREDENTIALS; // Bad credentials if (username.empty()) return HAR_CREDENTIALS; // Missing credentials context = new HttpAuthContext(auth_method); // TODO: convert sensitive to a secure buffer that gets securely deleted //std::string decoded = username + ":" + password; size_t len = username.size() + password.GetLength() + 2; char * sensitive = new char[len]; size_t pos = strcpyn(sensitive, len, username.data(), username.size()); pos += strcpyn(sensitive + pos, len - pos, ":"); password.CopyTo(sensitive + pos, true); response = auth_method; response.append(" "); // TODO: create a sensitive-source version of Base64::encode response.append(Base64::encode(sensitive)); memset(sensitive, 0, len); delete [] sensitive; return HAR_RESPONSE; } // DIGEST if (_stricmp(auth_method.c_str(), "digest") == 0) { if (context) return HAR_CREDENTIALS; // Bad credentials if (username.empty()) return HAR_CREDENTIALS; // Missing credentials context = new HttpAuthContext(auth_method); std::string cnonce, ncount;#if TEST_DIGEST method = DIGEST_METHOD; uri = DIGEST_URI; cnonce = DIGEST_CNONCE;#else char buffer[256]; sprintf(buffer, "%d", time(0)); cnonce = MD5(buffer);#endif ncount = "00000001"; std::string realm, nonce, qop, opaque; HttpHasAttribute(args, "realm", &realm); HttpHasAttribute(args, "nonce", &nonce); bool has_qop = HttpHasAttribute(args, "qop", &qop); bool has_opaque = HttpHasAttribute(args, "opaque", &opaque); // TODO: convert sensitive to be secure buffer //std::string A1 = username + ":" + realm + ":" + password; size_t len = username.size() + realm.size() + password.GetLength() + 3; char * sensitive = new char[len]; // A1 size_t pos = strcpyn(sensitive, len, username.data(), username.size()); pos += strcpyn(sensitive + pos, len - pos, ":"); pos += strcpyn(sensitive + pos, len - pos, realm.c_str()); pos += strcpyn(sensitive + pos, len - pos, ":"); password.CopyTo(sensitive + pos, true); std::string A2 = method + ":" + uri; std::string middle; if (has_qop) { qop = "auth"; middle = nonce + ":" + ncount + ":" + cnonce + ":" + qop; } else { middle = nonce; } std::string HA1 = MD5(sensitive); memset(sensitive, 0, len); delete [] sensitive; std::string HA2 = MD5(A2); std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);#if TEST_DIGEST assert(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);#endif std::stringstream ss; ss << auth_method; ss << " username=" << quote(username); ss << ", realm=" << quote(realm); ss << ", nonce=" << quote(nonce); ss << ", uri=" << quote(uri); if (has_qop) { ss << ", qop=" << qop; ss << ", nc=" << ncount; ss << ", cnonce=" << quote(cnonce); } ss << ", response=\"" << dig_response << "\""; if (has_opaque) { ss << ", opaque=" << quote(opaque); } response = ss.str(); return HAR_RESPONSE; }#ifdef WIN32#if 1 bool want_negotiate = (_stricmp(auth_method.c_str(), "negotiate") == 0); bool want_ntlm = (_stricmp(auth_method.c_str(), "ntlm") == 0); // SPNEGO & NTLM if (want_negotiate || want_ntlm) { const size_t MAX_MESSAGE = 12000, MAX_SPN = 256; char out_buf[MAX_MESSAGE], spn[MAX_SPN];#if 0 // Requires funky windows versions DWORD len = MAX_SPN; if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(), 0, &len, spn) != ERROR_SUCCESS) { LOG_F(WARNING) << "(Negotiate) - DsMakeSpn failed"; return HAR_IGNORE; }#else sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str());#endif SecBuffer out_sec; out_sec.pvBuffer = out_buf; out_sec.cbBuffer = sizeof(out_buf); out_sec.BufferType = SECBUFFER_TOKEN; SecBufferDesc out_buf_desc; out_buf_desc.ulVersion = 0; out_buf_desc.cBuffers = 1; out_buf_desc.pBuffers = &out_sec; const ULONG NEG_FLAGS_DEFAULT = //ISC_REQ_ALLOCATE_MEMORY ISC_REQ_CONFIDENTIALITY //| ISC_REQ_EXTENDED_ERROR //| ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT //| ISC_REQ_STREAM //| ISC_REQ_USE_SUPPLIED_CREDS ; TimeStamp lifetime; SECURITY_STATUS ret = S_OK; ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT; bool specify_credentials = !username.empty(); size_t steps = 0; //uint32 now = Time(); NegotiateAuthContext * neg = static_cast<NegotiateAuthContext *>(context); if (neg) { const size_t max_steps = 10; if (++neg->steps >= max_steps) { LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries"; return HAR_ERROR; } steps = neg->steps; std::string decoded_challenge; HttpHasNthAttribute(args, 1, &decoded_challenge, NULL); decoded_challenge = Base64::decode(decoded_challenge); if (!decoded_challenge.empty()) { SecBuffer in_sec; in_sec.pvBuffer = const_cast<char *>(decoded_challenge.data()); in_sec.cbBuffer = static_cast<unsigned long>(decoded_challenge.size()); in_sec.BufferType = SECBUFFER_TOKEN; SecBufferDesc in_buf_desc; in_buf_desc.ulVersion = 0; in_buf_desc.cBuffers = 1; in_buf_desc.pBuffers = &in_sec; ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime); //LOG(INFO) << "$$$ InitializeSecurityContext @ " << TimeDiff(talk_base::Time(), now); if (FAILED(ret)) { LOG(LS_ERROR) << "InitializeSecurityContext returned: " << ErrorName(ret, SECURITY_ERRORS); return HAR_ERROR; } } else if (neg->specified_credentials) { // Try again with default credentials specify_credentials = false; delete context; context = neg = 0; } else { return HAR_CREDENTIALS; } } if (!neg) { unsigned char userbuf[256], passbuf[256], domainbuf[16]; SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0; if (specify_credentials) { memset(&auth_id, 0, sizeof(auth_id)); size_t len = password.GetLength()+1; char * sensitive = new char[len]; password.CopyTo(sensitive, true); std::string::size_type pos = username.find('\\'); if (pos == std::string::npos) { auth_id.UserLength = static_cast<unsigned long>( _min((unsigned int)sizeof(userbuf) - 1, (unsigned int)username.size())); memcpy(userbuf, username.c_str(), auth_id.UserLength); userbuf[auth_id.UserLength] = 0; auth_id.DomainLength = 0; domainbuf[auth_id.DomainLength] = 0; auth_id.PasswordLength = static_cast<unsigned long>( _min((unsigned int)sizeof(passbuf) - 1, (unsigned int)password.GetLength())); memcpy(passbuf, sensitive, auth_id.PasswordLength); passbuf[auth_id.PasswordLength] = 0; } else { auth_id.UserLength = static_cast<unsigned long>( _min((unsigned int)sizeof(userbuf) - 1, (unsigned int)username.size() - pos - 1)); memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength); userbuf[auth_id.UserLength] = 0; auth_id.DomainLength = static_cast<unsigned long>( _min((unsigned int)sizeof(domainbuf) - 1, (unsigned int)pos)); memcpy(domainbuf, username.c_str(), auth_id.DomainLength); domainbuf[auth_id.DomainLength] = 0; auth_id.PasswordLength = static_cast<unsigned long>( _min((unsigned int)sizeof(passbuf) - 1, (unsigned int)password.GetLength())); memcpy(passbuf, sensitive, auth_id.PasswordLength); passbuf[auth_id.PasswordLength] = 0; } memset(sensitive, 0, len); delete [] sensitive; auth_id.User = userbuf; auth_id.Domain = domainbuf; auth_id.Password = passbuf; auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; pauth_id = &auth_id; LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials"; } else { LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials"; } CredHandle cred; ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime); //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << TimeDiff(talk_base::Time(), now); if (ret != SEC_E_OK) { LOG(LS_ERROR) << "AcquireCredentialsHandle error: " << ErrorName(ret, SECURITY_ERRORS); return HAR_IGNORE; } //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out; CtxtHandle ctx; ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime); //LOG(INFO) << "$$$ InitializeSecurityContext @ " << TimeDiff(talk_base::Time(), now); if (FAILED(ret)) { LOG(LS_ERROR) << "InitializeSecurityContext returned: " << ErrorName(ret, SECURITY_ERRORS); FreeCredentialsHandle(&cred); return HAR_IGNORE; } assert(!context); context = neg = new NegotiateAuthContext(auth_method, cred, ctx); neg->specified_credentials = specify_credentials; neg->steps = steps; } if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) { ret = CompleteAuthToken(&neg->ctx, &out_buf_desc); //LOG(INFO) << "$$$ CompleteAuthToken @ " << TimeDiff(talk_base::Time(), now); LOG(LS_VERBOSE) << "CompleteAuthToken returned: " << ErrorName(ret, SECURITY_ERRORS); if (FAILED(ret)) { return HAR_ERROR; } } //LOG(INFO) << "$$$ NEGOTIATE took " << TimeDiff(talk_base::Time(), now) << "ms"; std::string decoded(out_buf, out_buf + out_sec.cbBuffer); response = auth_method; response.append(" "); response.append(Base64::encode(decoded)); return HAR_RESPONSE; }#endif#endif // WIN32 return HAR_IGNORE;}//////////////////////////////////////////////////////////////////////} // namespace talk_base
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -