1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/net/spdyproxy/http_auth_handler_spdyproxy.h"
#include <string>
#include "base/i18n/icu_string_conversions.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth.h"
#include "net/http/http_request_info.h"
namespace spdyproxy {
using net::AuthCredentials;
using net::BoundNetLog;
using net::CompletionCallback;
using net::HttpAuth;
using net::HttpAuthHandler;
using net::HttpAuthHandlerFactory;
using net::HttpRequestInfo;
using net::HttpUtil;
HttpAuthHandlerSpdyProxy::Factory::Factory(
const GURL& authorized_spdyproxy_origin)
: authorized_spdyproxy_origin_(authorized_spdyproxy_origin) {
}
HttpAuthHandlerSpdyProxy::Factory::~Factory() {
}
int HttpAuthHandlerSpdyProxy::Factory::CreateAuthHandler(
HttpAuth::ChallengeTokenizer* challenge,
HttpAuth::Target target,
const GURL& origin,
CreateReason reason,
int digest_nonce_count,
const BoundNetLog& net_log,
scoped_ptr<HttpAuthHandler>* handler) {
// If a spdyproxy auth proxy has not been set, refuse all requests to use this
// auth handler.
if (authorized_spdyproxy_origin_.possibly_invalid_spec().empty()) {
VLOG(1) << "SpdyProxy auth without configuring authorized origin.";
return net::ERR_UNSUPPORTED_AUTH_SCHEME;
}
// We ensure that this authentication handler is used only with an authorized
// SPDY proxy, since otherwise a user's authentication token can be
// sniffed by a malicious proxy that presents an appropriate challenge.
const GURL origin_origin = origin.GetOrigin();
if (!(target == HttpAuth::AUTH_PROXY &&
origin_origin == authorized_spdyproxy_origin_)) {
UMA_HISTOGRAM_COUNTS("Net.UnexpectedSpdyProxyAuth", 1);
VLOG(1) << "SpdyProxy auth request with an unexpected config."
<< " origin: " << origin_origin.possibly_invalid_spec()
<< " authorized_origin: "
<< authorized_spdyproxy_origin_.possibly_invalid_spec();
return net::ERR_UNSUPPORTED_AUTH_SCHEME;
}
scoped_ptr<HttpAuthHandler> tmp_handler(
new HttpAuthHandlerSpdyProxy(authorized_spdyproxy_origin_));
if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
return net::ERR_INVALID_RESPONSE;
handler->swap(tmp_handler);
return net::OK;
}
HttpAuthHandlerSpdyProxy::HttpAuthHandlerSpdyProxy(
const GURL& authorized_spdyproxy_origin)
: HttpAuthHandler(),
authorized_spdyproxy_origin_(authorized_spdyproxy_origin) {
}
HttpAuth::AuthorizationResult
HttpAuthHandlerSpdyProxy::HandleAnotherChallenge(
HttpAuth::ChallengeTokenizer* challenge) {
// SpdyProxy authentication is always a single round, so any responses
// should be treated as a rejection.
return HttpAuth::AUTHORIZATION_RESULT_REJECT;
}
bool HttpAuthHandlerSpdyProxy::NeedsIdentity() {
return true;
}
bool HttpAuthHandlerSpdyProxy::AllowsDefaultCredentials() {
return false;
}
bool HttpAuthHandlerSpdyProxy::AllowsExplicitCredentials() {
return true;
}
bool HttpAuthHandlerSpdyProxy::Init(
HttpAuth::ChallengeTokenizer* challenge) {
auth_scheme_ = HttpAuth::AUTH_SCHEME_SPDYPROXY;
score_ = 5;
properties_ = ENCRYPTS_IDENTITY;
return ParseChallenge(challenge);
}
int HttpAuthHandlerSpdyProxy::GenerateAuthTokenImpl(
const AuthCredentials* credentials, const HttpRequestInfo* request,
const CompletionCallback&, std::string* auth_token) {
DCHECK(credentials);
if (credentials->password().length() == 0) {
DVLOG(1) << "Received a SpdyProxy auth token request without an "
<< "available token.";
return -1;
}
*auth_token = "SpdyProxy ps=\"" + ps_token_ + "\", sid=\"" +
UTF16ToUTF8(credentials->password()) + "\"";
return net::OK;
}
bool HttpAuthHandlerSpdyProxy::ParseChallenge(
HttpAuth::ChallengeTokenizer* challenge) {
// Verify the challenge's auth-scheme.
if (!LowerCaseEqualsASCII(challenge->scheme(), "spdyproxy")) {
VLOG(1) << "Parsed challenge without SpdyProxy type";
return false;
}
HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
// Loop through all the properties.
while (parameters.GetNext()) {
// FAIL -- couldn't parse a property.
if (!ParseChallengeProperty(parameters.name(),
parameters.value()))
return false;
}
// Check if tokenizer failed.
if (!parameters.valid())
return false;
// Check that the required properties were provided.
if (realm_.empty())
return false;
if (ps_token_.empty())
return false;
return true;
}
bool HttpAuthHandlerSpdyProxy::ParseChallengeProperty(
const std::string& name, const std::string& value) {
if (LowerCaseEqualsASCII(name, "realm")) {
std::string realm;
if (!base::ConvertToUtf8AndNormalize(value, base::kCodepageLatin1, &realm))
return false;
realm_ = realm;
} else if (LowerCaseEqualsASCII(name, "ps")) {
ps_token_ = value;
} else {
VLOG(1) << "Skipping unrecognized SpdyProxy auth property, " << name;
}
return true;
}
} // namespace spdyproxy
|