• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~SSPILibrary()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:
SSPILibraryDefault()70   SSPILibraryDefault() {}
~SSPILibraryDefault()71   virtual ~SSPILibraryDefault() {}
72 
AcquireCredentialsHandle(LPWSTR pszPrincipal,LPWSTR pszPackage,unsigned long fCredentialUse,void * pvLogonId,void * pvAuthData,SEC_GET_KEY_FN pGetKeyFn,void * pvGetKeyArgument,PCredHandle phCredential,PTimeStamp ptsExpiry)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 
InitializeSecurityContext(PCredHandle phCredential,PCtxtHandle phContext,SEC_WCHAR * pszTargetName,unsigned long fContextReq,unsigned long Reserved1,unsigned long TargetDataRep,PSecBufferDesc pInput,unsigned long Reserved2,PCtxtHandle phNewContext,PSecBufferDesc pOutput,unsigned long * contextAttr,PTimeStamp ptsExpiry)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 
QuerySecurityPackageInfo(LPWSTR pszPackageName,PSecPkgInfoW * pkgInfo)106   virtual SECURITY_STATUS QuerySecurityPackageInfo(LPWSTR pszPackageName,
107                                                    PSecPkgInfoW *pkgInfo) {
108     return ::QuerySecurityPackageInfo(pszPackageName, pkgInfo);
109   }
110 
FreeCredentialsHandle(PCredHandle phCredential)111   virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) {
112     return ::FreeCredentialsHandle(phCredential);
113   }
114 
DeleteSecurityContext(PCtxtHandle phContext)115   virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) {
116     return ::DeleteSecurityContext(phContext);
117   }
118 
FreeContextBuffer(PVOID pvContextBuffer)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