2b245c6ea335b0f93001a3c5896fb2c68aacbee9
[WebKit-https.git] / Source / WebCore / platform / network / mac / AuthenticationMac.mm
1 /*
2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 #import "config.h"
26 #import "AuthenticationMac.h"
27
28 #import "AuthenticationCF.h"
29 #import "AuthenticationChallenge.h"
30 #import "AuthenticationClient.h"
31 #import "Credential.h"
32 #import "ProtectionSpace.h"
33
34 #import <Foundation/NSURLAuthenticationChallenge.h>
35 #import <Foundation/NSURLCredential.h>
36 #import <Foundation/NSURLProtectionSpace.h>
37
38 #if USE(CFNETWORK)
39
40 @interface NSURLProtectionSpace (Details)
41 - (CFURLProtectionSpaceRef) _cfurlprotectionspace;
42 - (id)_initWithCFURLProtectionSpace:(CFURLProtectionSpaceRef)cfProtSpace;
43 @end
44
45 @interface NSURLAuthenticationChallenge (Details)
46 +(NSURLAuthenticationChallenge *)_authenticationChallengeForCFAuthChallenge:(CFURLAuthChallengeRef)cfChallenge sender:(id <NSURLAuthenticationChallengeSender>)sender;
47 @end
48
49 @interface NSURLCredential (Details)
50 - (id) _initWithCFURLCredential:(CFURLCredentialRef)credential;
51 - (CFURLCredentialRef) _cfurlcredential;
52 @end
53
54 #endif
55
56 using namespace WebCore;
57
58 @interface WebCoreAuthenticationClientAsChallengeSender : NSObject <NSURLAuthenticationChallengeSender>
59 {
60     AuthenticationClient* m_client;
61 #if USE(CFNETWORK)
62     CFURLAuthChallengeRef m_cfChallenge;
63 #endif
64 }
65 - (id)initWithAuthenticationClient:(AuthenticationClient*)client;
66 - (AuthenticationClient*)client;
67 - (void)detachClient;
68 @end
69
70 @implementation WebCoreAuthenticationClientAsChallengeSender
71
72 - (id)initWithAuthenticationClient:(AuthenticationClient*)client
73 {
74     self = [self init];
75     if (!self)
76         return nil;
77     m_client = client;
78     return self;
79 }
80
81 - (AuthenticationClient*)client
82 {
83     return m_client;
84 }
85
86 - (void)detachClient
87 {
88     m_client = 0;
89 }
90
91 - (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
92 {
93     if (m_client)
94         m_client->receivedCredential(core(challenge), core(credential));
95 }
96
97 - (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
98 {
99     if (m_client)
100         m_client->receivedRequestToContinueWithoutCredential(core(challenge));
101 }
102
103 - (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
104 {
105     if (m_client)
106         m_client->receivedCancellation(core(challenge));
107 }
108
109 #if USE(CFNETWORK)
110 - (void)setCFChallenge:(CFURLAuthChallengeRef)challenge
111 {
112     m_cfChallenge = challenge;
113 }
114
115 - (CFURLAuthChallengeRef)cfChallenge
116 {
117     return m_cfChallenge;
118 }
119 #endif
120
121 @end
122
123 namespace WebCore {
124
125 #if USE(CFNETWORK)
126
127 AuthenticationChallenge core(NSURLAuthenticationChallenge *macChallenge)
128 {
129     WebCoreAuthenticationClientAsChallengeSender *challengeSender = (WebCoreAuthenticationClientAsChallengeSender*) [macChallenge sender];
130     return AuthenticationChallenge([challengeSender cfChallenge], [challengeSender client]);
131 }
132
133 Credential core(NSURLCredential *macCredential)
134 {
135     return core([macCredential _cfurlcredential]);
136 }
137
138 ProtectionSpace core(NSURLProtectionSpace *macSpace)
139 {
140     return core([macSpace _cfurlprotectionspace]);
141 }
142
143 NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace)
144 {
145     RetainPtr<CFURLProtectionSpaceRef> protectionSpace(AdoptCF, createCF(coreSpace));
146     return [[[NSURLProtectionSpace alloc] _initWithCFURLProtectionSpace:protectionSpace.get()] autorelease];
147 }
148
149 NSURLAuthenticationChallenge *mac(const AuthenticationChallenge& coreChallenge)
150 {
151     AuthenticationClient* authClient = coreChallenge.authenticationClient();
152     RetainPtr<WebCoreAuthenticationClientAsChallengeSender> challengeSender(AdoptNS, [[WebCoreAuthenticationClientAsChallengeSender alloc] initWithAuthenticationClient:authClient]);
153     RetainPtr<CFURLAuthChallengeRef> authChallenge = coreChallenge.cfURLAuthChallengeRef();
154     if (!authChallenge)
155         authChallenge.adoptCF(createCF(coreChallenge));
156     [challengeSender.get() setCFChallenge:authChallenge.get()];
157     return [[NSURLAuthenticationChallenge _authenticationChallengeForCFAuthChallenge:authChallenge.get() sender:challengeSender.get()] autorelease];
158 }
159
160 NSURLCredential *mac(const Credential& coreCredential)
161 {
162     RetainPtr<CFURLCredentialRef> credential(AdoptCF, createCF(coreCredential));
163     return [[[NSURLCredential alloc] _initWithCFURLCredential:credential.get()] autorelease];
164 }
165
166 #else
167
168 #if !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED == 1050
169 // There is no constant in headers, but NTLM is supported.
170 NSString * const NSURLAuthenticationMethodNTLM = @"NSURLAuthenticationMethodNTLM";
171 #endif
172
173 static uint64_t generateUniqueIdentifier()
174 {
175     static uint64_t uniqueIdentifier;
176     return ++uniqueIdentifier;
177 }
178
179 AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace,
180                                                  const Credential& proposedCredential,
181                                                  unsigned previousFailureCount,
182                                                  const ResourceResponse& response,
183                                                  const ResourceError& error,
184                                                  uint64_t identifier)
185     : AuthenticationChallengeBase(protectionSpace,
186                                   proposedCredential,
187                                   previousFailureCount,
188                                   response,
189                                   error)
190 {
191     m_identifier = identifier;
192 }
193
194 AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *challenge)
195     : AuthenticationChallengeBase(core([challenge protectionSpace]),
196                                   core([challenge proposedCredential]),
197                                   [challenge previousFailureCount],
198                                   [challenge failureResponse],
199                                   [challenge error])
200     , m_sender([challenge sender])
201     , m_nsChallenge(challenge)
202 {
203     m_identifier = generateUniqueIdentifier();
204 }
205
206 void AuthenticationChallenge::setAuthenticationClient(AuthenticationClient* client)
207 {
208     if (client) {
209         m_sender.adoptNS([[WebCoreAuthenticationClientAsChallengeSender alloc] initWithAuthenticationClient:client]);
210         if (m_nsChallenge)
211             m_nsChallenge.adoptNS([[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:m_nsChallenge.get() sender:m_sender.get()]);
212     } else {
213         if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]])
214             [(WebCoreAuthenticationClientAsChallengeSender *)m_sender.get() detachClient];
215     }
216 }
217
218 AuthenticationClient* AuthenticationChallenge::authenticationClient() const
219 {
220     if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]])
221         return [static_cast<WebCoreAuthenticationClientAsChallengeSender*>(m_sender.get()) client];
222     
223     return 0;
224 }
225
226 bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
227 {
228     if (a.sender() != b.sender())
229         return false;
230         
231     if (a.nsURLAuthenticationChallenge() != b.nsURLAuthenticationChallenge())
232         return false;
233
234     return true;
235 }
236
237 NSURLAuthenticationChallenge *mac(const AuthenticationChallenge& coreChallenge)
238 {
239     if (coreChallenge.nsURLAuthenticationChallenge())
240         return coreChallenge.nsURLAuthenticationChallenge();
241         
242     return [[[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:mac(coreChallenge.protectionSpace())
243                                                        proposedCredential:mac(coreChallenge.proposedCredential())
244                                                      previousFailureCount:coreChallenge.previousFailureCount()
245                                                           failureResponse:coreChallenge.failureResponse().nsURLResponse()
246                                                                     error:coreChallenge.error()
247                                                                    sender:coreChallenge.sender()] autorelease];
248 }
249
250 NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace)
251 {
252     NSString *proxyType = nil;
253     NSString *protocol = nil;
254     switch (coreSpace.serverType()) {
255         case ProtectionSpaceServerHTTP:
256             protocol = @"http";
257             break;
258         case ProtectionSpaceServerHTTPS:
259             protocol = @"https";
260             break;
261         case ProtectionSpaceServerFTP:
262             protocol = @"ftp";
263             break;
264         case ProtectionSpaceServerFTPS:
265             protocol = @"ftps";
266             break;
267         case ProtectionSpaceProxyHTTP:
268             proxyType = NSURLProtectionSpaceHTTPProxy;
269             break;
270         case ProtectionSpaceProxyHTTPS:
271             proxyType = NSURLProtectionSpaceHTTPSProxy;
272             break;
273         case ProtectionSpaceProxyFTP:
274             proxyType = NSURLProtectionSpaceFTPProxy;
275             break;
276         case ProtectionSpaceProxySOCKS:
277             proxyType = NSURLProtectionSpaceSOCKSProxy;
278             break;
279         default:
280             ASSERT_NOT_REACHED();
281     }
282   
283     NSString *method = nil;
284     switch (coreSpace.authenticationScheme()) {
285         case ProtectionSpaceAuthenticationSchemeDefault:
286             method = NSURLAuthenticationMethodDefault;
287             break;
288         case ProtectionSpaceAuthenticationSchemeHTTPBasic:
289             method = NSURLAuthenticationMethodHTTPBasic;
290             break;
291         case ProtectionSpaceAuthenticationSchemeHTTPDigest:
292             method = NSURLAuthenticationMethodHTTPDigest;
293             break;
294         case ProtectionSpaceAuthenticationSchemeHTMLForm:
295             method = NSURLAuthenticationMethodHTMLForm;
296             break;
297         case ProtectionSpaceAuthenticationSchemeNTLM:
298             method = NSURLAuthenticationMethodNTLM;
299             break;
300 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
301         case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
302             method = NSURLAuthenticationMethodServerTrust;
303             break;
304         case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
305             method = NSURLAuthenticationMethodClientCertificate;
306             break;
307 #endif
308         default:
309             ASSERT_NOT_REACHED();
310     }
311     
312     if (proxyType)
313         return [[[NSURLProtectionSpace alloc] initWithProxyHost:coreSpace.host()
314                                                            port:coreSpace.port()
315                                                            type:proxyType
316                                                           realm:coreSpace.realm()
317                                            authenticationMethod:method] autorelease];
318     return [[[NSURLProtectionSpace alloc] initWithHost:coreSpace.host()
319                                                   port:coreSpace.port()
320                                               protocol:protocol
321                                                  realm:coreSpace.realm()
322                                   authenticationMethod:method] autorelease];
323 }
324
325 NSURLCredential *mac(const Credential& coreCredential)
326 {
327     if (coreCredential.isEmpty())
328         return nil;
329
330     NSURLCredentialPersistence persistence = NSURLCredentialPersistenceNone;
331     switch (coreCredential.persistence()) {
332         case CredentialPersistenceNone:
333             break;
334         case CredentialPersistenceForSession:
335             persistence = NSURLCredentialPersistenceForSession;
336             break;
337         case CredentialPersistencePermanent:
338             persistence = NSURLCredentialPersistencePermanent;
339             break;
340         default:
341             ASSERT_NOT_REACHED();
342     }
343
344 #if CERTIFICATE_CREDENTIALS_SUPPORTED
345     if (coreCredential.type() == CredentialTypeClientCertificate) {
346         return [[[NSURLCredential alloc] initWithIdentity:coreCredential.identity()
347                                              certificates:(NSArray *)coreCredential.certificates()
348                                               persistence:persistence]
349                                               autorelease];
350     }
351 #endif
352
353     return [[[NSURLCredential alloc] initWithUser:coreCredential.user()
354                                         password:coreCredential.password()
355                                      persistence:persistence]
356                                      autorelease];
357 }
358
359 AuthenticationChallenge core(NSURLAuthenticationChallenge *macChallenge)
360 {
361     return AuthenticationChallenge(macChallenge);
362 }
363
364 ProtectionSpace core(NSURLProtectionSpace *macSpace)
365 {
366     ProtectionSpaceServerType serverType = ProtectionSpaceProxyHTTP;
367     
368     if ([macSpace isProxy]) {
369         NSString *proxyType = [macSpace proxyType];
370         if ([proxyType isEqualToString:NSURLProtectionSpaceHTTPProxy])
371             serverType = ProtectionSpaceProxyHTTP;
372         else if ([proxyType isEqualToString:NSURLProtectionSpaceHTTPSProxy])
373             serverType = ProtectionSpaceProxyHTTPS;
374         else if ([proxyType isEqualToString:NSURLProtectionSpaceFTPProxy])
375             serverType = ProtectionSpaceProxyFTP;
376         else if ([proxyType isEqualToString:NSURLProtectionSpaceSOCKSProxy])
377             serverType = ProtectionSpaceProxySOCKS;
378         else 
379             ASSERT_NOT_REACHED();
380     } else {
381         NSString *protocol = [macSpace protocol];
382         if ([protocol caseInsensitiveCompare:@"http"] == NSOrderedSame)
383             serverType = ProtectionSpaceServerHTTP;
384         else if ([protocol caseInsensitiveCompare:@"https"] == NSOrderedSame)
385             serverType = ProtectionSpaceServerHTTPS;
386         else if ([protocol caseInsensitiveCompare:@"ftp"] == NSOrderedSame)
387             serverType = ProtectionSpaceServerFTP;
388         else if ([protocol caseInsensitiveCompare:@"ftps"] == NSOrderedSame)
389             serverType = ProtectionSpaceServerFTPS;
390         else
391             ASSERT_NOT_REACHED();
392     }
393
394     ProtectionSpaceAuthenticationScheme scheme = ProtectionSpaceAuthenticationSchemeDefault;
395     NSString *method = [macSpace authenticationMethod];
396     if ([method isEqualToString:NSURLAuthenticationMethodDefault])
397         scheme = ProtectionSpaceAuthenticationSchemeDefault;
398     else if ([method isEqualToString:NSURLAuthenticationMethodHTTPBasic])
399         scheme = ProtectionSpaceAuthenticationSchemeHTTPBasic;
400     else if ([method isEqualToString:NSURLAuthenticationMethodHTTPDigest])
401         scheme = ProtectionSpaceAuthenticationSchemeHTTPDigest;
402     else if ([method isEqualToString:NSURLAuthenticationMethodHTMLForm])
403         scheme = ProtectionSpaceAuthenticationSchemeHTMLForm;
404     else if ([method isEqualToString:NSURLAuthenticationMethodNTLM])
405         scheme = ProtectionSpaceAuthenticationSchemeNTLM;
406 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
407     else if ([method isEqualToString:NSURLAuthenticationMethodClientCertificate])
408         scheme = ProtectionSpaceAuthenticationSchemeClientCertificateRequested;
409     else if ([method isEqualToString:NSURLAuthenticationMethodServerTrust])
410         scheme = ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
411 #endif
412     else {
413         scheme = ProtectionSpaceAuthenticationSchemeUnknown;
414         ASSERT_NOT_REACHED();
415     }
416         
417     return ProtectionSpace([macSpace host], [macSpace port], serverType, [macSpace realm], scheme);
418
419 }
420
421 Credential core(NSURLCredential *macCredential)
422 {
423     CredentialPersistence persistence = CredentialPersistenceNone;
424     switch ([macCredential persistence]) {
425         case NSURLCredentialPersistenceNone:
426             break;
427         case NSURLCredentialPersistenceForSession:
428             persistence = CredentialPersistenceForSession;
429             break;
430         case NSURLCredentialPersistencePermanent:
431             persistence = CredentialPersistencePermanent;
432             break;
433         default:
434             ASSERT_NOT_REACHED();
435     }
436
437 #if CERTIFICATE_CREDENTIALS_SUPPORTED
438     SecIdentityRef identity = [macCredential identity];
439     if (identity)
440         return Credential(identity, (CFArrayRef)[macCredential certificates], persistence);
441 #endif
442     
443     return Credential([macCredential user], [macCredential password], persistence);
444 }
445
446 #endif // USE(CFNETWORK)
447
448 } // namespace WebCore