Navigation Menu

Skip to content

Commit

Permalink
Pluggable authentication modules
Browse files Browse the repository at this point in the history
  • Loading branch information
robbiehanson committed Apr 17, 2012
1 parent be5eab5 commit e29af14
Show file tree
Hide file tree
Showing 27 changed files with 1,937 additions and 1,137 deletions.
45 changes: 45 additions & 0 deletions Authentication/Anonymous/XMPPAnonymousAuthentication.h
@@ -0,0 +1,45 @@
#import <Foundation/Foundation.h>
#import "XMPPSASLAuthentication.h"
#import "XMPP.h"


@interface XMPPAnonymousAuthentication : NSObject <XMPPSASLAuthentication>

- (id)initWithStream:(XMPPStream *)stream;

// This class implements the XMPPSASLAuthentication protocol.
//
// See XMPPSASLAuthentication.h for more information.

@end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@interface XMPPStream (XMPPAnonymousAuthentication)

/**
* Returns whether or not the server support anonymous authentication.
*
* This information is available after the stream is connected.
* In other words, after the delegate has received xmppStreamDidConnect: notification.
**/
- (BOOL)supportsAnonymousAuthentication;

/**
* This method attempts to start the anonymous authentication process.
*
* This method is asynchronous.
*
* If there is something immediately wrong,
* such as the stream is not connected or doesn't support anonymous authentication,
* the method will return NO and set the error.
* Otherwise the delegate callbacks are used to communicate auth success or failure.
*
* @see xmppStreamDidAuthenticate:
* @see xmppStream:didNotAuthenticate:
**/
- (BOOL)authenticateAnonymously:(NSError **)errPtr;

@end
131 changes: 131 additions & 0 deletions Authentication/Anonymous/XMPPAnonymousAuthentication.m
@@ -0,0 +1,131 @@
#import "XMPPAnonymousAuthentication.h"
#import "XMPP.h"
#import "XMPPLogging.h"
#import "XMPPInternal.h"
#import "NSXMLElement+XMPP.h"

#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif

// Log levels: off, error, warn, info, verbose
#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO; // | XMPP_LOG_FLAG_TRACE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif

/**
* Seeing a return statements within an inner block
* can sometimes be mistaken for a return point of the enclosing method.
* This makes inline blocks a bit easier to read.
**/
#define return_from_block return


@implementation XMPPAnonymousAuthentication
{
#if __has_feature(objc_arc_weak)
__weak XMPPStream *xmppStream;
#else
__unsafe_unretained XMPPStream *xmppStream;
#endif
}

+ (NSString *)mechanismName
{
return @"ANONYMOUS";
}

- (id)initWithStream:(XMPPStream *)stream
{
if ((self = [super init]))
{
xmppStream = stream;
}
return self;
}

- (id)initWithStream:(XMPPStream *)stream password:(NSString *)password
{
return [self initWithStream:stream];
}

- (BOOL)start:(NSError **)errPtr
{
// <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="ANONYMOUS" />

NSXMLElement *auth = [NSXMLElement elementWithName:@"auth" xmlns:@"urn:ietf:params:xml:ns:xmpp-sasl"];
[auth addAttributeWithName:@"mechanism" stringValue:@"ANONYMOUS"];

[xmppStream sendAuthElement:auth];

return YES;
}

- (XMPPHandleAuthResponse)handleAuth:(NSXMLElement *)authResponse
{
// We're expecting a success response.
// If we get anything else we can safely assume it's the equivalent of a failure response.

if ([[authResponse name] isEqualToString:@"success"])
{
return XMPP_AUTH_SUCCESS;
}
else
{
return XMPP_AUTH_FAIL;
}
}

@end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@implementation XMPPStream (XMPPAnonymousAuthentication)

- (BOOL)supportsAnonymousAuthentication
{
return [self supportsAuthenticationMechanism:[XMPPAnonymousAuthentication mechanismName]];
}

- (BOOL)authenticateAnonymously:(NSError **)errPtr
{
XMPPLogTrace();

__block BOOL result = YES;
__block NSError *err = nil;

dispatch_block_t block = ^{ @autoreleasepool {

if ([self supportsAnonymousAuthentication])
{
XMPPAnonymousAuthentication *anonymousAuth = [[XMPPAnonymousAuthentication alloc] initWithStream:self];

result = [self authenticate:anonymousAuth error:&err];
}
else
{
NSString *errMsg = @"The server does not support anonymous authentication.";
NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];

err = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamUnsupportedAction userInfo:info];

result = NO;
}
}};

if (dispatch_get_current_queue() == xmppQueue)
block();
else
dispatch_sync(xmppQueue, block);

if (errPtr)
*errPtr = err;

return result;
}

@end
@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>
#import "XMPPSASLAuthentication.h"
#import "XMPPStream.h"


@interface XMPPDeprecatedDigestAuthentication : NSObject <XMPPSASLAuthentication>

// This class implements the XMPPSASLAuthentication protocol.
//
// See XMPPSASLAuthentication.h for more information.

