1 | // |
2 | // HTTPNTLMCredentials.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: HTTP |
6 | // Module: HTTPNTLMCredentials |
7 | // |
8 | // Copyright (c) 2019, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/HTTPNTLMCredentials.h" |
16 | #include "Poco/Net/NTLMCredentials.h" |
17 | #include "Poco/Net/HTTPAuthenticationParams.h" |
18 | #include "Poco/Net/HTTPRequest.h" |
19 | #include "Poco/Net/HTTPResponse.h" |
20 | #include "Poco/Net/NetException.h" |
21 | #include "Poco/DateTime.h" |
22 | #include "Poco/NumberFormatter.h" |
23 | #include "Poco/Exception.h" |
24 | |
25 | |
26 | namespace Poco { |
27 | namespace Net { |
28 | |
29 | |
30 | const std::string HTTPNTLMCredentials::SCHEME = "NTLM" ; |
31 | |
32 | |
33 | HTTPNTLMCredentials::HTTPNTLMCredentials() |
34 | { |
35 | } |
36 | |
37 | |
38 | HTTPNTLMCredentials::HTTPNTLMCredentials(const std::string& username, const std::string& password): |
39 | _username(username), |
40 | _password(password) |
41 | { |
42 | } |
43 | |
44 | |
45 | HTTPNTLMCredentials::~HTTPNTLMCredentials() |
46 | { |
47 | } |
48 | |
49 | |
50 | void HTTPNTLMCredentials::reset() |
51 | { |
52 | } |
53 | |
54 | |
55 | void HTTPNTLMCredentials::setUsername(const std::string& username) |
56 | { |
57 | _username = username; |
58 | } |
59 | |
60 | |
61 | void HTTPNTLMCredentials::setPassword(const std::string& password) |
62 | { |
63 | _password = password; |
64 | } |
65 | |
66 | |
67 | void HTTPNTLMCredentials::setHost(const std::string& host) |
68 | { |
69 | _host = host; |
70 | } |
71 | |
72 | |
73 | void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response) |
74 | { |
75 | HTTPAuthenticationParams params(response); |
76 | authenticate(request, params.get(HTTPAuthenticationParams::NTLM, "" )); |
77 | } |
78 | |
79 | |
80 | void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64) |
81 | { |
82 | std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64); |
83 | request.setCredentials(SCHEME, ntlmMessage); |
84 | } |
85 | |
86 | |
87 | void HTTPNTLMCredentials::updateAuthInfo(HTTPRequest& request) |
88 | { |
89 | request.removeCredentials(); |
90 | } |
91 | |
92 | |
93 | void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) |
94 | { |
95 | HTTPAuthenticationParams params(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE); |
96 | proxyAuthenticate(request, params.get(HTTPAuthenticationParams::NTLM, "" )); |
97 | } |
98 | |
99 | |
100 | void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64) |
101 | { |
102 | std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64); |
103 | request.setProxyCredentials(SCHEME, ntlmMessage); |
104 | } |
105 | |
106 | |
107 | void HTTPNTLMCredentials::updateProxyAuthInfo(HTTPRequest& request) |
108 | { |
109 | request.removeProxyCredentials(); |
110 | } |
111 | |
112 | |
113 | std::string HTTPNTLMCredentials::createNTLMMessage(const std::string& responseAuthParams) |
114 | { |
115 | if (responseAuthParams.empty()) |
116 | { |
117 | std::vector<unsigned char> negotiateBuf; |
118 | if (useSSPINTLM()) |
119 | { |
120 | _pNTLMContext = SSPINTLMCredentials::createNTLMContext(_host, SSPINTLMCredentials::SERVICE_HTTP); |
121 | negotiateBuf = SSPINTLMCredentials::negotiate(*_pNTLMContext); |
122 | } |
123 | else |
124 | { |
125 | NTLMCredentials::NegotiateMessage negotiateMsg; |
126 | std::string username; |
127 | NTLMCredentials::splitUsername(_username, username, negotiateMsg.domain); |
128 | negotiateBuf = NTLMCredentials::formatNegotiateMessage(negotiateMsg); |
129 | } |
130 | return NTLMCredentials::toBase64(negotiateBuf); |
131 | } |
132 | else |
133 | { |
134 | std::vector<unsigned char> buffer = NTLMCredentials::fromBase64(responseAuthParams); |
135 | if (buffer.empty()) throw HTTPException("Invalid NTLM challenge" ); |
136 | std::vector<unsigned char> authenticateBuf; |
137 | if (useSSPINTLM() && _pNTLMContext) |
138 | { |
139 | authenticateBuf = SSPINTLMCredentials::authenticate(*_pNTLMContext, buffer); |
140 | } |
141 | else |
142 | { |
143 | NTLMCredentials::ChallengeMessage challengeMsg; |
144 | if (NTLMCredentials::parseChallengeMessage(&buffer[0], buffer.size(), challengeMsg)) |
145 | { |
146 | if ((challengeMsg.flags & NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM2_KEY) == 0) |
147 | { |
148 | throw HTTPException("Proxy does not support NTLMv2 authentication" ); |
149 | } |
150 | |
151 | std::string username; |
152 | std::string domain; |
153 | NTLMCredentials::splitUsername(_username, username, domain); |
154 | |
155 | NTLMCredentials::AuthenticateMessage authenticateMsg; |
156 | authenticateMsg.flags = challengeMsg.flags; |
157 | authenticateMsg.target = challengeMsg.target; |
158 | authenticateMsg.username = username; |
159 | |
160 | std::vector<unsigned char> lmNonce = NTLMCredentials::createNonce(); |
161 | std::vector<unsigned char> ntlmNonce = NTLMCredentials::createNonce(); |
162 | Poco::UInt64 timestamp = NTLMCredentials::createTimestamp(); |
163 | std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash(username, challengeMsg.target, _password); |
164 | |
165 | authenticateMsg.lmResponse = NTLMCredentials::createLMv2Response(ntlm2Hash, challengeMsg.challenge, lmNonce); |
166 | authenticateMsg.ntlmResponse = NTLMCredentials::createNTLMv2Response(ntlm2Hash, challengeMsg.challenge, ntlmNonce, challengeMsg.targetInfo, timestamp); |
167 | |
168 | authenticateBuf = NTLMCredentials::formatAuthenticateMessage(authenticateMsg); |
169 | } |
170 | else throw HTTPException("Invalid NTLM challenge" ); |
171 | } |
172 | return NTLMCredentials::toBase64(authenticateBuf); |
173 | } |
174 | } |
175 | |
176 | |
177 | } } // namespace Poco::Net |
178 | |