PageRenderTime 24ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/http/negotiate.cpp

http://github.com/mozy/mordor
C++ | 156 lines | 134 code | 19 blank | 3 comment | 12 complexity | d90516eb1f596e985e8eead3edf57170 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "negotiate.h"
  3. #include "http.h"
  4. #include "mordor/log.h"
  5. #include "mordor/string.h"
  6. #pragma comment(lib, "secur32.lib")
  7. namespace Mordor {
  8. namespace HTTP {
  9. static Logger::ptr g_log = Log::lookup("mordor:http:negotiate");
  10. NegotiateAuth::NegotiateAuth(const std::string &username,
  11. const std::string &password)
  12. : m_username(toUtf16(username)),
  13. m_password(toUtf16(password))
  14. {
  15. SecInvalidateHandle(&m_creds);
  16. SecInvalidateHandle(&m_secCtx);
  17. size_t pos = m_username.find(L'\\');
  18. if (pos != std::wstring::npos) {
  19. m_domain = m_username.substr(0, pos);
  20. m_username = m_username.substr(pos + 1);
  21. }
  22. }
  23. NegotiateAuth::~NegotiateAuth()
  24. {
  25. if (SecIsValidHandle(&m_creds)) {
  26. FreeCredentialHandle(&m_creds);
  27. SecInvalidateHandle(&m_creds);
  28. }
  29. if (SecIsValidHandle(&m_secCtx)) {
  30. FreeCredentialHandle(&m_secCtx);
  31. SecInvalidateHandle(&m_secCtx);
  32. }
  33. }
  34. bool
  35. NegotiateAuth::authorize(const AuthParams &challenge, AuthParams &authorization,
  36. const URI &uri)
  37. {
  38. SECURITY_STATUS status;
  39. std::wstring packageW = toUtf16(challenge.scheme);
  40. std::string param = challenge.param;
  41. std::string outboundBuffer;
  42. SecBufferDesc outboundBufferDesc;
  43. SecBuffer outboundSecBuffer;
  44. TimeStamp lifetime;
  45. ULONG contextAttributes;
  46. outboundBuffer.resize(4096);
  47. outboundBufferDesc.ulVersion = 0;
  48. outboundBufferDesc.cBuffers = 1;
  49. outboundBufferDesc.pBuffers = &outboundSecBuffer;
  50. outboundSecBuffer.BufferType = SECBUFFER_TOKEN;
  51. outboundSecBuffer.pvBuffer = &outboundBuffer[0];
  52. outboundSecBuffer.cbBuffer = (unsigned long)outboundBuffer.size();
  53. if (param.empty()) {
  54. // No response from server; we're starting a new session
  55. if (SecIsValidHandle(&m_creds))
  56. return false;
  57. SEC_WINNT_AUTH_IDENTITY_W id;
  58. id.User = (unsigned short *)m_username.c_str();
  59. id.UserLength = (unsigned long)m_username.size();
  60. id.Domain = (unsigned short *)m_domain.c_str();
  61. id.DomainLength = (unsigned long)m_domain.size();
  62. id.Password = (unsigned short *)m_password.c_str();
  63. id.PasswordLength = (unsigned long)m_password.size();
  64. id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  65. status = AcquireCredentialsHandleW(NULL,
  66. (wchar_t *)packageW.c_str(),
  67. SECPKG_CRED_OUTBOUND,
  68. NULL,
  69. m_username.empty() ? NULL : &id,
  70. NULL,
  71. NULL,
  72. &m_creds,
  73. &lifetime);
  74. MORDOR_LOG_TRACE(g_log) << "AcquireCredentialsHandleW("
  75. << challenge.scheme << ", " << toUtf8(m_username) << "): ("
  76. << status << ")";
  77. if (!SUCCEEDED(status))
  78. MORDOR_THROW_EXCEPTION_FROM_ERROR_API(status, "AcquireCredentialsHandleW");
  79. status = InitializeSecurityContextW(
  80. &m_creds,
  81. NULL,
  82. (wchar_t *)toUtf16(uri.toString()).c_str(),
  83. ISC_REQ_CONFIDENTIALITY,
  84. 0,
  85. SECURITY_NATIVE_DREP,
  86. NULL,
  87. 0,
  88. &m_secCtx,
  89. &outboundBufferDesc,
  90. &contextAttributes,
  91. &lifetime);
  92. MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW("
  93. << uri << ", {0}): {" << outboundSecBuffer.cbBuffer << "} ("
  94. << status << ")";
  95. } else {
  96. // Prepare the response from the server
  97. std::string inboundBuffer = base64decode(param);
  98. SecBufferDesc inboundBufferDesc;
  99. SecBuffer inboundSecBuffer;
  100. inboundBufferDesc.ulVersion = 0;
  101. inboundBufferDesc.cBuffers = 1;
  102. inboundBufferDesc.pBuffers = &inboundSecBuffer;
  103. inboundSecBuffer.BufferType = SECBUFFER_TOKEN;
  104. inboundSecBuffer.pvBuffer = &inboundBuffer[0];
  105. inboundSecBuffer.cbBuffer = (unsigned long)inboundBuffer.size();
  106. status = InitializeSecurityContextW(
  107. &m_creds,
  108. &m_secCtx,
  109. (wchar_t *)toUtf16(uri.toString()).c_str(),
  110. ISC_REQ_CONFIDENTIALITY,
  111. 0,
  112. SECURITY_NATIVE_DREP,
  113. &inboundBufferDesc,
  114. 0,
  115. &m_secCtx,
  116. &outboundBufferDesc,
  117. &contextAttributes,
  118. &lifetime);
  119. MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW("
  120. << uri << ", {" << inboundSecBuffer.cbBuffer << "}): {"
  121. << outboundSecBuffer.cbBuffer << "} (" << status << ")";
  122. }
  123. if (status == SEC_I_COMPLETE_NEEDED ||
  124. status == SEC_I_COMPLETE_AND_CONTINUE) {
  125. status = CompleteAuthToken(&m_secCtx, &outboundBufferDesc);
  126. MORDOR_LOG_TRACE(g_log) << "CompleteAuthToken(): {"
  127. << outboundSecBuffer.cbBuffer << "} (" << status << ")";
  128. }
  129. if (!SUCCEEDED(status))
  130. MORDOR_THROW_EXCEPTION_FROM_ERROR(status);
  131. outboundBuffer.resize(outboundSecBuffer.cbBuffer);
  132. authorization.scheme = challenge.scheme;
  133. authorization.param = base64encode(outboundBuffer);
  134. authorization.parameters.clear();
  135. return true;
  136. }
  137. }}