mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-02 09:49:48 +02:00
NTLM (proxy) authentication support for HTTPClientSession
This commit is contained in:
parent
da7de5e586
commit
0f3f11a3b2
@ -32,7 +32,8 @@ objects = \
|
|||||||
RemoteSyslogChannel RemoteSyslogListener SMTPChannel \
|
RemoteSyslogChannel RemoteSyslogListener SMTPChannel \
|
||||||
WebSocket WebSocketImpl \
|
WebSocket WebSocketImpl \
|
||||||
OAuth10Credentials OAuth20Credentials \
|
OAuth10Credentials OAuth20Credentials \
|
||||||
PollSet UDPClient UDPServerParams
|
PollSet UDPClient UDPServerParams \
|
||||||
|
NTLMCredentials HTTPNTLMCredentials
|
||||||
|
|
||||||
target = PocoNet
|
target = PocoNet
|
||||||
target_version = $(LIBVERSION)
|
target_version = $(LIBVERSION)
|
||||||
|
@ -33,6 +33,9 @@ class HTTPResponse;
|
|||||||
class Net_API HTTPAuthenticationParams: public NameValueCollection
|
class Net_API HTTPAuthenticationParams: public NameValueCollection
|
||||||
/// Collection of name-value pairs of HTTP authentication header (i.e.
|
/// Collection of name-value pairs of HTTP authentication header (i.e.
|
||||||
/// "realm", "qop", "nonce" in case of digest authentication header).
|
/// "realm", "qop", "nonce" in case of digest authentication header).
|
||||||
|
///
|
||||||
|
/// For NTLM, the base64-encoded NTLM message is available from
|
||||||
|
/// the "NTLM" property.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HTTPAuthenticationParams();
|
HTTPAuthenticationParams();
|
||||||
@ -89,6 +92,7 @@ public:
|
|||||||
/// request or response authentication header.
|
/// request or response authentication header.
|
||||||
|
|
||||||
static const std::string REALM;
|
static const std::string REALM;
|
||||||
|
static const std::string NTLM;
|
||||||
static const std::string WWW_AUTHENTICATE;
|
static const std::string WWW_AUTHENTICATE;
|
||||||
static const std::string PROXY_AUTHENTICATE;
|
static const std::string PROXY_AUTHENTICATE;
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#include "Poco/Net/Net.h"
|
#include "Poco/Net/Net.h"
|
||||||
#include "Poco/Net/HTTPSession.h"
|
#include "Poco/Net/HTTPSession.h"
|
||||||
|
#include "Poco/Net/HTTPBasicCredentials.h"
|
||||||
|
#include "Poco/Net/HTTPDigestCredentials.h"
|
||||||
|
#include "Poco/Net/HTTPNTLMCredentials.h"
|
||||||
#include "Poco/Net/SocketAddress.h"
|
#include "Poco/Net/SocketAddress.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
#include <istream>
|
#include <istream>
|
||||||
@ -62,11 +65,20 @@ class Net_API HTTPClientSession: public HTTPSession
|
|||||||
/// set up a session through a proxy.
|
/// set up a session through a proxy.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum ProxyAuthentication
|
||||||
|
{
|
||||||
|
PROXY_AUTH_NONE, /// No proxy authentication
|
||||||
|
PROXY_AUTH_HTTP_BASIC, /// HTTP Basic proxy authentication (default, if username and password are supplied)
|
||||||
|
PROXY_AUTH_HTTP_DIGEST, /// HTTP Digest proxy authentication
|
||||||
|
PROXY_AUTH_NTLM /// NTLMv2 proxy authentication
|
||||||
|
};
|
||||||
|
|
||||||
struct ProxyConfig
|
struct ProxyConfig
|
||||||
/// HTTP proxy server configuration.
|
/// HTTP proxy server configuration.
|
||||||
{
|
{
|
||||||
ProxyConfig():
|
ProxyConfig():
|
||||||
port(HTTP_PORT)
|
port(HTTP_PORT),
|
||||||
|
authMethod(PROXY_AUTH_HTTP_BASIC)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +94,9 @@ public:
|
|||||||
/// A regular expression defining hosts for which the proxy should be bypassed,
|
/// A regular expression defining hosts for which the proxy should be bypassed,
|
||||||
/// e.g. "localhost|127\.0\.0\.1|192\.168\.0\.\d+". Can also be an empty
|
/// e.g. "localhost|127\.0\.0\.1|192\.168\.0\.\d+". Can also be an empty
|
||||||
/// string to disable proxy bypassing.
|
/// string to disable proxy bypassing.
|
||||||
|
|
||||||
|
ProxyAuthentication authMethod;
|
||||||
|
/// The authentication method to use - HTTP Basic or NTLM.
|
||||||
};
|
};
|
||||||
|
|
||||||
HTTPClientSession();
|
HTTPClientSession();
|
||||||
@ -275,6 +290,9 @@ protected:
|
|||||||
int write(const char* buffer, std::streamsize length);
|
int write(const char* buffer, std::streamsize length);
|
||||||
/// Tries to re-connect if keep-alive is on.
|
/// Tries to re-connect if keep-alive is on.
|
||||||
|
|
||||||
|
std::ostream& sendRequestImpl(const HTTPRequest& request);
|
||||||
|
/// Sends the given HTTPRequest over an existing connection.
|
||||||
|
|
||||||
virtual std::string proxyRequestPrefix() const;
|
virtual std::string proxyRequestPrefix() const;
|
||||||
/// Returns the prefix prepended to the URI for proxy requests
|
/// Returns the prefix prepended to the URI for proxy requests
|
||||||
/// (e.g., "http://myhost.com").
|
/// (e.g., "http://myhost.com").
|
||||||
@ -286,10 +304,20 @@ protected:
|
|||||||
/// Sets the proxy credentials (Proxy-Authorization header), if
|
/// Sets the proxy credentials (Proxy-Authorization header), if
|
||||||
/// proxy username and password have been set.
|
/// proxy username and password have been set.
|
||||||
|
|
||||||
void proxyAuthenticateImpl(HTTPRequest& request);
|
void proxyAuthenticateImpl(HTTPRequest& request, const ProxyConfig& proxyConfig);
|
||||||
/// Sets the proxy credentials (Proxy-Authorization header), if
|
/// Sets the proxy credentials (Proxy-Authorization header), if
|
||||||
/// proxy username and password have been set.
|
/// proxy username and password have been set.
|
||||||
|
|
||||||
|
void proxyAuthenticateDigest(HTTPRequest& request);
|
||||||
|
/// Initiates a HTTP Digest authentication handshake with the proxy.
|
||||||
|
|
||||||
|
void proxyAuthenticateNTLM(HTTPRequest& request);
|
||||||
|
/// Initiates a HTTP NTLM authentication handshake with the proxy.
|
||||||
|
|
||||||
|
void sendChallengeRequest(const HTTPRequest& request, HTTPResponse& response);
|
||||||
|
/// Sends a probe request for Digest and NTLM authentication
|
||||||
|
/// to obtain the server challenge.
|
||||||
|
|
||||||
StreamSocket proxyConnect();
|
StreamSocket proxyConnect();
|
||||||
/// Sends a CONNECT request to the proxy server and returns
|
/// Sends a CONNECT request to the proxy server and returns
|
||||||
/// a StreamSocket for the resulting connection.
|
/// a StreamSocket for the resulting connection.
|
||||||
@ -310,6 +338,10 @@ private:
|
|||||||
bool _responseReceived;
|
bool _responseReceived;
|
||||||
Poco::SharedPtr<std::ostream> _pRequestStream;
|
Poco::SharedPtr<std::ostream> _pRequestStream;
|
||||||
Poco::SharedPtr<std::istream> _pResponseStream;
|
Poco::SharedPtr<std::istream> _pResponseStream;
|
||||||
|
HTTPBasicCredentials _proxyBasicCreds;
|
||||||
|
HTTPDigestCredentials _proxyDigestCreds;
|
||||||
|
HTTPNTLMCredentials _proxyNTLMCreds;
|
||||||
|
bool _ntlmProxyAuthenticated;
|
||||||
|
|
||||||
static ProxyConfig _globalProxyConfig;
|
static ProxyConfig _globalProxyConfig;
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Net/HTTPDigestCredentials.h"
|
#include "Poco/Net/HTTPDigestCredentials.h"
|
||||||
|
#include "Poco/Net/HTTPNTLMCredentials.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@ -37,7 +38,7 @@ class HTTPResponse;
|
|||||||
|
|
||||||
class Net_API HTTPCredentials
|
class Net_API HTTPCredentials
|
||||||
/// This is a utility class for working with HTTP
|
/// This is a utility class for working with HTTP
|
||||||
/// authentication (basic or digest) in HTTPRequest objects.
|
/// authentication (Basic, Digest or NTLM) in HTTPRequest objects.
|
||||||
///
|
///
|
||||||
/// Usage is as follows:
|
/// Usage is as follows:
|
||||||
/// First, create a HTTPCredentials object containing
|
/// First, create a HTTPCredentials object containing
|
||||||
@ -132,17 +133,26 @@ public:
|
|||||||
static bool isDigestCredentials(const std::string& header);
|
static bool isDigestCredentials(const std::string& header);
|
||||||
/// Returns true if authentication header is for Digest authentication.
|
/// Returns true if authentication header is for Digest authentication.
|
||||||
|
|
||||||
|
static bool isNTLMCredentials(const std::string& header);
|
||||||
|
/// Returns true if authentication header is for NTLM authentication.
|
||||||
|
|
||||||
static bool hasBasicCredentials(const HTTPRequest& request);
|
static bool hasBasicCredentials(const HTTPRequest& request);
|
||||||
/// Returns true if Authorization with Basic credentials header is present in the request.
|
/// Returns true if an Authorization header with Basic credentials is present in the request.
|
||||||
|
|
||||||
static bool hasDigestCredentials(const HTTPRequest& request);
|
static bool hasDigestCredentials(const HTTPRequest& request);
|
||||||
/// Returns true if Authorization with Digest credentials header is present in the request.
|
/// Returns true if an Authorization header with Digest credentials is present in the request.
|
||||||
|
|
||||||
|
static bool hasNTLMCredentials(const HTTPRequest& request);
|
||||||
|
/// Returns true if an Authorization header with NTLM credentials is present in the request.
|
||||||
|
|
||||||
static bool hasProxyBasicCredentials(const HTTPRequest& request);
|
static bool hasProxyBasicCredentials(const HTTPRequest& request);
|
||||||
/// Returns true if Authorization with Basic credentials header is present in the request.
|
/// Returns true if a Proxy-Authorization header with Basic credentials is present in the request.
|
||||||
|
|
||||||
static bool hasProxyDigestCredentials(const HTTPRequest& request);
|
static bool hasProxyDigestCredentials(const HTTPRequest& request);
|
||||||
/// Returns true if Authorization with Digest credentials header is present in the request.
|
/// Returns true if a Proxy-Authorization header with Digest credentials is present in the request.
|
||||||
|
|
||||||
|
static bool hasProxyNTLMCredentials(const HTTPRequest& request);
|
||||||
|
/// Returns true if a Proxy-Authorization header with Digest credentials is present in the request.
|
||||||
|
|
||||||
static void extractCredentials(const std::string& userInfo, std::string& username, std::string& password);
|
static void extractCredentials(const std::string& userInfo, std::string& username, std::string& password);
|
||||||
/// Extracts username and password from user:password information string.
|
/// Extracts username and password from user:password information string.
|
||||||
@ -155,6 +165,7 @@ private:
|
|||||||
HTTPCredentials& operator = (const HTTPCredentials&);
|
HTTPCredentials& operator = (const HTTPCredentials&);
|
||||||
|
|
||||||
HTTPDigestCredentials _digest;
|
HTTPDigestCredentials _digest;
|
||||||
|
HTTPNTLMCredentials _ntlm;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ public:
|
|||||||
static const std::string CONTENT_TYPE;
|
static const std::string CONTENT_TYPE;
|
||||||
static const std::string TRANSFER_ENCODING;
|
static const std::string TRANSFER_ENCODING;
|
||||||
static const std::string CONNECTION;
|
static const std::string CONNECTION;
|
||||||
|
static const std::string PROXY_CONNECTION;
|
||||||
|
|
||||||
static const std::string CONNECTION_KEEP_ALIVE;
|
static const std::string CONNECTION_KEEP_ALIVE;
|
||||||
static const std::string CONNECTION_CLOSE;
|
static const std::string CONNECTION_CLOSE;
|
||||||
@ -153,13 +154,16 @@ protected:
|
|||||||
/// Creates the HTTPMessage and sets
|
/// Creates the HTTPMessage and sets
|
||||||
/// the version.
|
/// the version.
|
||||||
|
|
||||||
|
HTTPMessage(const HTTPMessage& other);
|
||||||
|
/// Copy constructor.
|
||||||
|
|
||||||
|
HTTPMessage& operator = (const HTTPMessage& other);
|
||||||
|
/// Assignment operator.
|
||||||
|
|
||||||
virtual ~HTTPMessage();
|
virtual ~HTTPMessage();
|
||||||
/// Destroys the HTTPMessage.
|
/// Destroys the HTTPMessage.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HTTPMessage(const HTTPMessage&);
|
|
||||||
HTTPMessage& operator = (const HTTPMessage&);
|
|
||||||
|
|
||||||
std::string _version;
|
std::string _version;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
128
Net/include/Poco/Net/HTTPNTLMCredentials.h
Normal file
128
Net/include/Poco/Net/HTTPNTLMCredentials.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//
|
||||||
|
// HTTPNTLMCredentials.h
|
||||||
|
//
|
||||||
|
// Library: Net
|
||||||
|
// Package: HTTP
|
||||||
|
// Module: HTTPNTLMCredentials
|
||||||
|
//
|
||||||
|
// Definition of the HTTPNTLMCredentials class.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Net_HTTPNTLMCredentials_INCLUDED
|
||||||
|
#define Net_HTTPNTLMCredentials_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Net/Net.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPRequest;
|
||||||
|
class HTTPResponse;
|
||||||
|
|
||||||
|
|
||||||
|
class Net_API HTTPNTLMCredentials
|
||||||
|
/// This is a utility class for working with
|
||||||
|
/// HTTP NTLMv2 Authentication in HTTPRequest
|
||||||
|
/// objects.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HTTPNTLMCredentials();
|
||||||
|
/// Creates an empty HTTPNTLMCredentials object.
|
||||||
|
|
||||||
|
HTTPNTLMCredentials(const std::string& username, const std::string& password);
|
||||||
|
/// Creates a HTTPNTLMCredentials object with the given username and password.
|
||||||
|
|
||||||
|
~HTTPNTLMCredentials();
|
||||||
|
/// Destroys the HTTPNTLMCredentials.
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
/// Resets the HTTPNTLMCredentials object to a clean state.
|
||||||
|
|
||||||
|
void setUsername(const std::string& username);
|
||||||
|
/// Sets the username.
|
||||||
|
|
||||||
|
const std::string& getUsername() const;
|
||||||
|
/// Returns the username.
|
||||||
|
|
||||||
|
void setPassword(const std::string& password);
|
||||||
|
/// Sets the password.
|
||||||
|
|
||||||
|
const std::string& getPassword() const;
|
||||||
|
/// Returns the password.
|
||||||
|
|
||||||
|
void authenticate(HTTPRequest& request, const HTTPResponse& response);
|
||||||
|
/// Parses WWW-Authenticate header of the HTTPResponse, initializes
|
||||||
|
/// internal state, and adds authentication information to the given HTTPRequest.
|
||||||
|
|
||||||
|
void authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64);
|
||||||
|
/// Initializes internal state according to information from the
|
||||||
|
/// ntlmChallengeBase64, and adds authentication
|
||||||
|
/// information to the given HTTPRequest.
|
||||||
|
///
|
||||||
|
/// Throws InvalidArgumentException if responseAuthParams is
|
||||||
|
/// invalid.
|
||||||
|
|
||||||
|
void updateAuthInfo(HTTPRequest& request);
|
||||||
|
/// Updates internal state and adds authentication information to
|
||||||
|
/// the given HTTPRequest.
|
||||||
|
|
||||||
|
void proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response);
|
||||||
|
/// Parses Proxy-Authenticate header of the HTTPResponse, initializes
|
||||||
|
/// internal state, and adds proxy authentication information to the given HTTPRequest.
|
||||||
|
|
||||||
|
void proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64);
|
||||||
|
/// Initializes internal state according to information from the
|
||||||
|
/// HTTPAuthenticationParams of the response, and adds proxy authentication
|
||||||
|
/// information to the given HTTPRequest.
|
||||||
|
///
|
||||||
|
/// Throws InvalidArgumentException if HTTPAuthenticationParams is
|
||||||
|
/// invalid or some required parameter is missing.
|
||||||
|
/// Throws NotImplementedException in case of unsupported digest
|
||||||
|
/// algorithm or quality of protection method.
|
||||||
|
|
||||||
|
void updateProxyAuthInfo(HTTPRequest& request);
|
||||||
|
/// Updates internal state and adds proxy authentication information to
|
||||||
|
/// the given HTTPRequest.
|
||||||
|
|
||||||
|
static const std::string SCHEME;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HTTPNTLMCredentials(const HTTPNTLMCredentials&);
|
||||||
|
HTTPNTLMCredentials& operator = (const HTTPNTLMCredentials&);
|
||||||
|
|
||||||
|
std::string createNTLMMessage(const std::string& ntlmChallengeBase64);
|
||||||
|
static void splitUsername(const std::string& usernameAndDomain, std::string& username, std::string& domain);
|
||||||
|
|
||||||
|
std::string _username;
|
||||||
|
std::string _password;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline const std::string& HTTPNTLMCredentials::getUsername() const
|
||||||
|
{
|
||||||
|
return _username;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string& HTTPNTLMCredentials::getPassword() const
|
||||||
|
{
|
||||||
|
return _password;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Net
|
||||||
|
|
||||||
|
|
||||||
|
#endif // Net_HTTPNTLMCredentials_INCLUDED
|
@ -39,7 +39,7 @@ public:
|
|||||||
HTTPRequest();
|
HTTPRequest();
|
||||||
/// Creates a GET / HTTP/1.0 HTTP request.
|
/// Creates a GET / HTTP/1.0 HTTP request.
|
||||||
|
|
||||||
HTTPRequest(const std::string& version);
|
explicit HTTPRequest(const std::string& version);
|
||||||
/// Creates a GET / HTTP/1.x request with
|
/// Creates a GET / HTTP/1.x request with
|
||||||
/// the given version (HTTP/1.0 or HTTP/1.1).
|
/// the given version (HTTP/1.0 or HTTP/1.1).
|
||||||
|
|
||||||
@ -49,9 +49,15 @@ public:
|
|||||||
HTTPRequest(const std::string& method, const std::string& uri, const std::string& version);
|
HTTPRequest(const std::string& method, const std::string& uri, const std::string& version);
|
||||||
/// Creates a HTTP request with the given method, URI and version.
|
/// Creates a HTTP request with the given method, URI and version.
|
||||||
|
|
||||||
|
HTTPRequest(const HTTPRequest& other);
|
||||||
|
/// Creates a HTTP request by copying another one.
|
||||||
|
|
||||||
virtual ~HTTPRequest();
|
virtual ~HTTPRequest();
|
||||||
/// Destroys the HTTPRequest.
|
/// Destroys the HTTPRequest.
|
||||||
|
|
||||||
|
HTTPRequest& operator = (const HTTPRequest&);
|
||||||
|
/// Assignment operator.
|
||||||
|
|
||||||
void setMethod(const std::string& method);
|
void setMethod(const std::string& method);
|
||||||
/// Sets the method.
|
/// Sets the method.
|
||||||
|
|
||||||
@ -103,6 +109,9 @@ public:
|
|||||||
/// Sets the authentication scheme and information for
|
/// Sets the authentication scheme and information for
|
||||||
/// this request.
|
/// this request.
|
||||||
|
|
||||||
|
void removeCredentials();
|
||||||
|
/// Removes any credentials from the request.
|
||||||
|
|
||||||
bool getExpectContinue() const;
|
bool getExpectContinue() const;
|
||||||
/// Returns true if the request contains an
|
/// Returns true if the request contains an
|
||||||
/// "Expect: 100-continue" header.
|
/// "Expect: 100-continue" header.
|
||||||
@ -126,6 +135,9 @@ public:
|
|||||||
/// Sets the proxy authentication scheme and information for
|
/// Sets the proxy authentication scheme and information for
|
||||||
/// this request.
|
/// this request.
|
||||||
|
|
||||||
|
void removeProxyCredentials();
|
||||||
|
/// Removes any proxy credentials from the request.
|
||||||
|
|
||||||
void write(std::ostream& ostr) const;
|
void write(std::ostream& ostr) const;
|
||||||
/// Writes the HTTP request to the given
|
/// Writes the HTTP request to the given
|
||||||
/// output stream.
|
/// output stream.
|
||||||
@ -173,9 +185,6 @@ private:
|
|||||||
|
|
||||||
std::string _method;
|
std::string _method;
|
||||||
std::string _uri;
|
std::string _uri;
|
||||||
|
|
||||||
HTTPRequest(const HTTPRequest&);
|
|
||||||
HTTPRequest& operator = (const HTTPRequest&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,17 +122,23 @@ public:
|
|||||||
/// Creates the HTTPResponse with the given version, status
|
/// Creates the HTTPResponse with the given version, status
|
||||||
/// and reason phrase.
|
/// and reason phrase.
|
||||||
|
|
||||||
HTTPResponse(HTTPStatus status);
|
explicit HTTPResponse(HTTPStatus status);
|
||||||
/// Creates the HTTPResponse with the given status
|
/// Creates the HTTPResponse with the given status
|
||||||
/// an an appropriate reason phrase.
|
/// and an appropriate reason phrase.
|
||||||
|
|
||||||
HTTPResponse(const std::string& version, HTTPStatus status);
|
HTTPResponse(const std::string& version, HTTPStatus status);
|
||||||
/// Creates the HTTPResponse with the given version, status
|
/// Creates the HTTPResponse with the given version, status
|
||||||
/// an an appropriate reason phrase.
|
/// and an appropriate reason phrase.
|
||||||
|
|
||||||
|
HTTPResponse(const HTTPResponse& other);
|
||||||
|
/// Creates the HTTPResponse by copying another one.
|
||||||
|
|
||||||
virtual ~HTTPResponse();
|
virtual ~HTTPResponse();
|
||||||
/// Destroys the HTTPResponse.
|
/// Destroys the HTTPResponse.
|
||||||
|
|
||||||
|
HTTPResponse& operator = (const HTTPResponse& other);
|
||||||
|
/// Assignment operator.
|
||||||
|
|
||||||
void setStatus(HTTPStatus status);
|
void setStatus(HTTPStatus status);
|
||||||
/// Sets the HTTP status code.
|
/// Sets the HTTP status code.
|
||||||
///
|
///
|
||||||
@ -268,9 +274,6 @@ private:
|
|||||||
|
|
||||||
HTTPStatus _status;
|
HTTPStatus _status;
|
||||||
std::string _reason;
|
std::string _reason;
|
||||||
|
|
||||||
HTTPResponse(const HTTPResponse&);
|
|
||||||
HTTPResponse& operator = (const HTTPResponse&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
171
Net/include/Poco/Net/NTLMCredentials.h
Normal file
171
Net/include/Poco/Net/NTLMCredentials.h
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
//
|
||||||
|
// NTLMCredentials.h
|
||||||
|
//
|
||||||
|
// Library: Net
|
||||||
|
// Package: HTTP
|
||||||
|
// Module: NTLMCredentials
|
||||||
|
//
|
||||||
|
// Definition of the NTLMCredentials class.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Net_NTLMCredentials_INCLUDED
|
||||||
|
#define Net_NTLMCredentials_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Net/Net.h"
|
||||||
|
#include "Poco/BinaryReader.h"
|
||||||
|
#include "Poco/BinaryWriter.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
|
class Net_API NTLMCredentials
|
||||||
|
/// This is a utility class for working with
|
||||||
|
/// NTLMv2 Authentication.
|
||||||
|
///
|
||||||
|
/// Note: This implementation is based on the
|
||||||
|
/// "The NTLM Authentication Protocol and Security Support Provider"
|
||||||
|
/// document written by Eric Glass and avilable from
|
||||||
|
/// http://davenport.sourceforge.net/ntlm.html
|
||||||
|
/// and the NT LAN Manager (NTLM) Authentication Protocol
|
||||||
|
/// [MS-NLMP] document by Microsoft.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NTLM_MESSAGE_TYPE_NEGOTIATE = 0x01,
|
||||||
|
NTLM_MESSAGE_TYPE_CHALLENGE = 0x02,
|
||||||
|
NTLM_MESSAGE_TYPE_AUTHENTICATE = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NTLM_FLAG_NEGOTIATE_UNICODE = 0x00000001,
|
||||||
|
NTLM_FLAG_NEGOTIATE_OEM = 0x00000002,
|
||||||
|
NTLM_FLAG_REQUEST_TARGET = 0x00000004,
|
||||||
|
NTLM_FLAG_NEGOTIATE_NTLM = 0x00000200,
|
||||||
|
NTLM_FLAG_DOMAIN_SUPPLIED = 0x00001000,
|
||||||
|
NTLM_FLAG_WORKST_SUPPLIED = 0x00002000,
|
||||||
|
NTLM_FLAG_NEGOTIATE_LOCAL = 0x00004000,
|
||||||
|
NTLM_FLAG_NEGOTIATE_ALWAYS_SIGN = 0x00008000,
|
||||||
|
NTLM_FLAG_NEGOTIATE_NTLM2_KEY = 0x00080000,
|
||||||
|
NTLM_FLAG_TARGET_DOMAIN = 0x00010000,
|
||||||
|
NTLM_FLAG_TARGET_SERVER = 0x00020000,
|
||||||
|
NTLM_FLAG_TARGET_SHARE = 0x00040000,
|
||||||
|
NTLM_FLAG_NEGOTIATE_TARGET = 0x00800000,
|
||||||
|
NTLM_FLAG_NEGOTIATE_128 = 0x20000000,
|
||||||
|
NTLM_FLAG_NEGOTIATE_56 = 0x80000000
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NegotiateMessage
|
||||||
|
/// This message is sent from the client to initiate NTLM authentication.
|
||||||
|
{
|
||||||
|
NegotiateMessage(): flags(0) {}
|
||||||
|
|
||||||
|
Poco::UInt32 flags;
|
||||||
|
std::string domain;
|
||||||
|
std::string workstation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChallengeMessage
|
||||||
|
/// This message is sent back by the server and contains the NTLM challenge.
|
||||||
|
{
|
||||||
|
ChallengeMessage(): flags(0) {}
|
||||||
|
|
||||||
|
Poco::UInt32 flags;
|
||||||
|
std::vector<unsigned char> challenge;
|
||||||
|
std::string target;
|
||||||
|
std::vector<unsigned char> targetInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AuthenticateMessage
|
||||||
|
/// This message is sent from the client to authenticate itself by providing
|
||||||
|
/// a response to the server challenge.
|
||||||
|
{
|
||||||
|
AuthenticateMessage(): flags(0) {}
|
||||||
|
|
||||||
|
Poco::UInt32 flags;
|
||||||
|
std::vector<unsigned char> lmResponse;
|
||||||
|
std::vector<unsigned char> ntlmResponse;
|
||||||
|
std::string target;
|
||||||
|
std::string username;
|
||||||
|
std::string workstation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BufferDesc
|
||||||
|
{
|
||||||
|
BufferDesc():
|
||||||
|
length(0),
|
||||||
|
reserved(0),
|
||||||
|
offset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferDesc(Poco::UInt16 len, Poco::UInt32 off):
|
||||||
|
length(len),
|
||||||
|
reserved(len),
|
||||||
|
offset(off)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Poco::UInt16 length;
|
||||||
|
Poco::UInt16 reserved;
|
||||||
|
Poco::UInt32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<unsigned char> createNonce();
|
||||||
|
/// Creates an 8-byte client nonce for NTLM authentication.
|
||||||
|
|
||||||
|
static Poco::UInt64 createTimestamp();
|
||||||
|
/// Creates the NTLM timestamp in tenths of a microsecond since January 1, 1601,
|
||||||
|
/// using the current system time.
|
||||||
|
|
||||||
|
static std::vector<unsigned char> createPasswordHash(const std::string& password);
|
||||||
|
/// Creates the NTLM password hash (MD4 of UTF-16-converted password).
|
||||||
|
|
||||||
|
static std::vector<unsigned char> createNTLMv2Hash(const std::string& username, const std::string& target, const std::string& password);
|
||||||
|
/// Creates the NTLMv2 hash, which is the HMAC-MD5 of the concatenated UTF-16 uppercase username and target,
|
||||||
|
/// using the password hash as HMAC passphrase.
|
||||||
|
|
||||||
|
static std::vector<unsigned char> createLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce);
|
||||||
|
/// Creates the LMv2 response by computing the HMAC-MD5 of the challenge and nonce, using the
|
||||||
|
/// ntlm2Hash (see createNTLMv2Hash()) as HMAC passphrase.
|
||||||
|
|
||||||
|
static std::vector<unsigned char> createNTLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce, const std::vector<unsigned char>& targetInfo, Poco::UInt64 timestamp);
|
||||||
|
/// Creates the NTLMv2 response by creating the "blob" and prepending its HMAC-MD5, using the ntlm2Hash as HMAC passphrase.
|
||||||
|
|
||||||
|
static std::vector<unsigned char> formatNegotiateMessage(const NegotiateMessage& message);
|
||||||
|
/// Creates the NTLM Type 1 Negotiate message used for initiating NTLM authentication from the client.
|
||||||
|
|
||||||
|
static bool parseChallengeMessage(const unsigned char* buffer, std::size_t size, ChallengeMessage& message);
|
||||||
|
/// Parses a NTLM Type 2 Challenge message.
|
||||||
|
///
|
||||||
|
/// Returns true if the message was parsed successfully, otherwise false.
|
||||||
|
|
||||||
|
static std::vector<unsigned char> formatAuthenticateMessage(const AuthenticateMessage& message);
|
||||||
|
/// Creates the NTLM Type 1 Authenticate message used for initiating NTLM authentication from the client.
|
||||||
|
|
||||||
|
static void readBufferDesc(Poco::BinaryReader& reader, BufferDesc& desc);
|
||||||
|
/// Reads a buffer descriptor.
|
||||||
|
|
||||||
|
static void writeBufferDesc(Poco::BinaryWriter& writer, const BufferDesc& desc);
|
||||||
|
/// Writes a buffer descriptor.
|
||||||
|
|
||||||
|
static const std::string NTLMSSP;
|
||||||
|
/// Message signature string.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Net
|
||||||
|
|
||||||
|
|
||||||
|
#endif // Net_NTLMCredentials_INCLUDED
|
@ -13,13 +13,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Exception.h"
|
|
||||||
#include "Poco/Net/HTTPAuthenticationParams.h"
|
#include "Poco/Net/HTTPAuthenticationParams.h"
|
||||||
#include "Poco/Net/HTTPRequest.h"
|
#include "Poco/Net/HTTPRequest.h"
|
||||||
#include "Poco/Net/HTTPResponse.h"
|
#include "Poco/Net/HTTPResponse.h"
|
||||||
#include "Poco/Net/NetException.h"
|
#include "Poco/Net/NetException.h"
|
||||||
#include "Poco/String.h"
|
#include "Poco/String.h"
|
||||||
#include "Poco/Ascii.h"
|
#include "Poco/Ascii.h"
|
||||||
|
#include "Poco/Exception.h"
|
||||||
|
|
||||||
|
|
||||||
using Poco::icompare;
|
using Poco::icompare;
|
||||||
@ -66,6 +66,7 @@ namespace Net {
|
|||||||
|
|
||||||
|
|
||||||
const std::string HTTPAuthenticationParams::REALM("realm");
|
const std::string HTTPAuthenticationParams::REALM("realm");
|
||||||
|
const std::string HTTPAuthenticationParams::NTLM("NTLM");
|
||||||
const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate");
|
const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate");
|
||||||
const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate");
|
const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate");
|
||||||
|
|
||||||
@ -135,20 +136,25 @@ void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
while (!found && it != response.end() && icompare(it->first, header) == 0)
|
while (!found && it != response.end() && icompare(it->first, header) == 0)
|
||||||
{
|
{
|
||||||
const std::string& header = it->second;
|
const std::string& headerValue = it->second;
|
||||||
if (icompare(header, 0, 6, "Basic ") == 0)
|
if (icompare(headerValue, 0, 6, "Basic ") == 0)
|
||||||
{
|
{
|
||||||
parse(header.begin() + 6, header.end());
|
parse(headerValue.begin() + 6, headerValue.end());
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
else if (icompare(header, 0, 7, "Digest ") == 0)
|
else if (icompare(headerValue, 0, 7, "Digest ") == 0)
|
||||||
{
|
{
|
||||||
parse(header.begin() + 7, header.end());
|
parse(headerValue.begin() + 7, headerValue.end());
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
else if (icompare(headerValue, 0, 5, "NTLM ") == 0)
|
||||||
|
{
|
||||||
|
set(NTLM, headerValue.substr(5));
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found");
|
if (!found) throw NotAuthenticatedException("No Basic, Digest or NTLM authentication header found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,21 +172,27 @@ void HTTPAuthenticationParams::setRealm(const std::string& realm)
|
|||||||
|
|
||||||
std::string HTTPAuthenticationParams::toString() const
|
std::string HTTPAuthenticationParams::toString() const
|
||||||
{
|
{
|
||||||
ConstIterator iter = begin();
|
|
||||||
std::string result;
|
std::string result;
|
||||||
|
if (size() == 1 && find(NTLM) != end())
|
||||||
if (iter != end())
|
|
||||||
{
|
{
|
||||||
formatParameter(result, iter->first, iter->second);
|
result = get(NTLM);
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
for (; iter != end(); ++iter)
|
|
||||||
{
|
{
|
||||||
result.append(", ");
|
ConstIterator iter = begin();
|
||||||
formatParameter(result, iter->first, iter->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (iter != end())
|
||||||
|
{
|
||||||
|
formatParameter(result, iter->first, iter->second);
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; iter != end(); ++iter)
|
||||||
|
{
|
||||||
|
result.append(", ");
|
||||||
|
formatParameter(result, iter->first, iter->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include "Poco/Net/HTTPStream.h"
|
#include "Poco/Net/HTTPStream.h"
|
||||||
#include "Poco/Net/HTTPFixedLengthStream.h"
|
#include "Poco/Net/HTTPFixedLengthStream.h"
|
||||||
#include "Poco/Net/HTTPChunkedStream.h"
|
#include "Poco/Net/HTTPChunkedStream.h"
|
||||||
#include "Poco/Net/HTTPBasicCredentials.h"
|
#include "Poco/Net/HTTPCredentials.h"
|
||||||
#include "Poco/Net/NetException.h"
|
#include "Poco/Net/NetException.h"
|
||||||
#include "Poco/NumberFormatter.h"
|
#include "Poco/NumberFormatter.h"
|
||||||
#include "Poco/CountingStream.h"
|
#include "Poco/CountingStream.h"
|
||||||
@ -45,7 +45,8 @@ HTTPClientSession::HTTPClientSession():
|
|||||||
_reconnect(false),
|
_reconnect(false),
|
||||||
_mustReconnect(false),
|
_mustReconnect(false),
|
||||||
_expectResponseBody(false),
|
_expectResponseBody(false),
|
||||||
_responseReceived(false)
|
_responseReceived(false),
|
||||||
|
_ntlmProxyAuthenticated(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,8 @@ HTTPClientSession::HTTPClientSession(const StreamSocket& socket):
|
|||||||
_reconnect(false),
|
_reconnect(false),
|
||||||
_mustReconnect(false),
|
_mustReconnect(false),
|
||||||
_expectResponseBody(false),
|
_expectResponseBody(false),
|
||||||
_responseReceived(false)
|
_responseReceived(false),
|
||||||
|
_ntlmProxyAuthenticated(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +73,8 @@ HTTPClientSession::HTTPClientSession(const SocketAddress& address):
|
|||||||
_reconnect(false),
|
_reconnect(false),
|
||||||
_mustReconnect(false),
|
_mustReconnect(false),
|
||||||
_expectResponseBody(false),
|
_expectResponseBody(false),
|
||||||
_responseReceived(false)
|
_responseReceived(false),
|
||||||
|
_ntlmProxyAuthenticated(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +87,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port)
|
|||||||
_reconnect(false),
|
_reconnect(false),
|
||||||
_mustReconnect(false),
|
_mustReconnect(false),
|
||||||
_expectResponseBody(false),
|
_expectResponseBody(false),
|
||||||
_responseReceived(false)
|
_responseReceived(false),
|
||||||
|
_ntlmProxyAuthenticated(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +101,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port,
|
|||||||
_reconnect(false),
|
_reconnect(false),
|
||||||
_mustReconnect(false),
|
_mustReconnect(false),
|
||||||
_expectResponseBody(false),
|
_expectResponseBody(false),
|
||||||
_responseReceived(false)
|
_responseReceived(false),
|
||||||
|
_ntlmProxyAuthenticated(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +200,6 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
|||||||
{
|
{
|
||||||
_pRequestStream = 0;
|
_pRequestStream = 0;
|
||||||
_pResponseStream = 0;
|
_pResponseStream = 0;
|
||||||
clearException();
|
|
||||||
_responseReceived = false;
|
|
||||||
|
|
||||||
bool keepAlive = getKeepAlive();
|
bool keepAlive = getKeepAlive();
|
||||||
if (((connected() && !keepAlive) || mustReconnect()) && !_host.empty())
|
if (((connected() && !keepAlive) || mustReconnect()) && !_host.empty())
|
||||||
@ -207,50 +210,28 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!connected())
|
if (!connected())
|
||||||
|
{
|
||||||
|
_ntlmProxyAuthenticated = false;
|
||||||
reconnect();
|
reconnect();
|
||||||
|
}
|
||||||
if (!keepAlive)
|
if (!keepAlive)
|
||||||
|
{
|
||||||
request.setKeepAlive(false);
|
request.setKeepAlive(false);
|
||||||
|
}
|
||||||
if (!request.has(HTTPRequest::HOST) && !_host.empty())
|
if (!request.has(HTTPRequest::HOST) && !_host.empty())
|
||||||
|
{
|
||||||
request.setHost(_host, _port);
|
request.setHost(_host, _port);
|
||||||
|
}
|
||||||
if (!_proxyConfig.host.empty() && !bypassProxy())
|
if (!_proxyConfig.host.empty() && !bypassProxy())
|
||||||
{
|
{
|
||||||
request.setURI(proxyRequestPrefix() + request.getURI());
|
std::string prefix = proxyRequestPrefix();
|
||||||
|
if (!prefix.empty() && request.getURI().compare(0, 7, "http://") != 0 && request.getURI().compare(0, 8, "https://") != 0)
|
||||||
|
request.setURI(prefix + request.getURI());
|
||||||
|
if (keepAlive) request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||||
proxyAuthenticate(request);
|
proxyAuthenticate(request);
|
||||||
}
|
}
|
||||||
_reconnect = keepAlive;
|
_reconnect = keepAlive;
|
||||||
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
|
return sendRequestImpl(request);
|
||||||
const std::string& method = request.getMethod();
|
|
||||||
if (request.getChunkedTransferEncoding())
|
|
||||||
{
|
|
||||||
HTTPHeaderOutputStream hos(*this);
|
|
||||||
request.write(hos);
|
|
||||||
_pRequestStream = new HTTPChunkedOutputStream(*this);
|
|
||||||
}
|
|
||||||
else if (request.hasContentLength())
|
|
||||||
{
|
|
||||||
Poco::CountingOutputStream cs;
|
|
||||||
request.write(cs);
|
|
||||||
#if POCO_HAVE_INT64
|
|
||||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength64() + cs.chars());
|
|
||||||
#else
|
|
||||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
|
|
||||||
#endif
|
|
||||||
request.write(*_pRequestStream);
|
|
||||||
}
|
|
||||||
else if ((method != HTTPRequest::HTTP_PUT && method != HTTPRequest::HTTP_POST && method != HTTPRequest::HTTP_PATCH) || request.has(HTTPRequest::UPGRADE))
|
|
||||||
{
|
|
||||||
Poco::CountingOutputStream cs;
|
|
||||||
request.write(cs);
|
|
||||||
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
|
|
||||||
request.write(*_pRequestStream);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pRequestStream = new HTTPOutputStream(*this);
|
|
||||||
request.write(*_pRequestStream);
|
|
||||||
}
|
|
||||||
_lastRequest.update();
|
|
||||||
return *_pRequestStream;
|
|
||||||
}
|
}
|
||||||
catch (Exception&)
|
catch (Exception&)
|
||||||
{
|
{
|
||||||
@ -260,6 +241,48 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& HTTPClientSession::sendRequestImpl(const HTTPRequest& request)
|
||||||
|
{
|
||||||
|
_pRequestStream = 0;
|
||||||
|
_pResponseStream = 0;
|
||||||
|
clearException();
|
||||||
|
_responseReceived = false;
|
||||||
|
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
|
||||||
|
const std::string& method = request.getMethod();
|
||||||
|
if (request.getChunkedTransferEncoding())
|
||||||
|
{
|
||||||
|
HTTPHeaderOutputStream hos(*this);
|
||||||
|
request.write(hos);
|
||||||
|
_pRequestStream = new HTTPChunkedOutputStream(*this);
|
||||||
|
}
|
||||||
|
else if (request.hasContentLength())
|
||||||
|
{
|
||||||
|
Poco::CountingOutputStream cs;
|
||||||
|
request.write(cs);
|
||||||
|
#if POCO_HAVE_INT64
|
||||||
|
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength64() + cs.chars());
|
||||||
|
#else
|
||||||
|
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
|
||||||
|
#endif
|
||||||
|
request.write(*_pRequestStream);
|
||||||
|
}
|
||||||
|
else if ((method != HTTPRequest::HTTP_PUT && method != HTTPRequest::HTTP_POST && method != HTTPRequest::HTTP_PATCH) || request.has(HTTPRequest::UPGRADE))
|
||||||
|
{
|
||||||
|
Poco::CountingOutputStream cs;
|
||||||
|
request.write(cs);
|
||||||
|
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
|
||||||
|
request.write(*_pRequestStream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pRequestStream = new HTTPOutputStream(*this);
|
||||||
|
request.write(*_pRequestStream);
|
||||||
|
}
|
||||||
|
_lastRequest.update();
|
||||||
|
return *_pRequestStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
|
||||||
{
|
{
|
||||||
_pRequestStream = 0;
|
_pRequestStream = 0;
|
||||||
@ -409,20 +432,89 @@ bool HTTPClientSession::mustReconnect() const
|
|||||||
|
|
||||||
void HTTPClientSession::proxyAuthenticate(HTTPRequest& request)
|
void HTTPClientSession::proxyAuthenticate(HTTPRequest& request)
|
||||||
{
|
{
|
||||||
proxyAuthenticateImpl(request);
|
proxyAuthenticateImpl(request, _proxyConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request)
|
void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request, const ProxyConfig& proxyConfig)
|
||||||
{
|
{
|
||||||
if (!_proxyConfig.username.empty())
|
switch (proxyConfig.authMethod)
|
||||||
{
|
{
|
||||||
HTTPBasicCredentials creds(_proxyConfig.username, _proxyConfig.password);
|
case PROXY_AUTH_NONE:
|
||||||
creds.proxyAuthenticate(request);
|
break;
|
||||||
|
|
||||||
|
case PROXY_AUTH_HTTP_BASIC:
|
||||||
|
_proxyBasicCreds.setUsername(proxyConfig.username);
|
||||||
|
_proxyBasicCreds.setPassword(proxyConfig.password);
|
||||||
|
_proxyBasicCreds.proxyAuthenticate(request);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROXY_AUTH_HTTP_DIGEST:
|
||||||
|
if (HTTPCredentials::hasDigestCredentials(request))
|
||||||
|
{
|
||||||
|
_proxyDigestCreds.updateProxyAuthInfo(request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_proxyDigestCreds.setUsername(proxyConfig.username);
|
||||||
|
_proxyDigestCreds.setPassword(proxyConfig.password);
|
||||||
|
proxyAuthenticateDigest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
case PROXY_AUTH_NTLM:
|
||||||
|
if (_ntlmProxyAuthenticated)
|
||||||
|
{
|
||||||
|
_proxyNTLMCreds.updateProxyAuthInfo(request);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_proxyNTLMCreds.setUsername(proxyConfig.username);
|
||||||
|
_proxyNTLMCreds.setPassword(proxyConfig.password);
|
||||||
|
proxyAuthenticateNTLM(request);
|
||||||
|
_ntlmProxyAuthenticated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPClientSession::proxyAuthenticateDigest(HTTPRequest& request)
|
||||||
|
{
|
||||||
|
HTTPResponse response;
|
||||||
|
request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||||
|
sendChallengeRequest(request, response);
|
||||||
|
_proxyDigestCreds.proxyAuthenticate(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPClientSession::proxyAuthenticateNTLM(HTTPRequest& request)
|
||||||
|
{
|
||||||
|
HTTPResponse response;
|
||||||
|
request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||||
|
_proxyNTLMCreds.proxyAuthenticate(request, std::string());
|
||||||
|
sendChallengeRequest(request, response);
|
||||||
|
_proxyNTLMCreds.proxyAuthenticate(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPClientSession::sendChallengeRequest(const HTTPRequest& request, HTTPResponse& response)
|
||||||
|
{
|
||||||
|
if (!connected())
|
||||||
|
{
|
||||||
|
reconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPRequest challengeRequest(request);
|
||||||
|
if (challengeRequest.hasContentLength())
|
||||||
|
{
|
||||||
|
challengeRequest.setContentLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendRequestImpl(challengeRequest);
|
||||||
|
std::istream& istr = receiveResponse(response);
|
||||||
|
while (istr.good()) istr.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StreamSocket HTTPClientSession::proxyConnect()
|
StreamSocket HTTPClientSession::proxyConnect()
|
||||||
{
|
{
|
||||||
ProxyConfig emptyProxyConfig;
|
ProxyConfig emptyProxyConfig;
|
||||||
@ -433,9 +525,9 @@ StreamSocket HTTPClientSession::proxyConnect()
|
|||||||
NumberFormatter::append(targetAddress, _port);
|
NumberFormatter::append(targetAddress, _port);
|
||||||
HTTPRequest proxyRequest(HTTPRequest::HTTP_CONNECT, targetAddress, HTTPMessage::HTTP_1_1);
|
HTTPRequest proxyRequest(HTTPRequest::HTTP_CONNECT, targetAddress, HTTPMessage::HTTP_1_1);
|
||||||
HTTPResponse proxyResponse;
|
HTTPResponse proxyResponse;
|
||||||
proxyRequest.set("Proxy-Connection", "keep-alive");
|
proxyRequest.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
|
||||||
proxyRequest.set("Host", getHost());
|
proxyRequest.set(HTTPRequest::HOST, getHost());
|
||||||
proxyAuthenticateImpl(proxyRequest);
|
proxySession.proxyAuthenticateImpl(proxyRequest, _proxyConfig);
|
||||||
proxySession.setKeepAlive(true);
|
proxySession.setKeepAlive(true);
|
||||||
proxySession.sendRequest(proxyRequest);
|
proxySession.sendRequest(proxyRequest);
|
||||||
proxySession.receiveResponse(proxyResponse);
|
proxySession.receiveResponse(proxyResponse);
|
||||||
|
@ -85,6 +85,13 @@ void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& res
|
|||||||
_digest.authenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
|
_digest.authenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (isNTLMCredentials(iter->second))
|
||||||
|
{
|
||||||
|
_ntlm.setUsername(_digest.getUsername());
|
||||||
|
_ntlm.setPassword(_digest.getPassword());
|
||||||
|
_ntlm.authenticate(request, iter->second.substr(5));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +110,10 @@ void HTTPCredentials::updateAuthInfo(HTTPRequest& request)
|
|||||||
{
|
{
|
||||||
_digest.updateAuthInfo(request);
|
_digest.updateAuthInfo(request);
|
||||||
}
|
}
|
||||||
|
else if (isNTLMCredentials(authorization))
|
||||||
|
{
|
||||||
|
_ntlm.updateAuthInfo(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +132,13 @@ void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse
|
|||||||
_digest.proxyAuthenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
|
_digest.proxyAuthenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (isNTLMCredentials(iter->second))
|
||||||
|
{
|
||||||
|
_ntlm.setUsername(_digest.getUsername());
|
||||||
|
_ntlm.setPassword(_digest.getPassword());
|
||||||
|
_ntlm.proxyAuthenticate(request, iter->second.substr(5));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +157,10 @@ void HTTPCredentials::updateProxyAuthInfo(HTTPRequest& request)
|
|||||||
{
|
{
|
||||||
_digest.updateProxyAuthInfo(request);
|
_digest.updateProxyAuthInfo(request);
|
||||||
}
|
}
|
||||||
|
else if (isNTLMCredentials(authorization))
|
||||||
|
{
|
||||||
|
_ntlm.updateProxyAuthInfo(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +177,12 @@ bool HTTPCredentials::isDigestCredentials(const std::string& header)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HTTPCredentials::isNTLMCredentials(const std::string& header)
|
||||||
|
{
|
||||||
|
return icompare(header, 0, 4, "NTLM") == 0 && (header.size() > 5 ? Poco::Ascii::isSpace(header[5]) : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HTTPCredentials::hasBasicCredentials(const HTTPRequest& request)
|
bool HTTPCredentials::hasBasicCredentials(const HTTPRequest& request)
|
||||||
{
|
{
|
||||||
return request.has(HTTPRequest::AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::AUTHORIZATION));
|
return request.has(HTTPRequest::AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::AUTHORIZATION));
|
||||||
@ -167,6 +195,12 @@ bool HTTPCredentials::hasDigestCredentials(const HTTPRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HTTPCredentials::hasNTLMCredentials(const HTTPRequest& request)
|
||||||
|
{
|
||||||
|
return request.has(HTTPRequest::AUTHORIZATION) && isNTLMCredentials(request.get(HTTPRequest::AUTHORIZATION));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HTTPCredentials::hasProxyBasicCredentials(const HTTPRequest& request)
|
bool HTTPCredentials::hasProxyBasicCredentials(const HTTPRequest& request)
|
||||||
{
|
{
|
||||||
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
|
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
|
||||||
@ -179,6 +213,12 @@ bool HTTPCredentials::hasProxyDigestCredentials(const HTTPRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool HTTPCredentials::hasProxyNTLMCredentials(const HTTPRequest& request)
|
||||||
|
{
|
||||||
|
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isNTLMCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPCredentials::extractCredentials(const std::string& userInfo, std::string& username, std::string& password)
|
void HTTPCredentials::extractCredentials(const std::string& userInfo, std::string& username, std::string& password)
|
||||||
{
|
{
|
||||||
const std::string::size_type p = userInfo.find(':');
|
const std::string::size_type p = userInfo.find(':');
|
||||||
|
@ -38,6 +38,7 @@ const std::string HTTPMessage::CONTENT_LENGTH = "Content-Length";
|
|||||||
const std::string HTTPMessage::CONTENT_TYPE = "Content-Type";
|
const std::string HTTPMessage::CONTENT_TYPE = "Content-Type";
|
||||||
const std::string HTTPMessage::TRANSFER_ENCODING = "Transfer-Encoding";
|
const std::string HTTPMessage::TRANSFER_ENCODING = "Transfer-Encoding";
|
||||||
const std::string HTTPMessage::CONNECTION = "Connection";
|
const std::string HTTPMessage::CONNECTION = "Connection";
|
||||||
|
const std::string HTTPMessage::PROXY_CONNECTION = "Proxy-Connection";
|
||||||
const std::string HTTPMessage::CONNECTION_KEEP_ALIVE = "Keep-Alive";
|
const std::string HTTPMessage::CONNECTION_KEEP_ALIVE = "Keep-Alive";
|
||||||
const std::string HTTPMessage::CONNECTION_CLOSE = "Close";
|
const std::string HTTPMessage::CONNECTION_CLOSE = "Close";
|
||||||
const std::string HTTPMessage::EMPTY;
|
const std::string HTTPMessage::EMPTY;
|
||||||
@ -55,11 +56,29 @@ HTTPMessage::HTTPMessage(const std::string& version):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPMessage::HTTPMessage(const HTTPMessage& other):
|
||||||
|
MessageHeader(other),
|
||||||
|
_version(other._version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HTTPMessage::~HTTPMessage()
|
HTTPMessage::~HTTPMessage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPMessage& HTTPMessage::operator = (const HTTPMessage& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
MessageHeader::operator = (other);
|
||||||
|
_version = other._version;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPMessage::setVersion(const std::string& version)
|
void HTTPMessage::setVersion(const std::string& version)
|
||||||
{
|
{
|
||||||
_version = version;
|
_version = version;
|
||||||
|
190
Net/src/HTTPNTLMCredentials.cpp
Normal file
190
Net/src/HTTPNTLMCredentials.cpp
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
//
|
||||||
|
// HTTPNTLMCredentials.cpp
|
||||||
|
//
|
||||||
|
// Library: Net
|
||||||
|
// Package: HTTP
|
||||||
|
// Module: HTTPNTLMCredentials
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Net/HTTPNTLMCredentials.h"
|
||||||
|
#include "Poco/Net/NTLMCredentials.h"
|
||||||
|
#include "Poco/Net/HTTPAuthenticationParams.h"
|
||||||
|
#include "Poco/Net/HTTPRequest.h"
|
||||||
|
#include "Poco/Net/HTTPResponse.h"
|
||||||
|
#include "Poco/DateTime.h"
|
||||||
|
#include "Poco/NumberFormatter.h"
|
||||||
|
#include "Poco/Exception.h"
|
||||||
|
#include "Poco/Base64Encoder.h"
|
||||||
|
#include "Poco/Base64Decoder.h"
|
||||||
|
#include "Poco/MemoryStream.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
|
const std::string HTTPNTLMCredentials::SCHEME = "NTLM";
|
||||||
|
|
||||||
|
|
||||||
|
HTTPNTLMCredentials::HTTPNTLMCredentials()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPNTLMCredentials::HTTPNTLMCredentials(const std::string& username, const std::string& password):
|
||||||
|
_username(username),
|
||||||
|
_password(password)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPNTLMCredentials::~HTTPNTLMCredentials()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::setUsername(const std::string& username)
|
||||||
|
{
|
||||||
|
_username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::setPassword(const std::string& password)
|
||||||
|
{
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
|
||||||
|
{
|
||||||
|
HTTPAuthenticationParams params(response);
|
||||||
|
authenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
|
||||||
|
{
|
||||||
|
std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
|
||||||
|
request.setCredentials(SCHEME, ntlmMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::updateAuthInfo(HTTPRequest& request)
|
||||||
|
{
|
||||||
|
request.removeCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
|
||||||
|
{
|
||||||
|
HTTPAuthenticationParams params(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE);
|
||||||
|
proxyAuthenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
|
||||||
|
{
|
||||||
|
std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
|
||||||
|
request.setProxyCredentials(SCHEME, ntlmMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::updateProxyAuthInfo(HTTPRequest& request)
|
||||||
|
{
|
||||||
|
request.removeProxyCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string HTTPNTLMCredentials::createNTLMMessage(const std::string& responseAuthParams)
|
||||||
|
{
|
||||||
|
if (responseAuthParams.empty())
|
||||||
|
{
|
||||||
|
NTLMCredentials::NegotiateMessage negotiateMsg;
|
||||||
|
std::string username;
|
||||||
|
splitUsername(_username, username, negotiateMsg.domain);
|
||||||
|
std::vector<unsigned char> negotiateBuf = NTLMCredentials::formatNegotiateMessage(negotiateMsg);
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
Poco::Base64Encoder base64(ostr);
|
||||||
|
base64.rdbuf()->setLineLength(0);
|
||||||
|
base64.write(reinterpret_cast<const char*>(&negotiateBuf[0]), negotiateBuf.size());
|
||||||
|
base64.close();
|
||||||
|
return ostr.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Poco::MemoryInputStream istr(responseAuthParams.data(), responseAuthParams.size());
|
||||||
|
Poco::Base64Decoder debase64(istr);
|
||||||
|
std::vector<unsigned char> buffer(responseAuthParams.size());
|
||||||
|
debase64.read(reinterpret_cast<char*>(&buffer[0]), buffer.size());
|
||||||
|
std::size_t size = debase64.gcount();
|
||||||
|
|
||||||
|
Poco::Net::NTLMCredentials::ChallengeMessage challengeMsg;
|
||||||
|
if (NTLMCredentials::parseChallengeMessage(&buffer[0], size, challengeMsg))
|
||||||
|
{
|
||||||
|
std::string username;
|
||||||
|
std::string domain;
|
||||||
|
splitUsername(_username, username, domain);
|
||||||
|
|
||||||
|
NTLMCredentials::AuthenticateMessage authenticateMsg;
|
||||||
|
authenticateMsg.flags = challengeMsg.flags;
|
||||||
|
authenticateMsg.target = challengeMsg.target;
|
||||||
|
authenticateMsg.username = username;
|
||||||
|
|
||||||
|
std::vector<unsigned char> nonce = NTLMCredentials::createNonce();
|
||||||
|
Poco::UInt64 timestamp = NTLMCredentials::createTimestamp();
|
||||||
|
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash(username, challengeMsg.target, _password);
|
||||||
|
authenticateMsg.lmResponse = NTLMCredentials::createLMv2Response(ntlm2Hash, challengeMsg.challenge, nonce);
|
||||||
|
authenticateMsg.ntlmResponse = Poco::Net::NTLMCredentials::createNTLMv2Response(ntlm2Hash, challengeMsg.challenge, nonce, challengeMsg.targetInfo, timestamp);
|
||||||
|
|
||||||
|
std::vector<unsigned char> authenticateBuf = Poco::Net::NTLMCredentials::formatAuthenticateMessage(authenticateMsg);
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
Poco::Base64Encoder base64(ostr);
|
||||||
|
base64.rdbuf()->setLineLength(0);
|
||||||
|
base64.write(reinterpret_cast<const char*>(&authenticateBuf[0]), authenticateBuf.size());
|
||||||
|
base64.close();
|
||||||
|
return ostr.str();
|
||||||
|
}
|
||||||
|
else throw Poco::InvalidArgumentException("Invalid NTLM challenge");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPNTLMCredentials::splitUsername(const std::string& usernameAndDomain, std::string& username, std::string& domain)
|
||||||
|
{
|
||||||
|
std::string::size_type pos = usernameAndDomain.find('\\');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
domain.assign(usernameAndDomain, 0, pos);
|
||||||
|
username.assign(usernameAndDomain, pos + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = usernameAndDomain.find('@');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
username.assign(usernameAndDomain, 0, pos);
|
||||||
|
domain.assign(usernameAndDomain, pos + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
username = usernameAndDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Net
|
@ -74,11 +74,31 @@ HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPRequest::HTTPRequest(const HTTPRequest& other):
|
||||||
|
HTTPMessage(other),
|
||||||
|
_method(other._method),
|
||||||
|
_uri(other._uri)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HTTPRequest::~HTTPRequest()
|
HTTPRequest::~HTTPRequest()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPRequest& HTTPRequest::operator = (const HTTPRequest& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
HTTPMessage::operator = (other);
|
||||||
|
_method = other._method;
|
||||||
|
_uri = other._uri;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPRequest::setMethod(const std::string& method)
|
void HTTPRequest::setMethod(const std::string& method)
|
||||||
{
|
{
|
||||||
_method = method;
|
_method = method;
|
||||||
@ -172,6 +192,12 @@ void HTTPRequest::setCredentials(const std::string& scheme, const std::string& a
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPRequest::removeCredentials()
|
||||||
|
{
|
||||||
|
erase(AUTHORIZATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HTTPRequest::hasProxyCredentials() const
|
bool HTTPRequest::hasProxyCredentials() const
|
||||||
{
|
{
|
||||||
return has(PROXY_AUTHORIZATION);
|
return has(PROXY_AUTHORIZATION);
|
||||||
@ -190,6 +216,12 @@ void HTTPRequest::setProxyCredentials(const std::string& scheme, const std::stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPRequest::removeProxyCredentials()
|
||||||
|
{
|
||||||
|
erase(PROXY_AUTHORIZATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPRequest::write(std::ostream& ostr) const
|
void HTTPRequest::write(std::ostream& ostr) const
|
||||||
{
|
{
|
||||||
ostr << _method << " " << _uri << " " << getVersion() << "\r\n";
|
ostr << _method << " " << _uri << " " << getVersion() << "\r\n";
|
||||||
|
@ -140,11 +140,31 @@ HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPResponse::HTTPResponse(const HTTPResponse& other):
|
||||||
|
HTTPMessage(other),
|
||||||
|
_status(other._status),
|
||||||
|
_reason(other._reason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HTTPResponse::~HTTPResponse()
|
HTTPResponse::~HTTPResponse()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPResponse& HTTPResponse::operator = (const HTTPResponse& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
HTTPMessage::operator = (other);
|
||||||
|
_status = other._status;
|
||||||
|
_reason = other._reason;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HTTPResponse::setStatus(HTTPStatus status)
|
void HTTPResponse::setStatus(HTTPStatus status)
|
||||||
{
|
{
|
||||||
_status = status;
|
_status = status;
|
||||||
|
329
Net/src/NTLMCredentials.cpp
Normal file
329
Net/src/NTLMCredentials.cpp
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
//
|
||||||
|
// NTLMCredentials.cpp
|
||||||
|
//
|
||||||
|
// Library: Net
|
||||||
|
// Package: HTTP
|
||||||
|
// Module: NTLMCredentials
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Net/NTLMCredentials.h"
|
||||||
|
#include "Poco/HMACEngine.h"
|
||||||
|
#include "Poco/MD4Engine.h"
|
||||||
|
#include "Poco/MD5Engine.h"
|
||||||
|
#include "Poco/DigestStream.h"
|
||||||
|
#include "Poco/StreamCopier.h"
|
||||||
|
#include "Poco/UTF8Encoding.h"
|
||||||
|
#include "Poco/UTF16Encoding.h"
|
||||||
|
#include "Poco/TextConverter.h"
|
||||||
|
#include "Poco/UTF8String.h"
|
||||||
|
#include "Poco/Random.h"
|
||||||
|
#include "Poco/Timestamp.h"
|
||||||
|
#include "Poco/MemoryStream.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Poco {
|
||||||
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
|
const std::string NTLMCredentials::NTLMSSP("NTLMSSP");
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::createNonce()
|
||||||
|
{
|
||||||
|
Poco::MD5Engine md5;
|
||||||
|
Poco::Random rnd;
|
||||||
|
rnd.seed();
|
||||||
|
|
||||||
|
Poco::UInt32 n = rnd.next();
|
||||||
|
md5.update(&n, sizeof(n));
|
||||||
|
|
||||||
|
Poco::Timestamp ts;
|
||||||
|
md5.update(&ts, sizeof(ts));
|
||||||
|
|
||||||
|
Poco::DigestEngine::Digest d = md5.digest();
|
||||||
|
d.resize(8);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Poco::UInt64 NTLMCredentials::createTimestamp()
|
||||||
|
{
|
||||||
|
const Poco::UInt64 EPOCH_DELTA_SECONDS = 11644473600; // seconds between January 1, 1970 and January 1, 1601
|
||||||
|
|
||||||
|
Poco::Timestamp now;
|
||||||
|
Poco::UInt64 ts = now.epochMicroseconds();
|
||||||
|
ts += EPOCH_DELTA_SECONDS*1000000; // since January 1, 1601
|
||||||
|
ts *= 10; // tenths of a microsecond
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::createPasswordHash(const std::string& password)
|
||||||
|
{
|
||||||
|
Poco::UTF8Encoding utf8;
|
||||||
|
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
Poco::TextConverter converter(utf8, utf16);
|
||||||
|
|
||||||
|
std::string utf16Password;
|
||||||
|
converter.convert(password, utf16Password);
|
||||||
|
|
||||||
|
Poco::MD4Engine md4;
|
||||||
|
md4.update(utf16Password);
|
||||||
|
return md4.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::createNTLMv2Hash(const std::string& username, const std::string& target, const std::string& password)
|
||||||
|
{
|
||||||
|
Poco::UTF8Encoding utf8;
|
||||||
|
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
Poco::TextConverter converter(utf8, utf16);
|
||||||
|
|
||||||
|
std::vector<unsigned char> passwordHash = createPasswordHash(password);
|
||||||
|
|
||||||
|
std::string userDomain = Poco::UTF8::toUpper(username);
|
||||||
|
userDomain += target;
|
||||||
|
|
||||||
|
std::string utf16UserDomain;
|
||||||
|
converter.convert(userDomain, utf16UserDomain);
|
||||||
|
|
||||||
|
std::string passwordHashString(reinterpret_cast<const char*>(&passwordHash[0]), passwordHash.size());
|
||||||
|
Poco::HMACEngine<Poco::MD5Engine> hmac(passwordHashString);
|
||||||
|
hmac.update(utf16UserDomain);
|
||||||
|
return hmac.digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::createLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce)
|
||||||
|
{
|
||||||
|
poco_assert (challenge.size() == 8);
|
||||||
|
poco_assert (nonce.size() == 8);
|
||||||
|
|
||||||
|
std::vector<unsigned char> lm2Response;
|
||||||
|
|
||||||
|
std::string ntlm2HashString(reinterpret_cast<const char*>(&ntlm2Hash[0]), ntlm2Hash.size());
|
||||||
|
Poco::HMACEngine<Poco::MD5Engine> hmac2(ntlm2HashString);
|
||||||
|
hmac2.update(&challenge[0], challenge.size());
|
||||||
|
hmac2.update(&nonce[0], nonce.size());
|
||||||
|
lm2Response = hmac2.digest();
|
||||||
|
lm2Response.insert(lm2Response.end(), nonce.begin(), nonce.end());
|
||||||
|
|
||||||
|
return lm2Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::createNTLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce, const std::vector<unsigned char>& targetInfo, Poco::UInt64 timestamp)
|
||||||
|
{
|
||||||
|
poco_assert (challenge.size() == 8);
|
||||||
|
poco_assert (nonce.size() == 8);
|
||||||
|
|
||||||
|
std::vector<unsigned char> blob;
|
||||||
|
blob.resize(28 + targetInfo.size() + 4 + 16);
|
||||||
|
|
||||||
|
Poco::MemoryOutputStream blobStream(reinterpret_cast<char*>(&blob[16]), blob.size() - 16);
|
||||||
|
Poco::BinaryWriter writer(blobStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
writer << Poco::UInt32(0x0101);
|
||||||
|
writer << Poco::UInt32(0);
|
||||||
|
writer << timestamp;
|
||||||
|
writer.writeRaw(reinterpret_cast<const char*>(&nonce[0]), nonce.size());
|
||||||
|
writer << Poco::UInt32(0);
|
||||||
|
writer.writeRaw(reinterpret_cast<const char*>(&targetInfo[0]), targetInfo.size());
|
||||||
|
writer << Poco::UInt32(0);
|
||||||
|
|
||||||
|
poco_assert_dbg (blobStream.charsWritten() == blob.size() - 16);
|
||||||
|
|
||||||
|
std::string ntlm2HashString(reinterpret_cast<const char*>(&ntlm2Hash[0]), ntlm2Hash.size());
|
||||||
|
Poco::HMACEngine<Poco::MD5Engine> hmac2(ntlm2HashString);
|
||||||
|
hmac2.update(&challenge[0], challenge.size());
|
||||||
|
hmac2.update(&blob[16], blob.size() - 16);
|
||||||
|
Poco::DigestEngine::Digest d = hmac2.digest();
|
||||||
|
|
||||||
|
poco_assert_dbg (d.size() == 16);
|
||||||
|
|
||||||
|
std::memcpy(&blob[0], &d[0], 16);
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::formatNegotiateMessage(const NegotiateMessage& message)
|
||||||
|
{
|
||||||
|
Poco::UTF8Encoding utf8;
|
||||||
|
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
Poco::TextConverter converter(utf8, utf16);
|
||||||
|
|
||||||
|
std::string utf16Domain;
|
||||||
|
converter.convert(message.domain, utf16Domain);
|
||||||
|
|
||||||
|
std::string utf16Workstation;
|
||||||
|
converter.convert(message.workstation, utf16Workstation);
|
||||||
|
|
||||||
|
std::size_t size = 8 // signature
|
||||||
|
+ 4 // type
|
||||||
|
+ 4 // flags
|
||||||
|
+ 8 + utf16Domain.size()
|
||||||
|
+ 8 + utf16Workstation.size();
|
||||||
|
|
||||||
|
Poco::UInt32 flags = message.flags | NTLM_FLAG_NEGOTIATE_UNICODE | NTLM_FLAG_REQUEST_TARGET | NTLM_FLAG_NEGOTIATE_NTLM | NTLM_FLAG_NEGOTIATE_NTLM2_KEY | NTLM_FLAG_NEGOTIATE_ALWAYS_SIGN;
|
||||||
|
if (!utf16Domain.empty()) flags |= NTLM_FLAG_DOMAIN_SUPPLIED;
|
||||||
|
if (!utf16Workstation.empty()) flags |= NTLM_FLAG_WORKST_SUPPLIED;
|
||||||
|
|
||||||
|
BufferDesc domainDesc(utf16Domain.size(), 8 + 4 + 4 + 8);
|
||||||
|
BufferDesc workstDesc(utf16Workstation.size(), domainDesc.offset + domainDesc.length);
|
||||||
|
|
||||||
|
std::vector<unsigned char> buffer(size);
|
||||||
|
Poco::MemoryOutputStream bufferStream(reinterpret_cast<char*>(&buffer[0]), buffer.size());
|
||||||
|
Poco::BinaryWriter writer(bufferStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
writer.writeRaw(NTLMSSP.c_str(), 8);
|
||||||
|
writer << Poco::UInt32(NTLM_MESSAGE_TYPE_NEGOTIATE);
|
||||||
|
writer << flags;
|
||||||
|
writeBufferDesc(writer, domainDesc);
|
||||||
|
writeBufferDesc(writer, workstDesc);
|
||||||
|
writer.writeRaw(utf16Domain);
|
||||||
|
writer.writeRaw(utf16Workstation);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NTLMCredentials::parseChallengeMessage(const unsigned char* buffer, std::size_t size, ChallengeMessage& message)
|
||||||
|
{
|
||||||
|
Poco::MemoryInputStream istr(reinterpret_cast<const char*>(buffer), size);
|
||||||
|
Poco::BinaryReader reader(istr, Poco::BinaryReader::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
|
||||||
|
std::string signature;
|
||||||
|
reader.readRaw(7, signature);
|
||||||
|
if (signature != NTLMSSP) return false;
|
||||||
|
|
||||||
|
Poco::UInt8 zero;
|
||||||
|
reader >> zero;
|
||||||
|
if (zero != 0) return false;
|
||||||
|
|
||||||
|
Poco::UInt32 type;
|
||||||
|
reader >> type;
|
||||||
|
if (type != NTLM_MESSAGE_TYPE_CHALLENGE) return false;
|
||||||
|
|
||||||
|
BufferDesc targetDesc;
|
||||||
|
readBufferDesc(reader, targetDesc);
|
||||||
|
if (targetDesc.offset + targetDesc.length > size) return false;
|
||||||
|
|
||||||
|
reader >> message.flags;
|
||||||
|
|
||||||
|
message.challenge.resize(8);
|
||||||
|
reader.readRaw(reinterpret_cast<char*>(&message.challenge[0]), 8);
|
||||||
|
|
||||||
|
if (message.flags & NTLM_FLAG_NEGOTIATE_TARGET)
|
||||||
|
{
|
||||||
|
Poco::UInt64 reserved;
|
||||||
|
reader >> reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferDesc targetInfoDesc;
|
||||||
|
if (message.flags & NTLM_FLAG_NEGOTIATE_TARGET)
|
||||||
|
{
|
||||||
|
readBufferDesc(reader, targetInfoDesc);
|
||||||
|
if (targetInfoDesc.offset + targetInfoDesc.length > size) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetDesc.length > 0)
|
||||||
|
{
|
||||||
|
if (message.flags & NTLM_FLAG_NEGOTIATE_UNICODE)
|
||||||
|
{
|
||||||
|
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
Poco::UTF8Encoding utf8;
|
||||||
|
Poco::TextConverter converter(utf16, utf8);
|
||||||
|
converter.convert(buffer + targetDesc.offset, targetDesc.length, message.target);
|
||||||
|
if (targetDesc.reserved == 0) message.target.resize(std::strlen(message.target.c_str()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message.target.assign(buffer + targetDesc.offset, buffer + targetDesc.offset + targetDesc.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetInfoDesc.length > 0)
|
||||||
|
{
|
||||||
|
message.targetInfo.assign(buffer + targetInfoDesc.offset, buffer + targetInfoDesc.offset + targetInfoDesc.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned char> NTLMCredentials::formatAuthenticateMessage(const AuthenticateMessage& message)
|
||||||
|
{
|
||||||
|
Poco::UTF8Encoding utf8;
|
||||||
|
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
Poco::TextConverter converter(utf8, utf16);
|
||||||
|
|
||||||
|
std::string utf16Target;
|
||||||
|
converter.convert(message.target, utf16Target);
|
||||||
|
|
||||||
|
std::string utf16Username;
|
||||||
|
converter.convert(message.username, utf16Username);
|
||||||
|
|
||||||
|
std::string utf16Workstation;
|
||||||
|
converter.convert(message.workstation, utf16Workstation);
|
||||||
|
|
||||||
|
std::size_t size = 8 // signature
|
||||||
|
+ 4 // type
|
||||||
|
+ 8 + message.lmResponse.size()
|
||||||
|
+ 8 + message.ntlmResponse.size()
|
||||||
|
+ 8 + utf16Target.size()
|
||||||
|
+ 8 + utf16Username.size()
|
||||||
|
+ 8 + utf16Workstation.size()
|
||||||
|
+ 8 // session key
|
||||||
|
+ 4; // flags
|
||||||
|
|
||||||
|
Poco::UInt32 flags = message.flags | NTLM_FLAG_NEGOTIATE_UNICODE;
|
||||||
|
|
||||||
|
BufferDesc lmDesc(message.lmResponse.size(), 64);
|
||||||
|
BufferDesc ntlmDesc(message.ntlmResponse.size(), lmDesc.offset + lmDesc.length);
|
||||||
|
BufferDesc targetDesc(utf16Target.size(), ntlmDesc.offset + ntlmDesc.length);
|
||||||
|
BufferDesc usernameDesc(utf16Username.size(), targetDesc.offset + targetDesc.length);
|
||||||
|
BufferDesc workstDesc(utf16Workstation.size(), usernameDesc.offset + usernameDesc.length);
|
||||||
|
BufferDesc sessionKeyDesc(0, workstDesc.offset + workstDesc.length);
|
||||||
|
|
||||||
|
std::vector<unsigned char> buffer(size);
|
||||||
|
Poco::MemoryOutputStream bufferStream(reinterpret_cast<char*>(&buffer[0]), buffer.size());
|
||||||
|
Poco::BinaryWriter writer(bufferStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
|
||||||
|
writer.writeRaw(NTLMSSP.c_str(), 8);
|
||||||
|
writer << Poco::UInt32(NTLM_MESSAGE_TYPE_AUTHENTICATE);
|
||||||
|
writeBufferDesc(writer, lmDesc);
|
||||||
|
writeBufferDesc(writer, ntlmDesc);
|
||||||
|
writeBufferDesc(writer, targetDesc);
|
||||||
|
writeBufferDesc(writer, usernameDesc);
|
||||||
|
writeBufferDesc(writer, workstDesc);
|
||||||
|
writeBufferDesc(writer, sessionKeyDesc);
|
||||||
|
writer << flags;
|
||||||
|
writer.writeRaw(reinterpret_cast<const char*>(&message.lmResponse[0]), message.lmResponse.size());
|
||||||
|
writer.writeRaw(reinterpret_cast<const char*>(&message.ntlmResponse[0]), message.ntlmResponse.size());
|
||||||
|
writer.writeRaw(utf16Target);
|
||||||
|
writer.writeRaw(utf16Username);
|
||||||
|
writer.writeRaw(utf16Workstation);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentials::readBufferDesc(Poco::BinaryReader& reader, BufferDesc& desc)
|
||||||
|
{
|
||||||
|
reader >> desc.length >> desc.reserved >> desc.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentials::writeBufferDesc(Poco::BinaryWriter& writer, const BufferDesc& desc)
|
||||||
|
{
|
||||||
|
writer << desc.length << desc.reserved << desc.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} } // namespace Poco::Net
|
@ -27,7 +27,8 @@ objects = \
|
|||||||
WebSocketTest WebSocketTestSuite \
|
WebSocketTest WebSocketTestSuite \
|
||||||
SyslogTest \
|
SyslogTest \
|
||||||
OAuth10CredentialsTest OAuth20CredentialsTest OAuthTestSuite \
|
OAuth10CredentialsTest OAuth20CredentialsTest OAuthTestSuite \
|
||||||
PollSetTest UDPServerTest UDPServerTestSuite
|
PollSetTest UDPServerTest UDPServerTestSuite \
|
||||||
|
NTLMCredentialsTest
|
||||||
|
|
||||||
target = testrunner
|
target = testrunner
|
||||||
target_version = 1
|
target_version = 1
|
||||||
|
@ -140,6 +140,13 @@ void HTTPCredentialsTest::testAuthenticationParams()
|
|||||||
assertTrue (params["realm"] == "TestDigest");
|
assertTrue (params["realm"] == "TestDigest");
|
||||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||||
assertTrue (params.size() == 2);
|
assertTrue (params.size() == 2);
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
response.set("WWW-Authenticate", "NTLM TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMAbwBtAAAAAAA");
|
||||||
|
params.fromResponse(response);
|
||||||
|
|
||||||
|
assertTrue (params["NTLM"] == "TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAARABPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZABvAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMAbwBtAAAAAAA");
|
||||||
|
assertTrue (params.size() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "HTTPResponseTest.h"
|
#include "HTTPResponseTest.h"
|
||||||
#include "HTTPCookieTest.h"
|
#include "HTTPCookieTest.h"
|
||||||
#include "HTTPCredentialsTest.h"
|
#include "HTTPCredentialsTest.h"
|
||||||
|
#include "NTLMCredentialsTest.h"
|
||||||
|
|
||||||
|
|
||||||
CppUnit::Test* HTTPTestSuite::suite()
|
CppUnit::Test* HTTPTestSuite::suite()
|
||||||
@ -23,6 +24,7 @@ CppUnit::Test* HTTPTestSuite::suite()
|
|||||||
pSuite->addTest(HTTPResponseTest::suite());
|
pSuite->addTest(HTTPResponseTest::suite());
|
||||||
pSuite->addTest(HTTPCookieTest::suite());
|
pSuite->addTest(HTTPCookieTest::suite());
|
||||||
pSuite->addTest(HTTPCredentialsTest::suite());
|
pSuite->addTest(HTTPCredentialsTest::suite());
|
||||||
|
pSuite->addTest(NTLMCredentialsTest::suite());
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
279
Net/testsuite/src/NTLMCredentialsTest.cpp
Normal file
279
Net/testsuite/src/NTLMCredentialsTest.cpp
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
//
|
||||||
|
// NTLMCredentialsTest.cpp
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include "NTLMCredentialsTest.h"
|
||||||
|
#include "CppUnit/TestCaller.h"
|
||||||
|
#include "CppUnit/TestSuite.h"
|
||||||
|
#include "Poco/Net/NTLMCredentials.h"
|
||||||
|
#include "Poco/DigestEngine.h"
|
||||||
|
|
||||||
|
|
||||||
|
using Poco::Net::NTLMCredentials;
|
||||||
|
|
||||||
|
|
||||||
|
NTLMCredentialsTest::NTLMCredentialsTest(const std::string& name): CppUnit::TestCase(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTLMCredentialsTest::~NTLMCredentialsTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testNonce()
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> nonce1 = NTLMCredentials::createNonce();
|
||||||
|
assertTrue (nonce1.size() == 8);
|
||||||
|
|
||||||
|
std::vector<unsigned char> nonce2 = NTLMCredentials::createNonce();
|
||||||
|
assertTrue (nonce2.size() == 8);
|
||||||
|
|
||||||
|
assertTrue (nonce1 != nonce2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testPasswordHash()
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> passHash = NTLMCredentials::createPasswordHash("SecREt01");
|
||||||
|
std::string passHashHex = Poco::DigestEngine::digestToHex(passHash);
|
||||||
|
assertTrue (passHashHex == "cd06ca7c7e10c99b1d33b7485a2ed808");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testNTLMv2Hash()
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
|
||||||
|
std::string ntlm2HashHex = Poco::DigestEngine::digestToHex(ntlm2Hash);
|
||||||
|
assertTrue (ntlm2HashHex == "04b8e0ba74289cc540826bab1dee63ae");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testLMv2Response()
|
||||||
|
{
|
||||||
|
static const unsigned char CHALLENGE[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
|
||||||
|
static const unsigned char NONCE[] = {0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44};
|
||||||
|
|
||||||
|
std::vector<unsigned char> challenge(CHALLENGE, CHALLENGE + 8);
|
||||||
|
std::vector<unsigned char> nonce(NONCE, NONCE + 8);
|
||||||
|
|
||||||
|
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
|
||||||
|
std::vector<unsigned char> lm2Response = NTLMCredentials::createLMv2Response(ntlm2Hash, challenge, nonce);
|
||||||
|
|
||||||
|
std::string lm2ResponseHex = Poco::DigestEngine::digestToHex(lm2Response);
|
||||||
|
assertTrue (lm2ResponseHex == "d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testNTLMv2Response()
|
||||||
|
{
|
||||||
|
static const unsigned char CHALLENGE[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
|
||||||
|
static const unsigned char NONCE[] = {0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44};
|
||||||
|
static const unsigned char TARGET_INFO[] = {
|
||||||
|
0x02, 0x00, 0x0c, 0x00, 0x44, 0x00, 0x4f, 0x00,
|
||||||
|
0x4d, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4e, 0x00,
|
||||||
|
0x01, 0x00, 0x0c, 0x00, 0x53, 0x00, 0x45, 0x00,
|
||||||
|
0x52, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00,
|
||||||
|
0x04, 0x00, 0x14, 0x00, 0x64, 0x00, 0x6f, 0x00,
|
||||||
|
0x6d, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00,
|
||||||
|
0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00,
|
||||||
|
0x03, 0x00, 0x22, 0x00, 0x73, 0x00, 0x65, 0x00,
|
||||||
|
0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00,
|
||||||
|
0x2e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00,
|
||||||
|
0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00,
|
||||||
|
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<unsigned char> challenge(CHALLENGE, CHALLENGE + 8);
|
||||||
|
std::vector<unsigned char> nonce(NONCE, NONCE + 8);
|
||||||
|
std::vector<unsigned char> targetInfo(TARGET_INFO, TARGET_INFO + sizeof(TARGET_INFO));
|
||||||
|
|
||||||
|
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash("user", "DOMAIN", "SecREt01");
|
||||||
|
Poco::UInt64 timestamp = Poco::UInt64(12700317600)*10000000;
|
||||||
|
|
||||||
|
std::vector<unsigned char> ntlm2Response = NTLMCredentials::createNTLMv2Response(
|
||||||
|
ntlm2Hash,
|
||||||
|
challenge,
|
||||||
|
nonce,
|
||||||
|
targetInfo,
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
std::string ntlm2ResponseHex = Poco::DigestEngine::digestToHex(ntlm2Response);
|
||||||
|
|
||||||
|
assertTrue (ntlm2ResponseHex ==
|
||||||
|
"cbabbca713eb795d04c97abc01ee4983"
|
||||||
|
"01010000000000000090d336b734c301"
|
||||||
|
"ffffff00112233440000000002000c00"
|
||||||
|
"44004f004d00410049004e0001000c00"
|
||||||
|
"53004500520056004500520004001400"
|
||||||
|
"64006f006d00610069006e002e006300"
|
||||||
|
"6f006d00030022007300650072007600"
|
||||||
|
"650072002e0064006f006d0061006900"
|
||||||
|
"6e002e0063006f006d00000000000000"
|
||||||
|
"0000"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testFormatNegotiateMessage()
|
||||||
|
{
|
||||||
|
NTLMCredentials::NegotiateMessage msg1;
|
||||||
|
msg1.flags = 0;
|
||||||
|
|
||||||
|
std::vector<unsigned char> msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
|
||||||
|
std::string msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
|
||||||
|
|
||||||
|
assertTrue (msg1BufferHex == "4e544c4d53535000010000000582080000000000180000000000000018000000");
|
||||||
|
|
||||||
|
msg1.domain = "DOMAIN";
|
||||||
|
msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
|
||||||
|
msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
|
||||||
|
|
||||||
|
assertTrue (msg1BufferHex == "4e544c4d5353500001000000059208000c000c0018000000000000002400000044004f004d00410049004e00");
|
||||||
|
|
||||||
|
msg1.workstation = "WORKST";
|
||||||
|
msg1Buffer = NTLMCredentials::formatNegotiateMessage(msg1);
|
||||||
|
msg1BufferHex = Poco::DigestEngine::digestToHex(msg1Buffer);
|
||||||
|
|
||||||
|
assertTrue (msg1BufferHex == "4e544c4d535350000100000005b208000c000c00180000000c000c002400000044004f004d00410049004e0057004f0052004b0053005400");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testParseChallengeMessage()
|
||||||
|
{
|
||||||
|
const unsigned char BUFFER[] = {
|
||||||
|
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00,
|
||||||
|
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
|
||||||
|
};
|
||||||
|
|
||||||
|
NTLMCredentials::ChallengeMessage msg2;
|
||||||
|
bool ok = NTLMCredentials::parseChallengeMessage(BUFFER, sizeof(BUFFER), msg2);
|
||||||
|
|
||||||
|
assertTrue (ok);
|
||||||
|
assertTrue (msg2.flags == (NTLMCredentials::NTLM_FLAG_NEGOTIATE_OEM | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM));
|
||||||
|
assertTrue (msg2.challenge.size() == 8);
|
||||||
|
assertTrue (msg2.targetInfo.empty());
|
||||||
|
|
||||||
|
assertTrue (msg2.challenge[0] == 0x01);
|
||||||
|
assertTrue (msg2.challenge[1] == 0x23);
|
||||||
|
assertTrue (msg2.challenge[7] == 0xef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testParseChallengeMessageWithTargetInfo()
|
||||||
|
{
|
||||||
|
const unsigned char BUFFER[] = {
|
||||||
|
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
|
||||||
|
0x30, 0x00, 0x00, 0x00, 0x01, 0x02, 0x81, 0x00,
|
||||||
|
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x62, 0x00, 0x62, 0x00, 0x3c, 0x00, 0x00, 0x00,
|
||||||
|
0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00,
|
||||||
|
0x49, 0x00, 0x4e, 0x00, 0x02, 0x00, 0x0c, 0x00,
|
||||||
|
0x44, 0x00, 0x4f, 0x00, 0x4d, 0x00, 0x41, 0x00,
|
||||||
|
0x49, 0x00, 0x4e, 0x00, 0x01, 0x00, 0x0c, 0x00,
|
||||||
|
0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56, 0x00,
|
||||||
|
0x45, 0x00, 0x52, 0x00, 0x04, 0x00, 0x14, 0x00,
|
||||||
|
0x64, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00,
|
||||||
|
0x69, 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x63, 0x00,
|
||||||
|
0x6f, 0x00, 0x6d, 0x00, 0x03, 0x00, 0x22, 0x00,
|
||||||
|
0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00,
|
||||||
|
0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x64, 0x00,
|
||||||
|
0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x69, 0x00,
|
||||||
|
0x6e, 0x00, 0x2e, 0x00, 0x63, 0x00, 0x6f, 0x00,
|
||||||
|
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
NTLMCredentials::ChallengeMessage msg2;
|
||||||
|
bool ok = NTLMCredentials::parseChallengeMessage(BUFFER, sizeof(BUFFER), msg2);
|
||||||
|
|
||||||
|
assertTrue (ok);
|
||||||
|
assertTrue (msg2.flags == (NTLMCredentials::NTLM_FLAG_NEGOTIATE_UNICODE | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM | NTLMCredentials::NTLM_FLAG_NEGOTIATE_TARGET | NTLMCredentials::NTLM_FLAG_TARGET_DOMAIN));
|
||||||
|
assertTrue (msg2.challenge.size() == 8);
|
||||||
|
assertTrue (msg2.target == "DOMAIN");
|
||||||
|
|
||||||
|
assertTrue (msg2.targetInfo.size() == 98);
|
||||||
|
|
||||||
|
assertTrue (msg2.challenge[0] == 0x01);
|
||||||
|
assertTrue (msg2.challenge[1] == 0x23);
|
||||||
|
assertTrue (msg2.challenge[7] == 0xef);
|
||||||
|
|
||||||
|
assertTrue (msg2.targetInfo[0] == 0x02);
|
||||||
|
assertTrue (msg2.targetInfo[1] == 0x00);
|
||||||
|
assertTrue (msg2.targetInfo[97] == 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::testFormatAuthenticateMessage()
|
||||||
|
{
|
||||||
|
const unsigned char LM[] = {
|
||||||
|
0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97,
|
||||||
|
0x82, 0xa6, 0x67, 0xaf, 0x6d, 0x42, 0x7c, 0x6d,
|
||||||
|
0xe6, 0x7c, 0x20, 0xc2, 0xd3, 0xe7, 0x7c, 0x56
|
||||||
|
};
|
||||||
|
const unsigned char NTLM[] = {
|
||||||
|
0x25, 0xa9, 0x8c, 0x1c, 0x31, 0xe8, 0x18, 0x47,
|
||||||
|
0x46, 0x6b, 0x29, 0xb2, 0xdf, 0x46, 0x80, 0xf3,
|
||||||
|
0x99, 0x58, 0xfb, 0x8c, 0x21, 0x3a, 0x9c, 0xc6
|
||||||
|
};
|
||||||
|
|
||||||
|
NTLMCredentials::AuthenticateMessage msg3;
|
||||||
|
msg3.flags = NTLMCredentials::NTLM_FLAG_NEGOTIATE_UNICODE | NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM;
|
||||||
|
msg3.target = "DOMAIN";
|
||||||
|
msg3.username = "user";
|
||||||
|
msg3.workstation = "WORKSTATION";
|
||||||
|
msg3.lmResponse.assign(LM, LM + sizeof(LM));
|
||||||
|
msg3.ntlmResponse.assign(NTLM, NTLM + sizeof(NTLM));
|
||||||
|
|
||||||
|
std::vector<unsigned char> msg3Buffer = NTLMCredentials::formatAuthenticateMessage(msg3);
|
||||||
|
std::string msg3BufferHex = Poco::DigestEngine::digestToHex(msg3Buffer);
|
||||||
|
|
||||||
|
assertTrue (msg3BufferHex ==
|
||||||
|
"4e544c4d5353500003000000180018004000000018001800"
|
||||||
|
"580000000c000c0070000000080008007c00000016001600"
|
||||||
|
"84000000000000009a00000001020000c337cd5cbd44fc97"
|
||||||
|
"82a667af6d427c6de67c20c2d3e77c5625a98c1c31e81847"
|
||||||
|
"466b29b2df4680f39958fb8c213a9cc644004f004d004100"
|
||||||
|
"49004e00750073006500720057004f0052004b0053005400"
|
||||||
|
"4100540049004f004e00"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::setUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NTLMCredentialsTest::tearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CppUnit::Test* NTLMCredentialsTest::suite()
|
||||||
|
{
|
||||||
|
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NTLMCredentialsTest");
|
||||||
|
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testNonce);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testPasswordHash);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testNTLMv2Hash);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testLMv2Response);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testNTLMv2Response);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testFormatNegotiateMessage);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testParseChallengeMessage);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testParseChallengeMessageWithTargetInfo);
|
||||||
|
CppUnit_addTest(pSuite, NTLMCredentialsTest, testFormatAuthenticateMessage);
|
||||||
|
|
||||||
|
return pSuite;
|
||||||
|
}
|
46
Net/testsuite/src/NTLMCredentialsTest.h
Normal file
46
Net/testsuite/src/NTLMCredentialsTest.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//
|
||||||
|
// NTLMCredentialsTest.h
|
||||||
|
//
|
||||||
|
// Definition of the NTLMCredentialsTest class.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||||
|
// and Contributors.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NTLMCredentialsTest_INCLUDED
|
||||||
|
#define NTLMCredentialsTest_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "Poco/Net/Net.h"
|
||||||
|
#include "CppUnit/TestCase.h"
|
||||||
|
|
||||||
|
|
||||||
|
class NTLMCredentialsTest: public CppUnit::TestCase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NTLMCredentialsTest(const std::string& name);
|
||||||
|
~NTLMCredentialsTest();
|
||||||
|
|
||||||
|
void testNonce();
|
||||||
|
void testPasswordHash();
|
||||||
|
void testNTLMv2Hash();
|
||||||
|
void testLMv2Response();
|
||||||
|
void testNTLMv2Response();
|
||||||
|
void testFormatNegotiateMessage();
|
||||||
|
void testParseChallengeMessage();
|
||||||
|
void testParseChallengeMessageWithTargetInfo();
|
||||||
|
void testFormatAuthenticateMessage();
|
||||||
|
|
||||||
|
void setUp();
|
||||||
|
void tearDown();
|
||||||
|
|
||||||
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NTLMCredentialsTest_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user