blob: 050268931bd3e823d43cd12e8a443d2f17238c92 [file] [log] [blame]
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "AuthenticationMac.h"
#import "AuthenticationCF.h"
#import "AuthenticationChallenge.h"
#import "AuthenticationClient.h"
#import "Credential.h"
#import "ProtectionSpace.h"
#import <Foundation/NSURLAuthenticationChallenge.h>
#import <Foundation/NSURLCredential.h>
#import <Foundation/NSURLProtectionSpace.h>
#if USE(CFNETWORK)
@interface NSURLProtectionSpace (Details)
- (CFURLProtectionSpaceRef) _cfurlprotectionspace;
- (id)_initWithCFURLProtectionSpace:(CFURLProtectionSpaceRef)cfProtSpace;
@end
@interface NSURLAuthenticationChallenge (Details)
+(NSURLAuthenticationChallenge *)_authenticationChallengeForCFAuthChallenge:(CFURLAuthChallengeRef)cfChallenge sender:(id <NSURLAuthenticationChallengeSender>)sender;
@end
@interface NSURLCredential (Details)
- (id) _initWithCFURLCredential:(CFURLCredentialRef)credential;
- (CFURLCredentialRef) _cfurlcredential;
@end
#endif
using namespace WebCore;
@interface WebCoreAuthenticationClientAsChallengeSender : NSObject <NSURLAuthenticationChallengeSender>
{
AuthenticationClient* m_client;
#if USE(CFNETWORK)
CFURLAuthChallengeRef m_cfChallenge;
#endif
}
- (id)initWithAuthenticationClient:(AuthenticationClient*)client;
- (AuthenticationClient*)client;
- (void)detachClient;
@end
@implementation WebCoreAuthenticationClientAsChallengeSender
- (id)initWithAuthenticationClient:(AuthenticationClient*)client
{
self = [self init];
if (!self)
return nil;
m_client = client;
return self;
}
- (AuthenticationClient*)client
{
return m_client;
}
- (void)detachClient
{
m_client = 0;
}
- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (m_client)
m_client->receivedCredential(core(challenge), core(credential));
}
- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (m_client)
m_client->receivedRequestToContinueWithoutCredential(core(challenge));
}
- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (m_client)
m_client->receivedCancellation(core(challenge));
}
#if USE(CFNETWORK)
- (void)setCFChallenge:(CFURLAuthChallengeRef)challenge
{
m_cfChallenge = challenge;
}
- (CFURLAuthChallengeRef)cfChallenge
{
return m_cfChallenge;
}
#endif
@end
namespace WebCore {
#if USE(CFNETWORK)
AuthenticationChallenge core(NSURLAuthenticationChallenge *macChallenge)
{
WebCoreAuthenticationClientAsChallengeSender *challengeSender = (WebCoreAuthenticationClientAsChallengeSender*) [macChallenge sender];
return AuthenticationChallenge([challengeSender cfChallenge], [challengeSender client]);
}
Credential core(NSURLCredential *macCredential)
{
return core([macCredential _cfurlcredential]);
}
ProtectionSpace core(NSURLProtectionSpace *macSpace)
{
return core([macSpace _cfurlprotectionspace]);
}
NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace)
{
RetainPtr<CFURLProtectionSpaceRef> protectionSpace(AdoptCF, createCF(coreSpace));
return [[[NSURLProtectionSpace alloc] _initWithCFURLProtectionSpace:protectionSpace.get()] autorelease];
}
NSURLAuthenticationChallenge *mac(const AuthenticationChallenge& coreChallenge)
{
AuthenticationClient* authClient = coreChallenge.authenticationClient();
RetainPtr<WebCoreAuthenticationClientAsChallengeSender> challengeSender(AdoptNS, [[WebCoreAuthenticationClientAsChallengeSender alloc] initWithAuthenticationClient:authClient]);
RetainPtr<CFURLAuthChallengeRef> authChallenge = coreChallenge.cfURLAuthChallengeRef();
if (!authChallenge)
authChallenge.adoptCF(createCF(coreChallenge));
[challengeSender.get() setCFChallenge:authChallenge.get()];
return [[NSURLAuthenticationChallenge _authenticationChallengeForCFAuthChallenge:authChallenge.get() sender:challengeSender.get()] autorelease];
}
NSURLCredential *mac(const Credential& coreCredential)
{
RetainPtr<CFURLCredentialRef> credential(AdoptCF, createCF(coreCredential));
return [[[NSURLCredential alloc] _initWithCFURLCredential:credential.get()] autorelease];
}
#else
#if !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED == 1050
// There is no constant in headers, but NTLM is supported.
NSString * const NSURLAuthenticationMethodNTLM = @"NSURLAuthenticationMethodNTLM";
#endif
AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace,
const Credential& proposedCredential,
unsigned previousFailureCount,
const ResourceResponse& response,
const ResourceError& error)
: AuthenticationChallengeBase(protectionSpace,
proposedCredential,
previousFailureCount,
response,
error)
{
}
AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *challenge)
: AuthenticationChallengeBase(core([challenge protectionSpace]),
core([challenge proposedCredential]),
[challenge previousFailureCount],
[challenge failureResponse],
[challenge error])
, m_sender([challenge sender])
, m_nsChallenge(challenge)
{
}
void AuthenticationChallenge::setAuthenticationClient(AuthenticationClient* client)
{
if (client) {
m_sender.adoptNS([[WebCoreAuthenticationClientAsChallengeSender alloc] initWithAuthenticationClient:client]);
m_nsChallenge.adoptNS([[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:m_nsChallenge.get() sender:m_sender.get()]);
} else {
if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]])
[(WebCoreAuthenticationClientAsChallengeSender *)m_sender.get() detachClient];
}
}
AuthenticationClient* AuthenticationChallenge::authenticationClient() const
{
if ([m_sender.get() isMemberOfClass:[WebCoreAuthenticationClientAsChallengeSender class]])
return [static_cast<WebCoreAuthenticationClientAsChallengeSender*>(m_sender.get()) client];
return 0;
}
bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
{
if (a.sender() != b.sender())
return false;
if (a.nsURLAuthenticationChallenge() != b.nsURLAuthenticationChallenge())
return false;
return true;
}
NSURLAuthenticationChallenge *mac(const AuthenticationChallenge& coreChallenge)
{
if (coreChallenge.nsURLAuthenticationChallenge())
return coreChallenge.nsURLAuthenticationChallenge();
return [[[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:mac(coreChallenge.protectionSpace())
proposedCredential:mac(coreChallenge.proposedCredential())
previousFailureCount:coreChallenge.previousFailureCount()
failureResponse:coreChallenge.failureResponse().nsURLResponse()
error:coreChallenge.error()
sender:coreChallenge.sender()] autorelease];
}
NSURLProtectionSpace *mac(const ProtectionSpace& coreSpace)
{
NSString *proxyType = nil;
NSString *protocol = nil;
switch (coreSpace.serverType()) {
case ProtectionSpaceServerHTTP:
protocol = @"http";
break;
case ProtectionSpaceServerHTTPS:
protocol = @"https";
break;
case ProtectionSpaceServerFTP:
protocol = @"ftp";
break;
case ProtectionSpaceServerFTPS:
protocol = @"ftps";
break;
case ProtectionSpaceProxyHTTP:
proxyType = NSURLProtectionSpaceHTTPProxy;
break;
case ProtectionSpaceProxyHTTPS:
proxyType = NSURLProtectionSpaceHTTPSProxy;
break;
case ProtectionSpaceProxyFTP:
proxyType = NSURLProtectionSpaceFTPProxy;
break;
case ProtectionSpaceProxySOCKS:
proxyType = NSURLProtectionSpaceSOCKSProxy;
break;
default:
ASSERT_NOT_REACHED();
}
NSString *method = nil;
switch (coreSpace.authenticationScheme()) {
case ProtectionSpaceAuthenticationSchemeDefault:
method = NSURLAuthenticationMethodDefault;
break;
case ProtectionSpaceAuthenticationSchemeHTTPBasic:
method = NSURLAuthenticationMethodHTTPBasic;
break;
case ProtectionSpaceAuthenticationSchemeHTTPDigest:
method = NSURLAuthenticationMethodHTTPDigest;
break;
case ProtectionSpaceAuthenticationSchemeHTMLForm:
method = NSURLAuthenticationMethodHTMLForm;
break;
case ProtectionSpaceAuthenticationSchemeNTLM:
method = NSURLAuthenticationMethodNTLM;
break;
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
case ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested:
method = NSURLAuthenticationMethodServerTrust;
break;
case ProtectionSpaceAuthenticationSchemeClientCertificateRequested:
method = NSURLAuthenticationMethodClientCertificate;
break;
#endif
default:
ASSERT_NOT_REACHED();
}
if (proxyType)
return [[[NSURLProtectionSpace alloc] initWithProxyHost:coreSpace.host()
port:coreSpace.port()
type:proxyType
realm:coreSpace.realm()
authenticationMethod:method] autorelease];
return [[[NSURLProtectionSpace alloc] initWithHost:coreSpace.host()
port:coreSpace.port()
protocol:protocol
realm:coreSpace.realm()
authenticationMethod:method] autorelease];
}
NSURLCredential *mac(const Credential& coreCredential)
{
if (coreCredential.isEmpty())
return nil;
NSURLCredentialPersistence persistence = NSURLCredentialPersistenceNone;
switch (coreCredential.persistence()) {
case CredentialPersistenceNone:
break;
case CredentialPersistenceForSession:
persistence = NSURLCredentialPersistenceForSession;
break;
case CredentialPersistencePermanent:
persistence = NSURLCredentialPersistencePermanent;
break;
default:
ASSERT_NOT_REACHED();
}
#if CERTIFICATE_CREDENTIALS_SUPPORTED
if (coreCredential.type() == CredentialTypeClientCertificate) {
return [[[NSURLCredential alloc] initWithIdentity:coreCredential.identity()
certificates:(NSArray *)coreCredential.certificates()
persistence:persistence]
autorelease];
}
#endif
return [[[NSURLCredential alloc] initWithUser:coreCredential.user()
password:coreCredential.password()
persistence:persistence]
autorelease];
}
AuthenticationChallenge core(NSURLAuthenticationChallenge *macChallenge)
{
return AuthenticationChallenge(macChallenge);
}
ProtectionSpace core(NSURLProtectionSpace *macSpace)
{
ProtectionSpaceServerType serverType = ProtectionSpaceProxyHTTP;
if ([macSpace isProxy]) {
NSString *proxyType = [macSpace proxyType];
if ([proxyType isEqualToString:NSURLProtectionSpaceHTTPProxy])
serverType = ProtectionSpaceProxyHTTP;
else if ([proxyType isEqualToString:NSURLProtectionSpaceHTTPSProxy])
serverType = ProtectionSpaceProxyHTTPS;
else if ([proxyType isEqualToString:NSURLProtectionSpaceFTPProxy])
serverType = ProtectionSpaceProxyFTP;
else if ([proxyType isEqualToString:NSURLProtectionSpaceSOCKSProxy])
serverType = ProtectionSpaceProxySOCKS;
else
ASSERT_NOT_REACHED();
} else {
NSString *protocol = [macSpace protocol];
if ([protocol caseInsensitiveCompare:@"http"] == NSOrderedSame)
serverType = ProtectionSpaceServerHTTP;
else if ([protocol caseInsensitiveCompare:@"https"] == NSOrderedSame)
serverType = ProtectionSpaceServerHTTPS;
else if ([protocol caseInsensitiveCompare:@"ftp"] == NSOrderedSame)
serverType = ProtectionSpaceServerFTP;
else if ([protocol caseInsensitiveCompare:@"ftps"] == NSOrderedSame)
serverType = ProtectionSpaceServerFTPS;
else
ASSERT_NOT_REACHED();
}
ProtectionSpaceAuthenticationScheme scheme = ProtectionSpaceAuthenticationSchemeDefault;
NSString *method = [macSpace authenticationMethod];
if ([method isEqualToString:NSURLAuthenticationMethodDefault])
scheme = ProtectionSpaceAuthenticationSchemeDefault;
else if ([method isEqualToString:NSURLAuthenticationMethodHTTPBasic])
scheme = ProtectionSpaceAuthenticationSchemeHTTPBasic;
else if ([method isEqualToString:NSURLAuthenticationMethodHTTPDigest])
scheme = ProtectionSpaceAuthenticationSchemeHTTPDigest;
else if ([method isEqualToString:NSURLAuthenticationMethodHTMLForm])
scheme = ProtectionSpaceAuthenticationSchemeHTMLForm;
else if ([method isEqualToString:NSURLAuthenticationMethodNTLM])
scheme = ProtectionSpaceAuthenticationSchemeNTLM;
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
else if ([method isEqualToString:NSURLAuthenticationMethodClientCertificate])
scheme = ProtectionSpaceAuthenticationSchemeClientCertificateRequested;
else if ([method isEqualToString:NSURLAuthenticationMethodServerTrust])
scheme = ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
#endif
else {
scheme = ProtectionSpaceAuthenticationSchemeUnknown;
ASSERT_NOT_REACHED();
}
return ProtectionSpace([macSpace host], [macSpace port], serverType, [macSpace realm], scheme);
}
Credential core(NSURLCredential *macCredential)
{
CredentialPersistence persistence = CredentialPersistenceNone;
switch ([macCredential persistence]) {
case NSURLCredentialPersistenceNone:
break;
case NSURLCredentialPersistenceForSession:
persistence = CredentialPersistenceForSession;
break;
case NSURLCredentialPersistencePermanent:
persistence = CredentialPersistencePermanent;
break;
default:
ASSERT_NOT_REACHED();
}
#if CERTIFICATE_CREDENTIALS_SUPPORTED
SecIdentityRef identity = [macCredential identity];
if (identity)
return Credential(identity, (CFArrayRef)[macCredential certificates], persistence);
#endif
return Credential([macCredential user], [macCredential password], persistence);
}
#endif // USE(CFNETWORK)
} // namespace WebCore