mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
Updates to perform rudimentary digest authentication.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@23086 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
74fa1937cb
commit
a242a43259
4 changed files with 138 additions and 23 deletions
|
@ -6,6 +6,7 @@
|
||||||
* Source/NSURLProtectionSpace.m: Implement ([-hash]) and ([-isEqual:])
|
* Source/NSURLProtectionSpace.m: Implement ([-hash]) and ([-isEqual:])
|
||||||
* Headers/Foundation/NSURLAuthenticationChallenge.h: Improve comments.
|
* Headers/Foundation/NSURLAuthenticationChallenge.h: Improve comments.
|
||||||
Add GSHTTPDigest class to handle HTTP digest authentication.
|
Add GSHTTPDigest class to handle HTTP digest authentication.
|
||||||
|
* Source/GSHTTPURLHandle.m: Perform rudimentary digest authentication.
|
||||||
|
|
||||||
2006-06-17 Richard Frith-Macdonald <rfm@gnu.org>
|
2006-06-17 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
static NSMutableDictionary *store = nil;
|
static NSMutableDictionary *store = nil;
|
||||||
static GSLazyLock *storeLock = nil;
|
static GSLazyLock *storeLock = nil;
|
||||||
|
static GSMimeParser *mimeParser = nil;
|
||||||
|
|
||||||
@interface NSData(GSHTTPDigest)
|
@interface NSData(GSHTTPDigest)
|
||||||
- (NSString*) digestHex;
|
- (NSString*) digestHex;
|
||||||
|
@ -73,6 +74,7 @@ static GSLazyLock *storeLock = nil;
|
||||||
{
|
{
|
||||||
if (store == nil)
|
if (store == nil)
|
||||||
{
|
{
|
||||||
|
mimeParser = [GSMimeParser new];
|
||||||
store = [NSMutableDictionary new];
|
store = [NSMutableDictionary new];
|
||||||
storeLock = [GSLazyLock new];
|
storeLock = [GSLazyLock new];
|
||||||
}
|
}
|
||||||
|
@ -107,6 +109,38 @@ static GSLazyLock *storeLock = nil;
|
||||||
return AUTORELEASE(digest);
|
return AUTORELEASE(digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSString*) digestRealmForAuthentication: (NSString*)authentication
|
||||||
|
{
|
||||||
|
if (authentication != nil)
|
||||||
|
{
|
||||||
|
NSScanner *sc;
|
||||||
|
NSString *key;
|
||||||
|
NSString *val;
|
||||||
|
|
||||||
|
sc = [NSScanner scannerWithString: authentication];
|
||||||
|
if ([sc scanString: @"Digest" intoString: 0] == NO)
|
||||||
|
{
|
||||||
|
return nil; // Not a digest authentication
|
||||||
|
}
|
||||||
|
while ((key = [mimeParser scanName: sc]) != nil)
|
||||||
|
{
|
||||||
|
if ([sc scanString: @"=" intoString: 0] == NO)
|
||||||
|
{
|
||||||
|
return nil; // Bad name=value specification
|
||||||
|
}
|
||||||
|
if ((val = [mimeParser scanToken: sc]) == nil)
|
||||||
|
{
|
||||||
|
return nil; // Bad name=value specification
|
||||||
|
}
|
||||||
|
if ([key caseInsensitiveCompare: @"realm"] == NSOrderedSame)
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString*) authorizationForAuthentication: (NSString*)authentication
|
- (NSString*) authorizationForAuthentication: (NSString*)authentication
|
||||||
method: (NSString*)method
|
method: (NSString*)method
|
||||||
path: (NSString*)path
|
path: (NSString*)path
|
||||||
|
@ -121,34 +155,29 @@ static GSLazyLock *storeLock = nil;
|
||||||
NSString *HA1;
|
NSString *HA1;
|
||||||
NSString *HA2;
|
NSString *HA2;
|
||||||
NSString *response;
|
NSString *response;
|
||||||
NSString *authorisation;
|
NSMutableString *authorisation;
|
||||||
int nc;
|
int nc;
|
||||||
|
|
||||||
if (authentication != nil)
|
if (authentication != nil)
|
||||||
{
|
{
|
||||||
static GSMimeParser *p = nil;
|
|
||||||
NSScanner *sc;
|
NSScanner *sc;
|
||||||
NSString *key;
|
NSString *key;
|
||||||
NSString *val;
|
NSString *val;
|
||||||
|
|
||||||
if (p == nil)
|
|
||||||
{
|
|
||||||
p = [GSMimeParser new];
|
|
||||||
}
|
|
||||||
sc = [NSScanner scannerWithString: authentication];
|
sc = [NSScanner scannerWithString: authentication];
|
||||||
if ([sc scanString: @"Digest" intoString: 0] == NO)
|
if ([sc scanString: @"Digest" intoString: 0] == NO)
|
||||||
{
|
{
|
||||||
NSDebugMLog(@"Bad format HTTP digest in '%@'", authentication);
|
NSDebugMLog(@"Bad format HTTP digest in '%@'", authentication);
|
||||||
return nil; // Not a digest authentication
|
return nil; // Not a digest authentication
|
||||||
}
|
}
|
||||||
while ((key = [p scanName: sc]) != nil)
|
while ((key = [mimeParser scanName: sc]) != nil)
|
||||||
{
|
{
|
||||||
if ([sc scanString: @"=" intoString: 0] == NO)
|
if ([sc scanString: @"=" intoString: 0] == NO)
|
||||||
{
|
{
|
||||||
NSDebugMLog(@"Missing '=' in HTTP digest '%@'", authentication);
|
NSDebugMLog(@"Missing '=' in HTTP digest '%@'", authentication);
|
||||||
return nil; // Bad name=value specification
|
return nil; // Bad name=value specification
|
||||||
}
|
}
|
||||||
if ((val = [p scanToken: sc]) == nil)
|
if ((val = [mimeParser scanToken: sc]) == nil)
|
||||||
{
|
{
|
||||||
NSDebugMLog(@"Missing value in HTTP digest '%@'", authentication);
|
NSDebugMLog(@"Missing value in HTTP digest '%@'", authentication);
|
||||||
return nil; // Bad name=value specification
|
return nil; // Bad name=value specification
|
||||||
|
@ -198,11 +227,6 @@ static GSLazyLock *storeLock = nil;
|
||||||
NSDebugMLog(@"Missing HTTP digest nonce in '%@'", authentication);
|
NSDebugMLog(@"Missing HTTP digest nonce in '%@'", authentication);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
if (opaque == nil)
|
|
||||||
{
|
|
||||||
NSDebugMLog(@"Missing HTTP digest opaque in '%@'", authentication);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([algorithm isEqual: @"MD5"] == NO)
|
if ([algorithm isEqual: @"MD5"] == NO)
|
||||||
{
|
{
|
||||||
|
@ -253,11 +277,19 @@ static GSLazyLock *storeLock = nil;
|
||||||
HA1, nonce, nc, cnonce, qop, HA2]
|
HA1, nonce, nc, cnonce, qop, HA2]
|
||||||
dataUsingEncoding: NSUTF8StringEncoding] md5Digest] digestHex];
|
dataUsingEncoding: NSUTF8StringEncoding] md5Digest] digestHex];
|
||||||
|
|
||||||
authorisation = [NSString stringWithFormat: @"Digest username=\"%@\","
|
authorisation = [NSMutableString stringWithCapacity: 512];
|
||||||
@"realm=\"%@\",nonce=\"%@\",uri=\"%@\",qop=\"%@\",nc=%08x,cnonce=\"%@\","
|
[authorisation appendFormat: @"Digest realm=\"%@\"", realm];
|
||||||
@"response=\"%@\",opaque=\"%@\"",
|
[authorisation appendFormat: @",username=\"%@\"", [self->_credential user]];
|
||||||
[self->_credential user],
|
[authorisation appendFormat: @",nonce=\"%@\"", nonce];
|
||||||
realm, nonce, path, qop, nc, cnonce, response, opaque];
|
[authorisation appendFormat: @",uri=\"%@\"", path];
|
||||||
|
[authorisation appendFormat: @",response=\"%@\"", response];
|
||||||
|
[authorisation appendFormat: @",qop=\"%@\"", qop];
|
||||||
|
[authorisation appendFormat: @",nc=%08x", nc];
|
||||||
|
[authorisation appendFormat: @",cnonce=\"%@\"", cnonce];
|
||||||
|
if (opaque != nil)
|
||||||
|
{
|
||||||
|
[authorisation appendFormat: @",opaque=\"%@\"", opaque];
|
||||||
|
}
|
||||||
|
|
||||||
[self->_lock unlock];
|
[self->_lock unlock];
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "GNUstepBase/GSMime.h"
|
#include "GNUstepBase/GSMime.h"
|
||||||
#include "GNUstepBase/GSLock.h"
|
#include "GNUstepBase/GSLock.h"
|
||||||
#include "NSCallBacks.h"
|
#include "NSCallBacks.h"
|
||||||
|
#include "GSURLPrivate.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
|
@ -569,17 +570,94 @@ static void debugWrite(GSHTTPURLHandle *handle, NSData *data)
|
||||||
* Retrieve essential keys from document
|
* Retrieve essential keys from document
|
||||||
*/
|
*/
|
||||||
info = [document headerNamed: @"http"];
|
info = [document headerNamed: @"http"];
|
||||||
|
val = [info objectForKey: NSHTTPPropertyStatusCodeKey];
|
||||||
|
if ([val intValue] == 401)
|
||||||
|
{
|
||||||
|
NSString *a;
|
||||||
|
GSMimeHeader *ah;
|
||||||
|
|
||||||
|
a = (id)NSMapGet(wProperties, (void*)@"Authorization");
|
||||||
|
if ([a hasPrefix: @"Basic"] == YES
|
||||||
|
&& (ah = [document headerNamed: @"WWW-Authenticate"]) != nil)
|
||||||
|
{
|
||||||
|
NSString *realm;
|
||||||
|
NSString *ac;
|
||||||
|
|
||||||
|
ac = [ah value];
|
||||||
|
realm = [GSHTTPDigest digestRealmForAuthentication: ac];
|
||||||
|
if (realm != nil)
|
||||||
|
{
|
||||||
|
NSURLProtectionSpace *space;
|
||||||
|
NSURLCredential *cred;
|
||||||
|
GSHTTPDigest *digest;
|
||||||
|
NSString *method;
|
||||||
|
NSString *a;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create credential from user and password
|
||||||
|
* stored in the URL.
|
||||||
|
*/
|
||||||
|
cred = [[NSURLCredential alloc]
|
||||||
|
initWithUser: [url user]
|
||||||
|
password: [url password]
|
||||||
|
persistence: NSURLCredentialPersistenceForSession];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create protection space from the information in
|
||||||
|
* the URL and the realm of the authentication
|
||||||
|
* challenge.
|
||||||
|
*/
|
||||||
|
space = [[NSURLProtectionSpace alloc]
|
||||||
|
initWithHost: [url host]
|
||||||
|
port: [[url port] intValue]
|
||||||
|
protocol: [url scheme]
|
||||||
|
realm: realm
|
||||||
|
authenticationMethod:
|
||||||
|
NSURLAuthenticationMethodHTTPDigest];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the digest object and ask it for a header
|
||||||
|
* to use for authorisation.
|
||||||
|
*/
|
||||||
|
digest = [GSHTTPDigest digestWithCredential: cred
|
||||||
|
inProtectionSpace: space];
|
||||||
|
RELEASE(cred);
|
||||||
|
RELEASE(space);
|
||||||
|
|
||||||
|
method = [request objectForKey: GSHTTPPropertyMethodKey];
|
||||||
|
if (method == nil)
|
||||||
|
{
|
||||||
|
if ([wData length] > 0)
|
||||||
|
{
|
||||||
|
method = @"POST";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
method = @"GET";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a = [digest authorizationForAuthentication: ac
|
||||||
|
method: method
|
||||||
|
path: [url path]];
|
||||||
|
if (a != nil)
|
||||||
|
{
|
||||||
|
[self writeProperty: a forKey: @"Authorization"];
|
||||||
|
[self _tryLoadInBackground: u];
|
||||||
|
return; // Retrying.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val != nil)
|
||||||
|
{
|
||||||
|
[pageInfo setObject: val forKey: NSHTTPPropertyStatusCodeKey];
|
||||||
|
}
|
||||||
val = [info objectForKey: NSHTTPPropertyServerHTTPVersionKey];
|
val = [info objectForKey: NSHTTPPropertyServerHTTPVersionKey];
|
||||||
if (val != nil)
|
if (val != nil)
|
||||||
{
|
{
|
||||||
[pageInfo setObject: val
|
[pageInfo setObject: val
|
||||||
forKey: NSHTTPPropertyServerHTTPVersionKey];
|
forKey: NSHTTPPropertyServerHTTPVersionKey];
|
||||||
}
|
}
|
||||||
val = [info objectForKey: NSHTTPPropertyStatusCodeKey];
|
|
||||||
if (val != nil)
|
|
||||||
{
|
|
||||||
[pageInfo setObject: val forKey: NSHTTPPropertyStatusCodeKey];
|
|
||||||
}
|
|
||||||
val = [info objectForKey: NSHTTPPropertyStatusReasonKey];
|
val = [info objectForKey: NSHTTPPropertyStatusReasonKey];
|
||||||
if (val != nil)
|
if (val != nil)
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,6 +84,10 @@
|
||||||
*/
|
*/
|
||||||
+ (GSHTTPDigest *) digestWithCredential: (NSURLCredential*)credential
|
+ (GSHTTPDigest *) digestWithCredential: (NSURLCredential*)credential
|
||||||
inProtectionSpace: (NSURLProtectionSpace*)space;
|
inProtectionSpace: (NSURLProtectionSpace*)space;
|
||||||
|
/*
|
||||||
|
* Look for a digest realm in a header
|
||||||
|
*/
|
||||||
|
+ (NSString*) digestRealmForAuthentication: (NSString*)authentication;
|
||||||
/*
|
/*
|
||||||
* Generate next authorisation header for the specified authentication
|
* Generate next authorisation header for the specified authentication
|
||||||
* header, method, and path.
|
* header, method, and path.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue