PageRenderTime 220ms CodeModel.GetById 75ms app.highlight 14ms RepoModel.GetById 86ms app.codeStats 1ms

/mordor/http/digest.cpp

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