@end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@interface XMPPStream (XMPPDeprecatedDigestAuthentication)

- (BOOL)supportsDeprecatedDigestAuthentication;

@end
162 changes: 162 additions & 0 deletions Authentication/Deprecated-Digest/XMPPDeprecatedDigestAuthentication.m
@@ -0,0 +1,162 @@
#import "XMPPDeprecatedDigestAuthentication.h"
#import "XMPP.h"
#import "XMPPInternal.h"
#import "XMPPLogging.h"
#import "NSData+XMPP.h"
#import "NSXMLElement+XMPP.h"

#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif

// Log levels: off, error, warn, info, verbose
#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO; // | XMPP_LOG_FLAG_TRACE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif


@implementation XMPPDeprecatedDigestAuthentication
{
#if __has_feature(objc_arc_weak)
__weak XMPPStream *xmppStream;
#else
__unsafe_unretained XMPPStream *xmppStream;
#endif

NSString *password;
}

+ (NSString *)mechanismName
{
// This deprecated method isn't listed in the normal mechanisms list
return nil;
}

- (id)initWithStream:(XMPPStream *)stream password:(NSString *)inPassword
{
if ((self = [super init]))
{
xmppStream = stream;
password = inPassword;
}
return self;
}

- (BOOL)start:(NSError **)errPtr
{
XMPPLogTrace();

// The server does not appear to support SASL authentication (at least any type we can use)
// So we'll revert back to the old fashioned jabber:iq:auth mechanism

XMPPJID *myJID = xmppStream.myJID;

NSString *username = [myJID user];
NSString *resource = [myJID resource];

if ([resource length] == 0)
{
// If resource is nil or empty, we need to auto-create one

resource = [XMPPStream generateUUID];
}

NSString *rootID = [[[xmppStream rootElement] attributeForName:@"id"] stringValue];
NSString *digestStr = [NSString stringWithFormat:@"%@%@", rootID, password];

NSString *digest = [[[digestStr dataUsingEncoding:NSUTF8StringEncoding] sha1Digest] hexStringValue];

NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:auth"];
[query addChild:[NSXMLElement elementWithName:@"username" stringValue:username]];
[query addChild:[NSXMLElement elementWithName:@"resource" stringValue:resource]];
[query addChild:[NSXMLElement elementWithName:@"digest" stringValue:digest]];

XMPPIQ *iq = [XMPPIQ iqWithType:@"set"];
[iq addChild:query];

[xmppStream sendAuthElement:iq];

return YES;
}

- (XMPPHandleAuthResponse)handleAuth:(NSXMLElement *)authResponse
{
XMPPLogTrace();

// We used the old fashioned jabber:iq:auth mechanism

if ([[authResponse attributeStringValueForName:@"type"] isEqualToString:@"error"])
{
return XMPP_AUTH_FAIL;
}
else
{
return XMPP_AUTH_SUCCESS;
}
}

- (BOOL)shouldResendOpeningNegotiationAfterSuccessfulAuthentication
{
return NO;
}

@end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@implementation XMPPStream (XMPPDeprecatedDigestAuthentication)

/**
* This method only applies to servers that don't support XMPP version 1.0, as defined in RFC 3920.
* With these servers, we attempt to discover supported authentication modes via the jabber:iq:auth namespace.
**/
- (BOOL)supportsDeprecatedDigestAuthentication
{
__block BOOL result = NO;

dispatch_block_t block = ^{ @autoreleasepool {

// The root element can be properly queried for authentication mechanisms anytime after the
// stream:features are received, and TLS has been setup (if required)
if (state >= STATE_XMPP_POST_NEGOTIATION)
{
// Search for an iq element within the rootElement.
// Recall that some servers might stupidly add a "jabber:client" namespace which might cause problems
// if we simply used the elementForName method.

NSXMLElement *iq = nil;

NSUInteger i, count = [rootElement childCount];
for (i = 0; i < count; i++)
{
NSXMLNode *childNode = [rootElement childAtIndex:i];

if ([childNode kind] == NSXMLElementKind)
{
if ([[childNode name] isEqualToString:@"iq"])
{
iq = (NSXMLElement *)childNode;
}
}
}

NSXMLElement *query = [iq elementForName:@"query" xmlns:@"jabber:iq:auth"];
NSXMLElement *digest = [query elementForName:@"digest"];

result = (digest != nil);
}
}};

if (dispatch_get_current_queue() == xmppQueue)
block();
else
dispatch_sync(xmppQueue, block);

return result;
}

@end
@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>
#import "XMPPSASLAuthentication.h"
#import "XMPPStream.h"


@interface XMPPDeprecatedPlainAuthentication : NSObject <XMPPSASLAuthentication>

// This class implements the XMPPSASLAuthentication protocol.
//
// See XMPPSASLAuthentication.h for more information.

@end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@interface XMPPStream (XMPPDeprecatedPlainAuthentication)

- (BOOL)supportsDeprecatedPlainAuthentication;

@end

0 comments on commit e29af14

Please sign in to comment.