2006-03-12 Helge Hess <helge.hess@opengroupware.org>
+ * v4.5.223
+
+ * SoObjects: started SoCookieAuthenticator
+
+ * SoObjects/SoHTTPAuthenticator.m: code cleanups
+
* SoObjects/SoProductLoader.m: quickfix to API (v4.5.222)
* SoObjects: added new class SoProductLoader which can be used to
SoSecurityException.h \
SoComponent.h \
SoProductLoader.h \
+ SoCookieAuthenticator.h \
SoObjects_OBJC_FILES = \
NSException+HTTP.m \
SoSecurityException.m \
SoComponent.m \
SoProductLoader.m \
+ SoCookieAuthenticator.m \
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/subproject.make
--- /dev/null
+/*
+ Copyright (C) 2006 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __SoObjects_SoCookieAuthenticator_H__
+#define __SoObjects_SoCookieAuthenticator_H__
+
+#import <Foundation/NSObject.h>
+
+/*
+ SoCookieAuthenticator
+
+ SoCookieAuthenticator is an abstract base class for Cookie based
+ authentication. That is, it uses a Cookie to store the credentials
+ or a token of a session.
+ In the simplest case you only need to override -checkLogin:password:
+ to ensure login/password combinations.
+
+ NOTE: work in progress.
+
+ TODO: we also need a WOSessionAuthenticator which assumes that the
+ existance of a session implies a successful authentication?
+*/
+
+@class NSString, NSException, NSArray;
+@class WOContext, WOResponse, WOCookie;
+@class SoUser;
+
+@interface SoCookieAuthenticator : NSObject
+{
+}
+
+/* password checker (override in subclasses !) */
+
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd;
+
+/* Cookie authentication */
+
+- (NSString *)cookieNameInContext:(WOContext *)_ctx;
+- (WOResponse *)preprocessCredentialsInContext:(WOContext *)_ctx;
+
+- (NSString *)checkCredentialsInContext:(WOContext *)_ctx;
+- (NSArray *)parseCredentials:(NSString *)_creds;
+
+/* user management */
+
+- (SoUser *)userInContext:(WOContext *)_ctx;
+- (NSArray *)rolesForLogin:(NSString *)_login;
+
+/* render auth exceptions of SoSecurityManager */
+
+- (BOOL)renderException:(NSException *)_e inContext:(WOContext *)_ctx;
+
+@end
+
+#endif /* __SoObjects_SoCookieAuthenticator_H__ */
--- /dev/null
+/*
+ Copyright (C) 2006 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "SoCookieAuthenticator.h"
+#include "SoHTTPAuthenticator.h"
+#include "SoUser.h"
+#include "SoPermissions.h"
+#include "NSException+HTTP.h"
+#include <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WORequest.h>
+#include <NGObjWeb/WOResponse.h>
+#include <NGObjWeb/WOContext.h>
+#include <NGObjWeb/WOCookie.h>
+#include <NGExtensions/NSString+Ext.h>
+#include "common.h"
+
+#if APPLE_RUNTIME || NeXT_RUNTIME
+@interface NSObject(Miss)
+- (void)subclassResponsibility:(SEL)cmd;
+@end
+#endif
+
+// TODO: do we have 'anonymous' in such a scenario???
+// TODO: we want to redirect to a login panel and include the root URL
+// using a query path
+
+@implementation SoCookieAuthenticator
+
+static NSString *prefix = @"0xHIGHFLYx";
+
++ (int)version {
+ return 1;
+}
+
+/* HTTP basic authentication */
+
+- (NSString *)cookieNameInContext:(WOContext *)_ctx {
+ return [prefix stringByAppendingString:[[_ctx application] name]];
+}
+
+/* check for roles */
+
+- (BOOL)checkLogin:(NSString *)_login password:(NSString *)_pwd {
+ [self subclassResponsibility:_cmd];
+ return NO;
+}
+
+- (NSArray *)parseCredentials:(NSString *)_creds {
+ if (![_creds isNotEmpty])
+ return nil;
+
+ /* per default we just reuse HTTP basic credentials! */
+ return [SoHTTPAuthenticator parseCredentials:_creds];
+}
+
+- (NSString *)checkCredentials:(NSString *)_creds {
+ /* checks credentials, returnes login if successful */
+ NSString *login, *pwd;
+ NSArray *creds;
+
+ if (![(creds = [self parseCredentials:_creds]) isNotEmpty])
+ return nil;
+
+ login = [creds objectAtIndex:0];
+ if ([login isEqualToString:@"anonymous"])
+ return @"anonymous";
+
+ pwd = [creds objectAtIndex:1];
+ if (![self checkLogin:login password:pwd])
+ return nil;
+
+ return login;
+}
+
+- (NSString *)checkCredentialsInContext:(WOContext *)_ctx {
+ WORequest *rq;
+ NSString *auth;
+
+ rq = [_ctx request];
+
+ auth = [rq cookieValueForKey:[self cookieNameInContext:_ctx]];
+ if (![auth isNotEmpty]) {
+ /* no auth supplied */
+ return @"anonymous";
+ }
+ return [self checkCredentials:auth];
+}
+
+- (NSArray *)rolesForLogin:(NSString *)_login {
+ // TODO: I suppose this should be overridden?
+ NSArray *uroles;
+
+ // could add manager of login=root
+
+ uroles = [NSArray arrayWithObjects:
+ SoRole_Authenticated,
+ SoRole_Anonymous,
+ nil];
+ return uroles;
+}
+
+- (SoUser *)userWithLogin:(NSString *)_login andRoles:(NSArray *)_roles
+ inContext:(WOContext *)_ctx
+{
+ /* the actual factory method */
+ return [[[SoUser alloc] initWithLogin:_login roles:_roles] autorelease];
+}
+
+- (SoUser *)userInContext:(WOContext *)_ctx {
+ static SoUser *anonymous = nil;
+ NSString *login;
+ NSArray *uroles;
+
+ if (anonymous == nil) {
+ NSArray *ar = [NSArray arrayWithObject:SoRole_Anonymous];
+ anonymous = [[SoUser alloc] initWithLogin:@"anonymous" roles:ar];
+ }
+
+ if ((login = [self checkCredentialsInContext:_ctx]) == nil)
+ /* some error (otherwise result would have been anonymous */
+ return nil;
+
+ if ([login isEqualToString:@"anonymous"])
+ return anonymous;
+
+ uroles = [self rolesForLogin:login];
+ return [self userWithLogin:login andRoles:uroles inContext:_ctx];
+}
+
+/* auth fail handling */
+
+- (void)setupAuthFailResponse:(WOResponse *)_response
+ withReason:(NSString *)_reason inContext:(WOContext *)_ctx
+{
+ [_response appendContentString:@"TODO: render login page ..."];
+}
+
+- (WOResponse *)unauthorized:(NSString *)_reason inContext:(WOContext *)_ctx {
+ WOResponse *r;
+
+ if (![_reason isNotEmpty]) _reason = @"Unauthorized";
+
+ r = [_ctx response];
+ [self setupAuthFailResponse:r withReason:_reason inContext:_ctx];
+ return r;
+}
+
+- (BOOL)renderException:(NSException *)_e inContext:(WOContext *)_ctx {
+ /*
+ TODO: this can be called for content which is not accessible to the
+ user? (but the user is otherwise perfectly ok?)
+ Should not: in this case we should get a 404?
+ */
+ if ([_e httpStatus] != 401)
+ return NO;
+
+ [self setupAuthFailResponse:[_ctx response]
+ withReason:[_e reason] inContext:_ctx];
+ return YES;
+}
+
+/* request preprocessing */
+
+- (WOResponse *)preprocessCredentialsInContext:(WOContext *)_ctx {
+ /*
+ This is called by SoObjectRequestHandler prior doing any significant
+ processing to allow the authenticator to reject invalid requests.
+ */
+ WOResponse *r;
+ NSString *auth;
+ NSString *k;
+ NSString *user, *pwd;
+ NSRange rng;
+
+ auth = [[_ctx request] cookieValueForKey:[self cookieNameInContext:_ctx]];
+ if (![auth isNotEmpty]) {
+ /* no authentication provided */
+ static NSArray *anon = nil;
+ if (anon == nil)
+ anon = [[NSArray alloc] initWithObjects:SoRole_Anonymous, nil];
+
+ [_ctx setObject:anon forKey:@"SoAuthenticatedRoles"];
+ return nil;
+ }
+
+ /* authentication provided, check whether it's valid */
+
+ r = [_ctx response];
+ if ([auth length] < 6) {
+ [self logWithFormat:@"tried unknown authentication method: %@ (A)", auth];
+ return [self unauthorized:@"unsupported authentication method"
+ inContext:_ctx];
+ }
+ k = [[auth substringToIndex:5] lowercaseString];
+ if (![k hasPrefix:@"basic"]) {
+ [self logWithFormat:@"tried unknown authentication method: %@ (B)", auth];
+ return [self unauthorized:@"unsupported authentication method"
+ inContext:_ctx];
+ }
+
+ k = [auth substringFromIndex:6];
+ if ((k = [k stringByDecodingBase64]) == nil) {
+ [self logWithFormat:@"tried unknown authentication method: %@ (C)", auth];
+ return [self unauthorized:@"unsupported authentication method"
+ inContext:_ctx];
+ }
+
+ rng = [k rangeOfString:@":"];
+ if (rng.length <= 0) {
+ [self logWithFormat:@"got malformed basic credentials (missing colon)!"];
+ return [self unauthorized:@"malformed basic credentials!" inContext:_ctx];
+ }
+
+ user = [k substringToIndex:rng.location];
+ pwd = [k substringFromIndex:(rng.location + rng.length)];
+
+ rng = [user rangeOfString:@"\\"];
+ if (rng.length > 0) {
+ [self debugWithFormat:@"splitting of domain in user: '%@'", user];
+ user = [user substringFromIndex:(rng.location + rng.length)];
+ }
+
+ if (![user isNotEmpty]) {
+ [self logWithFormat:@"got malformed basic credentials!"];
+ return [self unauthorized:@"empty login in credentials?" inContext:_ctx];
+ }
+ if (![pwd isNotEmpty]) {
+ [self logWithFormat:@"got empty password for user '%@'!", user];
+ return [self unauthorized:@"empty passwords unsupported!" inContext:_ctx];
+ }
+
+ /* authenticate valid credentials */
+
+ if (![self checkLogin:user password:pwd]) {
+ [self logWithFormat:@"tried wrong password for user '%@'!", user];
+ return [self unauthorized:nil inContext:_ctx];
+ }
+
+ //[self debugWithFormat:@"authenticated user '%@'", user];
+
+ /* authentication succeeded */
+ {
+ static NSArray *auth = nil;
+ if (auth == nil) {
+ auth = [[NSArray alloc] initWithObjects:
+ SoRole_Authenticated, SoRole_Anonymous, nil];
+ }
+ [_ctx setObject:auth forKey:@"SoAuthenticatedRoles"];
+ }
+ return nil;
+}
+
+@end /* SoCookieAuthenticator */
/*
- Copyright (C) 2002-2005 SKYRIX Software AG
+ Copyright (C)
+ 2002-2006 SKYRIX Software AG
+ 2006 Helge Hess
This file is part of SOPE.
NSString *login, *pwd;
NSString *k;
- if ([_creds length] == 0) {
+ if (![_creds isNotEmpty]) {
static NSArray *anon = nil;
if (anon == nil)
anon = [[NSArray alloc] initWithObjects:@"anonymous", @"", nil];
NSString *login, *pwd;
NSArray *creds;
- if ((creds = [self parseCredentials:_creds]) == nil)
+ if (![(creds = [self parseCredentials:_creds]) isNotEmpty])
return nil;
-
+
login = [creds objectAtIndex:0];
if ([login isEqualToString:@"anonymous"])
return @"anonymous";
uroles = [NSArray arrayWithObjects:
SoRole_Authenticated,
SoRole_Anonymous,
- nil];
+ nil];
return uroles;
}
WOResponse *r;
NSString *auth;
- if ([_reason length] == 0) _reason = @"Unauthorized";
+ if (![_reason isNotEmpty]) _reason = @"Unauthorized";
auth = [NSString stringWithFormat:@"basic realm=\"%@\"",
[self authRealmInContext:_ctx]];
user = [user substringFromIndex:(rng.location + rng.length)];
}
- if ([user length] == 0) {
+ if (![user isNotEmpty]) {
[self logWithFormat:@"got malformed basic credentials!"];
return [self unauthorized:@"empty login in credentials?" inContext:_ctx];
}
- if ([pwd length] == 0) {
+ if (![pwd isNotEmpty]) {
[self logWithFormat:@"got empty password for user '%@'!", user];
return [self unauthorized:@"empty passwords unsupported!" inContext:_ctx];
}
# version file
-SUBMINOR_VERSION:=222
+SUBMINOR_VERSION:=223
# v4.5.214 requires libNGExtensions v4.5.179
# v4.5.122 requires libNGExtensions v4.5.153
--- /dev/null
+/*
+ Copyright (C) 2006 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include <NGObjWeb/SoApplication.h>
+
+@interface SoCookieAuth : SoApplication
+{
+}
+
+@end
+
+#include <NGObjWeb/SoCookieAuthenticator.h>
+#include "common.h"
+
+@implementation SoCookieAuth
+
+- (id)authenticatorInContext:(id)_ctx {
+ return [[[SoCookieAuthenticator alloc] init] autorelease];
+}
+
+@end /* SoCookieAuth */
+
+
+
+int main(int argc, char **argv, char **env) {
+ NSAutoreleasePool *pool;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ WOApplicationMain(@"SoCookieAuth", argc, (void*)argv);
+
+ [pool release];
+ return 0;
+}
--- /dev/null
+2005-07-10 Helge Hess <helge.hess@opengroupware.org>
+
+ * created ChangeLog / project
+
--- /dev/null
+# GNUstep makefile
+
+-include ../../../config.make
+include $(GNUSTEP_MAKEFILES)/common.make
+
+WOAPP_NAME = SoCookieAuth
+
+SoCookieAuth_OBJC_FILES += Application.m Main.m
+SoCookieAuth_COMPONENTS += Main.wo
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/woapp.make
+-include GNUmakefile.postamble
--- /dev/null
+# compile settings
+
+APPSERVER="../.."
+
+ADDITIONAL_LIB_DIRS += \
+ -L$(APPSERVER)/NGObjWeb/$(GNUSTEP_OBJ_DIR)
+
+# static references required for Mach linker
+
+ADDITIONAL_TOOL_LIBS += \
+ -lEOControl \
+ -lDOM -lXmlRpc -lSaxObjC
+
+ADDITIONAL_LIB_DIRS += -L/usr/local/lib -L/usr/lib
--- /dev/null
+/*
+ Copyright (C) 2006 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include <NGObjWeb/WOComponent.h>
+
+@class NSArray;
+
+@interface Main : WOComponent
+{
+}
+
+@end
+
+#include "common.h"
+
+@implementation Main
+
+- (id)initWithContext:(WOContext *)_ctx {
+ if ((self = [super initWithContext:_ctx]) != nil) {
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+/* accessors */
+
+#if 0
+- (void)setItem:(id)_item {
+ ASSIGN(self->item, _item);
+}
+- (id)item {
+ return self->item;
+}
+#endif
+
+@end /* Main */
--- /dev/null
+WORK IN PROGRESS
+
+App to test SOPE cookie authentication (SoCookieAuthenticator)
--- /dev/null
+/*
+ Copyright (C) 2006 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/Foundation.h>
+#include <NGObjWeb/NGObjWeb.h>