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 23namespace net { 24 25class 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. 33class 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 70class 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 126class 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. 185NET_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. 203NET_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