1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#import <KerberosHelper/NetworkAuthenticationHelper.h>
25#import <KerberosHelper/KerberosHelper.h>
26#import <Foundation/Foundation.h>
27#import <Foundation/NSURLConnectionPrivate.h>
28#import <CoreServices/CoreServices.h>
29#import <CoreServices/CoreServicesPriv.h>
30
31#include <err.h>
32
33static NSString *username;
34static NSString *password;
35
36@interface NSURLCredential (NSURLCredentialInternal)
37- (id) _initWithCFURLCredential:(CFURLCredentialRef)credential;
38@end
39
40@interface Foo : NSObject <NSURLConnectionDelegate> {
41    NAHRef _nah;
42    CFArrayRef _selections;
43    CFIndex _selection_index;
44}
45
46- (void)req:(NSURL *)url;
47
48
49
50- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
51- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
52- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
53- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
54
55- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse;
56- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
57- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
58- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
59- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
60
61- (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error;
62- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
63
64
65@end
66
67@implementation Foo
68
69
70- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
71{
72	return nil;
73}
74
75- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
76{
77}
78
79
80- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
81{
82}
83
84- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
85{
86}
87
88
89- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
90{
91    NSLog(@"canAuthenticateAgainstProtectionSpace: %@", [protectionSpace authenticationMethod]);
92    if ([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodNegotiate])
93	return YES;
94
95    return NO;
96}
97
98- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
99    NSLog(@"Connection didReceiveResponse! Response - %@", response);
100}
101- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
102    NSLog(@"Finished...");
103	exit(0);
104}
105
106- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
107{
108	NSLog(@"didFailWithError");
109}
110
111- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
112{
113	NSLog(@"willSendRequest");
114	return request;
115}
116
117- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
118{
119	NSLog(@"connectionShouldUseCredentialStorage");
120	return NO;
121}
122
123
124- (void)connection:(NSURLConnection*)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
125{
126    NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
127
128	NSLog(@"didReceiveAuthenticationChallenge: %@ %@", [protectionSpace authenticationMethod], [protectionSpace host]);
129
130    if (_nah == NULL) {
131	CFMutableDictionaryRef info = NULL;
132	CFDictionaryRef krbtoken = NULL;
133
134	info = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
135
136	krbtoken = KRBCreateNegTokenLegacyKerberos(NULL);
137
138	CFDictionaryAddValue(info, kNAHNegTokenInit, krbtoken);
139	CFRelease(krbtoken);
140
141	if (username){
142	    NSLog(@"using %@ as username", username);
143	    CFDictionaryAddValue(info, kNAHUserName, username);
144	}
145
146	if (password)
147	    CFDictionaryAddValue(info, kNAHPassword, password);
148
149	_nah = NAHCreate(NULL, (CFStringRef)[protectionSpace host], CFSTR("HTTP"), info);
150	if (_nah == NULL)
151	    goto failed;
152
153	_selections = NAHGetSelections(_nah);
154	_selection_index = 0;
155    }
156
157 next:
158    if (_selection_index >= CFArrayGetCount(_selections))
159	goto failed;
160
161    NAHSelectionRef sel = (NAHSelectionRef)CFArrayGetValueAtIndex(_selections, _selection_index);
162
163    _selection_index += 1;
164
165    if (!NAHSelectionAcquireCredential(sel, NULL, NULL))
166	goto next;
167
168
169    CFStringRef clientPrincipal = NAHSelectionGetInfoForKey(sel, kNAHClientPrincipal);
170    CFStringRef serverPrincipal = NAHSelectionGetInfoForKey(sel, kNAHServerPrincipal);
171
172	NSLog(@"trying: client: %@ server: %@", (NSString *)clientPrincipal, (NSString *)serverPrincipal);
173
174	CFURLCredentialRef cfCredential = _CFURLCredentialCreateForKerberosTicket(NULL, clientPrincipal, serverPrincipal, NULL);
175    if (cfCredential)
176	goto failed;
177
178    NSURLCredential *credential = [[[NSURLCredential alloc] _initWithCFURLCredential:cfCredential] autorelease];
179
180    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
181
182    CFRelease(cfCredential);
183
184    return;
185
186 failed:
187
188    [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
189
190    if (_selections)
191	CFRelease(_selections);
192    if (_nah)
193	CFRelease(_nah);
194    _nah = NULL;
195    _selections = NULL;
196}
197
198
199
200
201
202- (void)req:(NSURL *)url
203{
204    NSURLRequest *request = [NSURLRequest requestWithURL:url];
205    NSURLConnection *conn;
206
207    conn = [[NSURLConnection alloc] initWithRequest: request delegate: self];
208
209    [conn scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
210
211}
212
213@end
214
215int
216main(int argc, char **argv)
217{
218    NSURL *url;
219    Foo *foo;
220    int ch;
221
222    while ((ch = getopt(argc, argv, "u:p:")) != -1) {
223	switch (ch) {
224	    case 'u':
225		username = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
226		break;
227	    case 'p':
228		password = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
229		break;
230	}
231    }
232
233    argv += optind;
234    argc -= optind;
235
236    if (argc < 0)
237	errx(1, "missing url");
238
239    url = [NSURL URLWithString:[NSString stringWithUTF8String:argv[0]]];
240
241    foo = [[Foo alloc] init];
242
243    [foo req: url];
244
245    [[NSRunLoop currentRunLoop] run];
246
247    NSLog(@"done");
248
249    return 0;
250}
251