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