Home | History | Annotate | Download | only in http
      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