• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 The Chromium Authors
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 #include "base/memory/raw_ptr.h"
12 
13 // security.h needs to be included for CredHandle. Unfortunately CredHandle
14 // is a typedef and can't be forward declared.
15 #define SECURITY_WIN32 1
16 #include <windows.h>
17 #include <security.h>
18 
19 #include <string>
20 
21 #include "net/base/completion_once_callback.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/net_export.h"
24 #include "net/http/http_auth.h"
25 #include "net/http/http_auth_mechanism.h"
26 
27 namespace net {
28 
29 class HttpAuthChallengeTokenizer;
30 
31 // SSPILibrary is introduced so unit tests can mock the calls to Windows' SSPI
32 // implementation. The default implementation simply passes the arguments on to
33 // the SSPI implementation provided by Secur32.dll.
34 //
35 // A single SSPILibrary can only be used with a single security package. Hence
36 // the package is bound at construction time. Overridable SSPI methods exclude
37 // the security package parameter since it is implicit.
38 class NET_EXPORT_PRIVATE SSPILibrary {
39  public:
SSPILibrary(const wchar_t * package)40   explicit SSPILibrary(const wchar_t* package) : package_name_(package) {}
~SSPILibrary()41   virtual ~SSPILibrary() {}
42 
43   // Determines the maximum token length in bytes for a particular SSPI package.
44   //
45   // |library| and |max_token_length| must be non-nullptr pointers to valid
46   // objects.
47   //
48   // If the return value is OK, |*max_token_length| contains the maximum token
49   // length in bytes.
50   //
51   // If the return value is ERR_UNSUPPORTED_AUTH_SCHEME, |package| is not an
52   // known SSPI authentication scheme on this system. |*max_token_length| is not
53   // changed.
54   //
55   // If the return value is ERR_UNEXPECTED, there was an unanticipated problem
56   // in the underlying SSPI call. The details are logged, and
57   // |*max_token_length| is not changed.
58   Error DetermineMaxTokenLength(ULONG* max_token_length);
59 
60   virtual SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal,
61                                                    unsigned long fCredentialUse,
62                                                    void* pvLogonId,
63                                                    void* pvAuthData,
64                                                    SEC_GET_KEY_FN pGetKeyFn,
65                                                    void* pvGetKeyArgument,
66                                                    PCredHandle phCredential,
67                                                    PTimeStamp ptsExpiry) = 0;
68 
69   virtual SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential,
70                                                     PCtxtHandle phContext,
71                                                     SEC_WCHAR* pszTargetName,
72                                                     unsigned long fContextReq,
73                                                     unsigned long Reserved1,
74                                                     unsigned long TargetDataRep,
75                                                     PSecBufferDesc pInput,
76                                                     unsigned long Reserved2,
77                                                     PCtxtHandle phNewContext,
78                                                     PSecBufferDesc pOutput,
79                                                     unsigned long* contextAttr,
80                                                     PTimeStamp ptsExpiry) = 0;
81 
82   virtual SECURITY_STATUS QueryContextAttributesEx(PCtxtHandle phContext,
83                                                    ULONG ulAttribute,
84                                                    PVOID pBuffer,
85                                                    ULONG cbBuffer) = 0;
86 
87   virtual SECURITY_STATUS QuerySecurityPackageInfo(PSecPkgInfoW* pkgInfo) = 0;
88 
89   virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) = 0;
90 
91   virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) = 0;
92 
93   virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) = 0;
94 
95  protected:
96   // Security package used with DetermineMaxTokenLength(),
97   // QuerySecurityPackageInfo(), AcquireCredentialsHandle(). All of these must
98   // be consistent.
99   const std::wstring package_name_;
100   ULONG max_token_length_ = 0;
101 
102   bool is_supported_ = true;
103 };
104 
105 class SSPILibraryDefault : public SSPILibrary {
106  public:
SSPILibraryDefault(const wchar_t * package)107   explicit SSPILibraryDefault(const wchar_t* package) : SSPILibrary(package) {}
~SSPILibraryDefault()108   ~SSPILibraryDefault() override {}
109 
110   SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal,
111                                            unsigned long fCredentialUse,
112                                            void* pvLogonId,
113                                            void* pvAuthData,
114                                            SEC_GET_KEY_FN pGetKeyFn,
115                                            void* pvGetKeyArgument,
116                                            PCredHandle phCredential,
117                                            PTimeStamp ptsExpiry) override;
118 
119   SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential,
120                                             PCtxtHandle phContext,
121                                             SEC_WCHAR* pszTargetName,
122                                             unsigned long fContextReq,
123                                             unsigned long Reserved1,
124                                             unsigned long TargetDataRep,
125                                             PSecBufferDesc pInput,
126                                             unsigned long Reserved2,
127                                             PCtxtHandle phNewContext,
128                                             PSecBufferDesc pOutput,
129                                             unsigned long* contextAttr,
130                                             PTimeStamp ptsExpiry) override;
131 
132   SECURITY_STATUS QueryContextAttributesEx(PCtxtHandle phContext,
133                                            ULONG ulAttribute,
134                                            PVOID pBuffer,
135                                            ULONG cbBuffer) override;
136 
137   SECURITY_STATUS QuerySecurityPackageInfo(PSecPkgInfoW* pkgInfo) override;
138 
139   SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) override;
140 
141   SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) override;
142 
143   SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) override;
144 };
145 
146 class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpAuthMechanism {
147  public:
148   HttpAuthSSPI(SSPILibrary* sspi_library, HttpAuth::Scheme scheme);
149   ~HttpAuthSSPI() override;
150 
151   // HttpAuthMechanism implementation:
152   bool Init(const NetLogWithSource& net_log) override;
153   bool NeedsIdentity() const override;
154   bool AllowsExplicitCredentials() const override;
155   HttpAuth::AuthorizationResult ParseChallenge(
156       HttpAuthChallengeTokenizer* tok) override;
157   int GenerateAuthToken(const AuthCredentials* credentials,
158                         const std::string& spn,
159                         const std::string& channel_bindings,
160                         std::string* auth_token,
161                         const NetLogWithSource& net_log,
162                         CompletionOnceCallback callback) override;
163   void SetDelegation(HttpAuth::DelegationType delegation_type) override;
164 
165  private:
166   int OnFirstRound(const AuthCredentials* credentials,
167                    const NetLogWithSource& net_log);
168 
169   int GetNextSecurityToken(const std::string& spn,
170                            const std::string& channing_bindings,
171                            const void* in_token,
172                            int in_token_len,
173                            const NetLogWithSource& net_log,
174                            void** out_token,
175                            int* out_token_len);
176 
177   void ResetSecurityContext();
178 
179   raw_ptr<SSPILibrary> library_;
180   HttpAuth::Scheme scheme_;
181   std::string decoded_server_auth_token_;
182   CredHandle cred_;
183   CtxtHandle ctxt_;
184   HttpAuth::DelegationType delegation_type_;
185 };
186 
187 // Splits |combined| into domain and username.
188 // If |combined| is of form "FOO\bar", |domain| will contain "FOO" and |user|
189 // will contain "bar".
190 // If |combined| is of form "bar", |domain| will be empty and |user| will
191 // contain "bar".
192 // |domain| and |user| must be non-nullptr.
193 NET_EXPORT_PRIVATE void SplitDomainAndUser(const std::u16string& combined,
194                                            std::u16string* domain,
195                                            std::u16string* user);
196 
197 }  // namespace net
198 
199 #endif  // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
200