1 // Copyright 2011 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This file contains common routines used by NTLM and Negotiate authentication 6 // using the SSPI API on Windows. 7 8 #ifndef NET_HTTP_HTTP_AUTH_SSPI_WIN_H_ 9 #define NET_HTTP_HTTP_AUTH_SSPI_WIN_H_ 10 11 #include "base/memory/raw_ptr.h" 12 13 // security.h needs to be included for CredHandle. Unfortunately CredHandle 14 // is a typedef and can't be forward declared. 15 #define SECURITY_WIN32 1 16 #include <windows.h> 17 #include <security.h> 18 19 #include <string> 20 21 #include "net/base/completion_once_callback.h" 22 #include "net/base/net_errors.h" 23 #include "net/base/net_export.h" 24 #include "net/http/http_auth.h" 25 #include "net/http/http_auth_mechanism.h" 26 27 namespace net { 28 29 class HttpAuthChallengeTokenizer; 30 31 // SSPILibrary is introduced so unit tests can mock the calls to Windows' SSPI 32 // implementation. The default implementation simply passes the arguments on to 33 // the SSPI implementation provided by Secur32.dll. 34 // 35 // A single SSPILibrary can only be used with a single security package. Hence 36 // the package is bound at construction time. Overridable SSPI methods exclude 37 // the security package parameter since it is implicit. 38 class NET_EXPORT_PRIVATE SSPILibrary { 39 public: SSPILibrary(const wchar_t * package)40 explicit SSPILibrary(const wchar_t* package) : package_name_(package) {} ~SSPILibrary()41 virtual ~SSPILibrary() {} 42 43 // Determines the maximum token length in bytes for a particular SSPI package. 44 // 45 // |library| and |max_token_length| must be non-nullptr pointers to valid 46 // objects. 47 // 48 // If the return value is OK, |*max_token_length| contains the maximum token 49 // length in bytes. 50 // 51 // If the return value is ERR_UNSUPPORTED_AUTH_SCHEME, |package| is not an 52 // known SSPI authentication scheme on this system. |*max_token_length| is not 53 // changed. 54 // 55 // If the return value is ERR_UNEXPECTED, there was an unanticipated problem 56 // in the underlying SSPI call. The details are logged, and 57 // |*max_token_length| is not changed. 58 Error DetermineMaxTokenLength(ULONG* max_token_length); 59 60 virtual SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal, 61 unsigned long fCredentialUse, 62 void* pvLogonId, 63 void* pvAuthData, 64 SEC_GET_KEY_FN pGetKeyFn, 65 void* pvGetKeyArgument, 66 PCredHandle phCredential, 67 PTimeStamp ptsExpiry) = 0; 68 69 virtual SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential, 70 PCtxtHandle phContext, 71 SEC_WCHAR* pszTargetName, 72 unsigned long fContextReq, 73 unsigned long Reserved1, 74 unsigned long TargetDataRep, 75 PSecBufferDesc pInput, 76 unsigned long Reserved2, 77 PCtxtHandle phNewContext, 78 PSecBufferDesc pOutput, 79 unsigned long* contextAttr, 80 PTimeStamp ptsExpiry) = 0; 81 82 virtual SECURITY_STATUS QueryContextAttributesEx(PCtxtHandle phContext, 83 ULONG ulAttribute, 84 PVOID pBuffer, 85 ULONG cbBuffer) = 0; 86 87 virtual SECURITY_STATUS QuerySecurityPackageInfo(PSecPkgInfoW* pkgInfo) = 0; 88 89 virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) = 0; 90 91 virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) = 0; 92 93 virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) = 0; 94 95 protected: 96 // Security package used with DetermineMaxTokenLength(), 97 // QuerySecurityPackageInfo(), AcquireCredentialsHandle(). All of these must 98 // be consistent. 99 const std::wstring package_name_; 100 ULONG max_token_length_ = 0; 101 102 bool is_supported_ = true; 103 }; 104 105 class SSPILibraryDefault : public SSPILibrary { 106 public: SSPILibraryDefault(const wchar_t * package)107 explicit SSPILibraryDefault(const wchar_t* package) : SSPILibrary(package) {} ~SSPILibraryDefault()108 ~SSPILibraryDefault() override {} 109 110 SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal, 111 unsigned long fCredentialUse, 112 void* pvLogonId, 113 void* pvAuthData, 114 SEC_GET_KEY_FN pGetKeyFn, 115 void* pvGetKeyArgument, 116 PCredHandle phCredential, 117 PTimeStamp ptsExpiry) override; 118 119 SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential, 120 PCtxtHandle phContext, 121 SEC_WCHAR* pszTargetName, 122 unsigned long fContextReq, 123 unsigned long Reserved1, 124 unsigned long TargetDataRep, 125 PSecBufferDesc pInput, 126 unsigned long Reserved2, 127 PCtxtHandle phNewContext, 128 PSecBufferDesc pOutput, 129 unsigned long* contextAttr, 130 PTimeStamp ptsExpiry) override; 131 132 SECURITY_STATUS QueryContextAttributesEx(PCtxtHandle phContext, 133 ULONG ulAttribute, 134 PVOID pBuffer, 135 ULONG cbBuffer) override; 136 137 SECURITY_STATUS QuerySecurityPackageInfo(PSecPkgInfoW* pkgInfo) override; 138 139 SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) override; 140 141 SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) override; 142 143 SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) override; 144 }; 145 146 class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpAuthMechanism { 147 public: 148 HttpAuthSSPI(SSPILibrary* sspi_library, HttpAuth::Scheme scheme); 149 ~HttpAuthSSPI() override; 150 151 // HttpAuthMechanism implementation: 152 bool Init(const NetLogWithSource& net_log) override; 153 bool NeedsIdentity() const override; 154 bool AllowsExplicitCredentials() const override; 155 HttpAuth::AuthorizationResult ParseChallenge( 156 HttpAuthChallengeTokenizer* tok) override; 157 int GenerateAuthToken(const AuthCredentials* credentials, 158 const std::string& spn, 159 const std::string& channel_bindings, 160 std::string* auth_token, 161 const NetLogWithSource& net_log, 162 CompletionOnceCallback callback) override; 163 void SetDelegation(HttpAuth::DelegationType delegation_type) override; 164 165 private: 166 int OnFirstRound(const AuthCredentials* credentials, 167 const NetLogWithSource& net_log); 168 169 int GetNextSecurityToken(const std::string& spn, 170 const std::string& channing_bindings, 171 const void* in_token, 172 int in_token_len, 173 const NetLogWithSource& net_log, 174 void** out_token, 175 int* out_token_len); 176 177 void ResetSecurityContext(); 178 179 raw_ptr<SSPILibrary> library_; 180 HttpAuth::Scheme scheme_; 181 std::string decoded_server_auth_token_; 182 CredHandle cred_; 183 CtxtHandle ctxt_; 184 HttpAuth::DelegationType delegation_type_; 185 }; 186 187 // Splits |combined| into domain and username. 188 // If |combined| is of form "FOO\bar", |domain| will contain "FOO" and |user| 189 // will contain "bar". 190 // If |combined| is of form "bar", |domain| will be empty and |user| will 191 // contain "bar". 192 // |domain| and |user| must be non-nullptr. 193 NET_EXPORT_PRIVATE void SplitDomainAndUser(const std::u16string& combined, 194 std::u16string* domain, 195 std::u16string* user); 196 197 } // namespace net 198 199 #endif // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_ 200