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
26namespace Poco {
27namespace Net {
28
29
30const std::string HTTPNTLMCredentials::SCHEME = "NTLM";
31
32
33HTTPNTLMCredentials::HTTPNTLMCredentials()
34{
35}
36
37
38HTTPNTLMCredentials::HTTPNTLMCredentials(const std::string& username, const std::string& password):
39 _username(username),
40 _password(password)
41{
42}
43
44
45HTTPNTLMCredentials::~HTTPNTLMCredentials()
46{
47}
48
49
50void HTTPNTLMCredentials::reset()
51{
52}
53
54
55void HTTPNTLMCredentials::setUsername(const std::string& username)
56{
57 _username = username;
58}
59
60
61void HTTPNTLMCredentials::setPassword(const std::string& password)
62{
63 _password = password;
64}
65
66
67void HTTPNTLMCredentials::setHost(const std::string& host)
68{
69 _host = host;
70}
71
72
73void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
74{
75 HTTPAuthenticationParams params(response);
76 authenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
77}
78
79
80void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
81{
82 std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
83 request.setCredentials(SCHEME, ntlmMessage);
84}
85
86
87void HTTPNTLMCredentials::updateAuthInfo(HTTPRequest& request)
88{
89 request.removeCredentials();
90}
91
92
93void 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
100void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
101{
102 std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
103 request.setProxyCredentials(SCHEME, ntlmMessage);
104}
105
106
107void HTTPNTLMCredentials::updateProxyAuthInfo(HTTPRequest& request)
108{
109 request.removeProxyCredentials();
110}
111
112
113std::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