20#include <openssl/ssl.h>
21#include <openssl/md5.h>
25using std::ostringstream;
28const string HTTPDigestAuthorization::_mechanism =
"digest";
33HTTPDigestAuthorization::
34HTTPDigestAuthorization(
const HTTPAuthorization::Tokens &tokens,
35 const URLSpec &url,
bool is_proxy) :
36 HTTPAuthorization(tokens, url, is_proxy)
38 Tokens::const_iterator ti;
39 ti = tokens.find(
"nonce");
40 if (ti != tokens.end()) {
41 _nonce = (*ti).second;
45 ti = tokens.find(
"opaque");
46 if (ti != tokens.end()) {
47 _opaque = (*ti).second;
51 ti = tokens.find(
"algorithm");
52 if (ti != tokens.end()) {
54 if (algo_str ==
"md5") {
56 }
else if (algo_str ==
"md5-sess") {
57 _algorithm = A_md5_sess;
59 _algorithm = A_unknown;
64 ti = tokens.find(
"qop");
65 if (ti != tokens.end()) {
70 while (p < qop_str.length()) {
71 while (p < qop_str.length() && isspace(qop_str[p])) {
76 while (q < qop_str.length() && qop_str[q] !=
',') {
77 if (!isspace(qop_str[q])) {
78 qop_str[q] = tolower(qop_str[q]);
85 _qop |= match_qop_token(qop_str.substr(p, last_char - p + 1));
93 strm << time(
nullptr) <<
":" << clock() <<
":"
96 _cnonce = calc_md5(strm.str());
102HTTPDigestAuthorization::
103~HTTPDigestAuthorization() {
111bool HTTPDigestAuthorization::
113 return (_algorithm != A_unknown);
120const string &HTTPDigestAuthorization::
121get_mechanism()
const {
130string HTTPDigestAuthorization::
131generate(HTTPEnum::Method method,
const string &request_path,
132 const string &username,
const string &body) {
135 size_t colon = username.find(
':');
136 string username_only = username.substr(0, colon);
137 string password_only = username.substr(colon + 1);
139 string digest = calc_request_digest(username_only, password_only,
140 method, request_path, body);
143 strm <<
"Digest username=\"" << username.substr(0, colon) <<
"\""
144 <<
", realm=\"" << get_realm() <<
"\""
145 <<
", nonce=\"" << _nonce <<
"\""
146 <<
", uri=" << request_path
147 <<
", response=\"" << digest <<
"\""
148 <<
", algorithm=" << _algorithm;
150 if (!_opaque.empty()) {
151 strm <<
", opaque=\"" << _opaque <<
"\"";
154 if (_chosen_qop != Q_unused) {
155 strm <<
", qop=" << _chosen_qop
156 <<
", cnonce=\"" << _cnonce <<
"\""
157 <<
", nc=" << get_hex_nonce_count();
167int HTTPDigestAuthorization::
168match_qop_token(
const string &token) {
169 if (token ==
"auth") {
171 }
else if (token ==
"auth-int") {
180string HTTPDigestAuthorization::
181calc_request_digest(
const string &username,
const string &password,
182 HTTPEnum::Method method,
const string &request_path,
183 const string &body) {
184 _chosen_qop = Q_unused;
185 string h_a1 = calc_h(get_a1(username, password));
186 string h_a2 = calc_h(get_a2(method, request_path, body));
191 _chosen_qop = Q_unused;
192 strm << _nonce <<
":" << h_a2;
195 strm << _nonce <<
":" << get_hex_nonce_count() <<
":"
196 << _cnonce <<
":" << _chosen_qop <<
":"
200 return calc_kd(h_a1, strm.str());
207string HTTPDigestAuthorization::
208calc_h(
const string &data)
const {
209 switch (_algorithm) {
213 return calc_md5(data);
223string HTTPDigestAuthorization::
224calc_kd(
const string &secret,
const string &data)
const {
225 switch (_algorithm) {
229 return calc_h(secret +
":" + data);
238string HTTPDigestAuthorization::
239get_a1(
const string &username,
const string &password) {
240 switch (_algorithm) {
243 return username +
":" + get_realm() +
":" + password;
247 _a1 = calc_h(username +
":" + get_realm() +
":" + password) +
248 ":" + _nonce +
":" + _cnonce;
259string HTTPDigestAuthorization::
260get_a2(HTTPEnum::Method method,
const string &request_path,
261 const string &body) {
264 if ((_qop & Q_auth_int) != 0 && !body.empty()) {
265 _chosen_qop = Q_auth_int;
266 strm << method <<
":" << request_path <<
":" << calc_h(body);
269 _chosen_qop = Q_auth;
270 strm << method <<
":" << request_path;
281string HTTPDigestAuthorization::
282get_hex_nonce_count()
const {
284 strm << std::hex << std::setfill(
'0') << std::setw(8) << _nonce_count;
292string HTTPDigestAuthorization::
293calc_md5(
const string &source) {
294 unsigned char binary[MD5_DIGEST_LENGTH];
296 MD5((
const unsigned char *)source.data(), source.length(), binary);
299 result.reserve(MD5_DIGEST_LENGTH * 2);
301 for (
int i = 0; i < MD5_DIGEST_LENGTH; i++) {
302 result += hexdigit((binary[i] >> 4) & 0xf);
303 result += hexdigit(binary[i] & 0xf);
310operator << (ostream &out, HTTPDigestAuthorization::Algorithm algorithm) {
312 case HTTPDigestAuthorization::A_md5:
315 case HTTPDigestAuthorization::A_md5_sess:
318 case HTTPDigestAuthorization::A_unknown:
327operator << (ostream &out, HTTPDigestAuthorization::Qop qop) {
329 case HTTPDigestAuthorization::Q_auth:
332 case HTTPDigestAuthorization::Q_auth_int:
335 case HTTPDigestAuthorization::Q_unused:
A container for a URL, e.g.
const std::string & get_url() const
Returns the complete URL specification.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.