mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +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
aa858059f5
commit
a3898bd77b
4 changed files with 138 additions and 23 deletions
|
@ -6,6 +6,7 @@
|
|||
* Source/NSURLProtectionSpace.m: Implement ([-hash]) and ([-isEqual:])
|
||||
* Headers/Foundation/NSURLAuthenticationChallenge.h: Improve comments.
|
||||
Add GSHTTPDigest class to handle HTTP digest authentication.
|
||||
* Source/GSHTTPURLHandle.m: Perform rudimentary digest authentication.
|
||||
|
||||
2006-06-17 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
static NSMutableDictionary *store = nil;
|
||||
static GSLazyLock *storeLock = nil;
|
||||
static GSMimeParser *mimeParser = nil;
|
||||
|
||||
@interface NSData(GSHTTPDigest)
|
||||
- (NSString*) digestHex;
|
||||
|
@ -73,6 +74,7 @@ static GSLazyLock *storeLock = nil;
|
|||
{
|
||||
if (store == nil)
|
||||
{
|
||||
mimeParser = [GSMimeParser new];
|
||||
store = [NSMutableDictionary new];
|
||||
storeLock = [GSLazyLock new];
|
||||
}
|
||||
|
@ -107,6 +109,38 @@ static GSLazyLock *storeLock = nil;
|
|||
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
|
||||
method: (NSString*)method
|
||||
path: (NSString*)path
|
||||
|
@ -121,34 +155,29 @@ static GSLazyLock *storeLock = nil;
|
|||
NSString *HA1;
|
||||
NSString *HA2;
|
||||
NSString *response;
|
||||
NSString *authorisation;
|
||||
NSMutableString *authorisation;
|
||||
int nc;
|
||||
|
||||
if (authentication != nil)
|
||||
{
|
||||
static GSMimeParser *p = nil;
|
||||
NSScanner *sc;
|
||||
NSString *key;
|
||||
NSString *val;
|
||||
|
||||
if (p == nil)
|
||||
{
|
||||
p = [GSMimeParser new];
|
||||
}
|
||||
sc = [NSScanner scannerWithString: authentication];
|
||||
if ([sc scanString: @"Digest" intoString: 0] == NO)
|
||||
{
|
||||
NSDebugMLog(@"Bad format HTTP digest in '%@'", 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)
|
||||
{
|
||||
NSDebugMLog(@"Missing '=' in HTTP digest '%@'", authentication);
|
||||
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);
|
||||
return nil; // Bad name=value specification
|
||||
|
@ -198,11 +227,6 @@ static GSLazyLock *storeLock = nil;
|
|||
NSDebugMLog(@"Missing HTTP digest nonce in '%@'", authentication);
|
||||
return nil;
|
||||
}
|
||||
if (opaque == nil)
|
||||
{
|
||||
NSDebugMLog(@"Missing HTTP digest opaque in '%@'", authentication);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([algorithm isEqual: @"MD5"] == NO)
|
||||
{
|
||||
|
@ -253,11 +277,19 @@ static GSLazyLock *storeLock = nil;
|
|||
HA1, nonce, nc, cnonce, qop, HA2]
|
||||
dataUsingEncoding: NSUTF8StringEncoding] md5Digest] digestHex];
|
||||
|
||||
authorisation = [NSString stringWithFormat: @"Digest username=\"%@\","
|
||||
@"realm=\"%@\",nonce=\"%@\",uri=\"%@\",qop=\"%@\",nc=%08x,cnonce=\"%@\","
|
||||
@"response=\"%@\",opaque=\"%@\"",
|
||||
[self->_credential user],
|
||||
realm, nonce, path, qop, nc, cnonce, response, opaque];
|
||||
authorisation = [NSMutableString stringWithCapacity: 512];
|
||||
[authorisation appendFormat: @"Digest realm=\"%@\"", realm];
|
||||
[authorisation appendFormat: @",username=\"%@\"", [self->_credential user]];
|
||||
[authorisation appendFormat: @",nonce=\"%@\"", nonce];
|
||||
[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];
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "GNUstepBase/GSMime.h"
|
||||
#include "GNUstepBase/GSLock.h"
|
||||
#include "NSCallBacks.h"
|
||||
#include "GSURLPrivate.h"
|
||||
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
|
@ -569,17 +570,94 @@ static void debugWrite(GSHTTPURLHandle *handle, NSData *data)
|
|||
* Retrieve essential keys from document
|
||||
*/
|
||||
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];
|
||||
if (val != nil)
|
||||
{
|
||||
[pageInfo setObject: val
|
||||
forKey: NSHTTPPropertyServerHTTPVersionKey];
|
||||
}
|
||||
val = [info objectForKey: NSHTTPPropertyStatusCodeKey];
|
||||
if (val != nil)
|
||||
{
|
||||
[pageInfo setObject: val forKey: NSHTTPPropertyStatusCodeKey];
|
||||
}
|
||||
val = [info objectForKey: NSHTTPPropertyStatusReasonKey];
|
||||
if (val != nil)
|
||||
{
|
||||
|
|
|
@ -84,6 +84,10 @@
|
|||
*/
|
||||
+ (GSHTTPDigest *) digestWithCredential: (NSURLCredential*)credential
|
||||
inProtectionSpace: (NSURLProtectionSpace*)space;
|
||||
/*
|
||||
* Look for a digest realm in a header
|
||||
*/
|
||||
+ (NSString*) digestRealmForAuthentication: (NSString*)authentication;
|
||||
/*
|
||||
* Generate next authorisation header for the specified authentication
|
||||
* header, method, and path.
|
||||
|
|
Loading…
Reference in a new issue