http_auth_sspi_win.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/string16.h"
20#include "net/base/net_export.h"
21#include "net/http/http_auth.h"
22
23namespace 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.
31class 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
68class 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
124class NET_EXPORT_PRIVATE 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  bool AllowsExplicitCredentials() const;
135
136  HttpAuth::AuthorizationResult ParseChallenge(
137      HttpAuth::ChallengeTokenizer* tok);
138
139  // Generates an authentication token for the service specified by the
140  // Service Principal Name |spn| and stores the value in |*auth_token|.
141  // If the return value is not |OK|, then the value of |*auth_token| is
142  // unspecified. ERR_IO_PENDING is not a valid return code.
143  // If this is the first round of a multiple round scheme, credentials are
144  // obtained using |*credentials|. If |credentials| is NULL, the credentials
145  // for the currently logged in user are used instead.
146  int GenerateAuthToken(const AuthCredentials* credentials,
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 AuthCredentials* credentials);
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.
183NET_EXPORT_PRIVATE 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.
201NET_EXPORT_PRIVATE 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