PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/http/digest.cpp

http://github.com/mozy/mordor
C++ | 102 lines | 84 code | 13 blank | 5 comment | 27 complexity | 35b5c799ede80ce7385baf1e54ea866b MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "digest.h"
  3. #include "mordor/string.h"
  4. #include "mordor/timer.h"
  5. #include "parser.h"
  6. namespace Mordor {
  7. namespace HTTP {
  8. namespace DigestAuth {
  9. void authorize(const AuthParams &challenge, AuthParams &authorization,
  10. const URI &uri, const std::string &method, const std::string &username,
  11. const std::string &password)
  12. {
  13. std::string realm, qop, nonce, opaque, algorithm;
  14. StringMap::const_iterator it;
  15. if ( (it = challenge.parameters.find("realm")) != challenge.parameters.end()) realm = it->second;
  16. if ( (it = challenge.parameters.find("qop")) != challenge.parameters.end()) qop = it->second;
  17. if ( (it = challenge.parameters.find("nonce")) != challenge.parameters.end()) nonce = it->second;
  18. if ( (it = challenge.parameters.find("opaque")) != challenge.parameters.end()) opaque = it->second;
  19. if ( (it = challenge.parameters.find("algorithm")) != challenge.parameters.end()) algorithm = it->second;
  20. if (algorithm.empty())
  21. algorithm = "MD5";
  22. StringSet qopValues;
  23. bool authQop = false;
  24. // If the server specified a quality of protection (qop), make sure it allows "auth"
  25. if (!qop.empty()) {
  26. ListParser parser(qopValues);
  27. parser.run(qop);
  28. if (parser.error() || !parser.complete())
  29. MORDOR_THROW_EXCEPTION(BadMessageHeaderException());
  30. if (qopValues.find("auth") == qopValues.end())
  31. MORDOR_THROW_EXCEPTION(InvalidQopException(qop));
  32. authQop = true;
  33. }
  34. // come up with a suitable client nonce
  35. std::ostringstream os;
  36. os << std::hex << TimerManager::now();
  37. std::string cnonce = os.str();
  38. std::string nc = "00000001";
  39. // compute A1
  40. std::string A1;
  41. if (algorithm == "MD5")
  42. A1 = username + ':' + realm + ':' + password;
  43. else if (algorithm == "MD5-sess")
  44. A1 = md5( username + ':' + realm + ':' + password ) + ':' + nonce + ':' + cnonce;
  45. else
  46. MORDOR_THROW_EXCEPTION(InvalidAlgorithmException(algorithm));
  47. // compute A2 - our qop is always auth or unspecified
  48. os.str("");
  49. os << method << ':' << uri;
  50. std::string A2 = os.str();
  51. authorization.scheme = "Digest";
  52. authorization.param.clear();
  53. authorization.parameters["username"] = username;
  54. authorization.parameters["realm"] = realm;
  55. authorization.parameters["nonce"] = nonce;
  56. authorization.parameters["uri"] = uri.toString();
  57. authorization.parameters["algorithm"] = algorithm;
  58. std::string response;
  59. if (authQop) {
  60. qop = "auth";
  61. response = md5( md5(A1) + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + md5(A2) );
  62. authorization.parameters["qop"] = qop;
  63. authorization.parameters["nc"] = nc;
  64. authorization.parameters["cnonce"] = cnonce;
  65. } else {
  66. response = md5( md5(A1) + ':' + nonce + ':' + md5(A2) );
  67. }
  68. authorization.parameters["response"] = response;
  69. if (!opaque.empty())
  70. authorization.parameters["opaque"] = opaque;
  71. }
  72. void
  73. authorize(const Response &challenge, Request &nextRequest,
  74. const std::string &username, const std::string &password)
  75. {
  76. MORDOR_ASSERT(challenge.status.status == UNAUTHORIZED ||
  77. challenge.status.status == PROXY_AUTHENTICATION_REQUIRED);
  78. bool proxy = challenge.status.status == PROXY_AUTHENTICATION_REQUIRED;
  79. const ChallengeList &authenticate = proxy ?
  80. challenge.response.proxyAuthenticate :
  81. challenge.response.wwwAuthenticate;
  82. AuthParams &authorization = proxy ?
  83. nextRequest.request.proxyAuthorization :
  84. nextRequest.request.authorization;
  85. authorize(challengeForSchemeAndRealm(authenticate, "Digest"),
  86. authorization, nextRequest.requestLine.uri,
  87. nextRequest.requestLine.method, username, password);
  88. }
  89. }}}