1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 // security.h needs to be included for CredHandle. Unfortunately CredHandle 12 // is a typedef and can't be forward declared. 13 #define SECURITY_WIN32 1 14 #include <windows.h> 15 #include <security.h> 16 17 #include <string> 18 19 #include "base/strings/string16.h" 20 #include "net/base/net_export.h" 21 #include "net/http/http_auth.h" 22 23 namespace net { 24 25 class HttpAuthChallengeTokenizer; 26 27 // SSPILibrary is introduced so unit tests can mock the calls to Windows' SSPI 28 // implementation. The default implementation simply passes the arguments on to 29 // the SSPI implementation provided by Secur32.dll. 30 // NOTE(cbentzel): I considered replacing the Secur32.dll with a mock DLL, but 31 // decided that it wasn't worth the effort as this is unlikely to be performance 32 // sensitive code. 33 class SSPILibrary { 34 public: 35 virtual ~SSPILibrary() {} 36 37 virtual SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal, 38 LPWSTR pszPackage, 39 unsigned long fCredentialUse, 40 void* pvLogonId, 41 void* pvAuthData, 42 SEC_GET_KEY_FN pGetKeyFn, 43 void* pvGetKeyArgument, 44 PCredHandle phCredential, 45 PTimeStamp ptsExpiry) = 0; 46 47 virtual SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential, 48 PCtxtHandle phContext, 49 SEC_WCHAR* pszTargetName, 50 unsigned long fContextReq, 51 unsigned long Reserved1, 52 unsigned long TargetDataRep, 53 PSecBufferDesc pInput, 54 unsigned long Reserved2, 55 PCtxtHandle phNewContext, 56 PSecBufferDesc pOutput, 57 unsigned long* contextAttr, 58 PTimeStamp ptsExpiry) = 0; 59 60 virtual SECURITY_STATUS QuerySecurityPackageInfo(LPWSTR pszPackageName, 61 PSecPkgInfoW *pkgInfo) = 0; 62 63 virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) = 0; 64 65 virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) = 0; 66 67 virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) = 0; 68 }; 69 70 class SSPILibraryDefault : public SSPILibrary { 71 public: 72 SSPILibraryDefault() {} 73 virtual ~SSPILibraryDefault() {} 74 75 virtual SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal, 76 LPWSTR pszPackage, 77 unsigned long fCredentialUse, 78 void* pvLogonId, 79 void* pvAuthData, 80 SEC_GET_KEY_FN pGetKeyFn, 81 void* pvGetKeyArgument, 82 PCredHandle phCredential, 83 PTimeStamp ptsExpiry) { 84 return ::AcquireCredentialsHandle(pszPrincipal, pszPackage, fCredentialUse, 85 pvLogonId, pvAuthData, pGetKeyFn, 86 pvGetKeyArgument, phCredential, 87 ptsExpiry); 88 } 89 90 virtual SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential, 91 PCtxtHandle phContext, 92 SEC_WCHAR* pszTargetName, 93 unsigned long fContextReq, 94 unsigned long Reserved1, 95 unsigned long TargetDataRep, 96 PSecBufferDesc pInput, 97 unsigned long Reserved2, 98 PCtxtHandle phNewContext, 99 PSecBufferDesc pOutput, 100 unsigned long* contextAttr, 101 PTimeStamp ptsExpiry) { 102 return ::InitializeSecurityContext(phCredential, phContext, pszTargetName, 103 fContextReq, Reserved1, TargetDataRep, 104 pInput, Reserved2, phNewContext, pOutput, 105 contextAttr, ptsExpiry); 106 } 107 108 virtual SECURITY_STATUS QuerySecurityPackageInfo(LPWSTR pszPackageName, 109 PSecPkgInfoW *pkgInfo) { 110 return ::QuerySecurityPackageInfo(pszPackageName, pkgInfo); 111 } 112 113 virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) { 114 return ::FreeCredentialsHandle(phCredential); 115 } 116 117 virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) { 118 return ::DeleteSecurityContext(phContext); 119 } 120 121 virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) { 122 return ::FreeContextBuffer(pvContextBuffer); 123 } 124 }; 125 126 class NET_EXPORT_PRIVATE HttpAuthSSPI { 127 public: 128 HttpAuthSSPI(SSPILibrary* sspi_library, 129 const std::string& scheme, 130 const SEC_WCHAR* security_package, 131 ULONG max_token_length); 132 ~HttpAuthSSPI(); 133 134 bool NeedsIdentity() const; 135 136 bool AllowsExplicitCredentials() const; 137 138 HttpAuth::AuthorizationResult ParseChallenge( 139 HttpAuthChallengeTokenizer* tok); 140 141 // Generates an authentication token for the service specified by the 142 // Service Principal Name |spn| and stores the value in |*auth_token|. 143 // If the return value is not |OK|, then the value of |*auth_token| is 144 // unspecified. ERR_IO_PENDING is not a valid return code. 145 // If this is the first round of a multiple round scheme, credentials are 146 // obtained using |*credentials|. If |credentials| is NULL, the credentials 147 // for the currently logged in user are used instead. 148 int GenerateAuthToken(const AuthCredentials* credentials, 149 const std::string& spn, 150 std::string* auth_token); 151 152 // Delegation is allowed on the Kerberos ticket. This allows certain servers 153 // to act as the user, such as an IIS server retrieiving data from a 154 // Kerberized MSSQL server. 155 void Delegate(); 156 157 private: 158 int OnFirstRound(const AuthCredentials* credentials); 159 160 int GetNextSecurityToken( 161 const std::string& spn, 162 const void* in_token, 163 int in_token_len, 164 void** out_token, 165 int* out_token_len); 166 167 void ResetSecurityContext(); 168 169 SSPILibrary* library_; 170 std::string scheme_; 171 const SEC_WCHAR* security_package_; 172 std::string decoded_server_auth_token_; 173 ULONG max_token_length_; 174 CredHandle cred_; 175 CtxtHandle ctxt_; 176 bool can_delegate_; 177 }; 178 179 // Splits |combined| into domain and username. 180 // If |combined| is of form "FOO\bar", |domain| will contain "FOO" and |user| 181 // will contain "bar". 182 // If |combined| is of form "bar", |domain| will be empty and |user| will 183 // contain "bar". 184 // |domain| and |user| must be non-NULL. 185 NET_EXPORT_PRIVATE void SplitDomainAndUser(const base::string16& combined, 186 base::string16* domain, 187 base::string16* user); 188 189 // Determines the maximum token length in bytes for a particular SSPI package. 190 // 191 // |library| and |max_token_length| must be non-NULL pointers to valid objects. 192 // 193 // If the return value is OK, |*max_token_length| contains the maximum token 194 // length in bytes. 195 // 196 // If the return value is ERR_UNSUPPORTED_AUTH_SCHEME, |package| is not an 197 // known SSPI authentication scheme on this system. |*max_token_length| is not 198 // changed. 199 // 200 // If the return value is ERR_UNEXPECTED, there was an unanticipated problem 201 // in the underlying SSPI call. The details are logged, and |*max_token_length| 202 // is not changed. 203 NET_EXPORT_PRIVATE int DetermineMaxTokenLength(SSPILibrary* library, 204 const std::wstring& package, 205 ULONG* max_token_length); 206 207 } // namespace net 208 209 #endif // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_ 210