Finalized support for SAML2 logon
parent
695fc5fff9
commit
aeabd85c90
|
@ -28,13 +28,30 @@
|
|||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include <lasso/lasso.h>
|
||||
|
||||
@class NSString;
|
||||
|
||||
@interface SOGoSAML2Session : NSObject
|
||||
{
|
||||
LassoLogin *lassoLogin;
|
||||
|
||||
NSString *login;
|
||||
NSString *identifier;
|
||||
}
|
||||
|
||||
+ (NSString *) metadataInContext: (WOContext *) context;
|
||||
+ (NSString *) authenticationURLInContext: (WOContext *) context;
|
||||
|
||||
+ (SOGoSAML2Session *) SAML2SessionInContext: (WOContext *) context;
|
||||
|
||||
+ (SOGoSAML2Session *) SAML2SessionWithIdentifier: (NSString *) newIdentifier
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
- (void) processAuthnResponse: (NSString *) authnResponse;
|
||||
|
||||
- (NSString *) login;
|
||||
- (NSString *) identifier;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -20,7 +20,18 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <lasso/lasso.h>
|
||||
#include <lasso/xml/misc_text_node.h>
|
||||
#include <lasso/xml/saml-2.0/saml2_attribute.h>
|
||||
#include <lasso/xml/saml-2.0/saml2_attribute_statement.h>
|
||||
#include <lasso/xml/saml-2.0/saml2_attribute_value.h>
|
||||
#include <lasso/xml/saml-2.0/samlp2_authn_request.h>
|
||||
#include <lasso/xml/saml-2.0/samlp2_response.h>
|
||||
|
||||
#import <Foundation/NSBundle.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSMapTable.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
|
@ -29,25 +40,154 @@
|
|||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import "SOGoCache.h"
|
||||
#import "SOGoSAML2Exceptions.h"
|
||||
#import "SOGoSystemDefaults.h"
|
||||
|
||||
#import "SOGoSAML2Session.h"
|
||||
|
||||
@interface WOContext (SOGoSAML2Extension)
|
||||
|
||||
- (NSString *) SAML2ServerURLString;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WOContext (SOGoSAML2Extension)
|
||||
|
||||
- (NSString *) SAML2ServerURLString
|
||||
{
|
||||
NSString *appName;
|
||||
NSURL *serverURL;
|
||||
|
||||
appName = [[WOApplication application] name];
|
||||
serverURL = [NSURL URLWithString: [NSString stringWithFormat: @"/%@",
|
||||
appName]
|
||||
relativeToURL: [self serverURL]];
|
||||
|
||||
return [serverURL absoluteString];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SOGoSAML2Session
|
||||
|
||||
static NSMapTable *serverTable = nil;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (!serverTable)
|
||||
{
|
||||
serverTable = [NSMapTable mapTableWithStrongToWeakObjects];
|
||||
[serverTable retain];
|
||||
}
|
||||
lasso_init ();
|
||||
}
|
||||
|
||||
static LassoServer *
|
||||
LassoServerInContext (WOContext *context)
|
||||
{
|
||||
NSString *urlString, *metadata, *filename, *keyContent, *certContent,
|
||||
*idpKeyFilename, *idpCertFilename;
|
||||
LassoServer *server;
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
urlString = [context SAML2ServerURLString];
|
||||
server = NSMapGet (serverTable, urlString);
|
||||
if (!server)
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
filename = [sd SAML2PrivateKeyLocation];
|
||||
if (!filename)
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"'SAML2PrivateKeyLocation' not set"];
|
||||
keyContent = [NSString stringWithContentsOfFile: filename];
|
||||
if (!keyContent)
|
||||
[NSException raise: NSGenericException
|
||||
format: @"private key file '%@' could not be read",
|
||||
filename];
|
||||
|
||||
filename = [sd SAML2CertificateLocation];
|
||||
if (!filename)
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"'SAML2CertificateLocation' not set"];
|
||||
certContent = [NSString stringWithContentsOfFile: filename];
|
||||
if (!certContent)
|
||||
[NSException raise: NSGenericException
|
||||
format: @"certificate file '%@' could not be read",
|
||||
filename];
|
||||
|
||||
metadata = [SOGoSAML2Session metadataInContext: context];
|
||||
/* FIXME: enable key password in config ? */
|
||||
server = lasso_server_new_from_buffers ([metadata UTF8String],
|
||||
[keyContent UTF8String],
|
||||
NULL,
|
||||
[certContent UTF8String]);
|
||||
|
||||
filename = [sd SAML2IdpMetadataLocation];
|
||||
idpKeyFilename = [sd SAML2IdpPublicKeyLocation];
|
||||
idpCertFilename = [sd SAML2IdpCertificateLocation];
|
||||
lasso_server_add_provider (server, LASSO_PROVIDER_ROLE_IDP,
|
||||
[filename UTF8String],
|
||||
[idpKeyFilename UTF8String],
|
||||
[idpCertFilename UTF8String]);
|
||||
NSMapInsert (serverTable, urlString, server);
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
+ (NSString *) authenticationURLInContext: (WOContext *) context
|
||||
{
|
||||
lasso_error_t rc;
|
||||
LassoServer *server;
|
||||
LassoLogin *tempLogin;
|
||||
LassoSamlp2AuthnRequest *request;
|
||||
NSString *url;
|
||||
GList *providers;
|
||||
|
||||
server = LassoServerInContext (context);
|
||||
tempLogin = lasso_login_new (server);
|
||||
|
||||
providers = g_hash_table_get_keys (server->providers);
|
||||
rc = lasso_login_init_authn_request (tempLogin, providers->data, LASSO_HTTP_METHOD_REDIRECT);
|
||||
if (rc)
|
||||
[NSException raiseSAML2Exception: rc];
|
||||
|
||||
request = LASSO_SAMLP2_AUTHN_REQUEST (LASSO_PROFILE (tempLogin)->request);
|
||||
if (request->NameIDPolicy->Format) {
|
||||
g_free (request->NameIDPolicy->Format);
|
||||
}
|
||||
request->NameIDPolicy->Format = g_strdup(LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT);
|
||||
request->NameIDPolicy->AllowCreate = 1;
|
||||
request->ForceAuthn = TRUE;
|
||||
request->IsPassive = FALSE;
|
||||
if (request->ProtocolBinding) {
|
||||
g_free (request->ProtocolBinding);
|
||||
}
|
||||
// request->NameIDPolicy = strdup (LASSO_LIB_NAMEID_POLICY_TYPE_FEDERATED);
|
||||
// request->consent = strdup (LASSO_LIB_CONSENT_OBTAINED);
|
||||
rc = lasso_login_build_authn_request_msg (tempLogin);
|
||||
if (rc)
|
||||
[NSException raiseSAML2Exception: rc];
|
||||
|
||||
url = [NSString stringWithUTF8String: LASSO_PROFILE (tempLogin)->msg_url];
|
||||
|
||||
g_object_unref (tempLogin);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
+ (NSString *) metadataInContext: (WOContext *) context
|
||||
{
|
||||
NSString *metadata, *serverURLString, *filename, *appName;
|
||||
NSString *metadata, *serverURLString, *filename;
|
||||
NSBundle *bundle;
|
||||
NSURL *serverURL;
|
||||
|
||||
bundle = [NSBundle bundleForClass: self];
|
||||
filename = [bundle pathForResource: @"SOGoSAML2Metadata" ofType: @"xml"];
|
||||
if (filename)
|
||||
{
|
||||
appName = [[WOApplication application] name];
|
||||
serverURL = [NSURL URLWithString: [NSString stringWithFormat: @"/%@/so",
|
||||
appName]
|
||||
relativeToURL: [context serverURL]];
|
||||
serverURLString = [serverURL absoluteString];
|
||||
serverURLString = [context SAML2ServerURLString];
|
||||
metadata = [[NSString stringWithContentsOfFile: filename]
|
||||
stringByReplacingString: @"%{base_url}"
|
||||
withString: serverURLString];
|
||||
|
@ -58,4 +198,204 @@
|
|||
return metadata;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
lassoLogin = NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) _updateDataFromLogin
|
||||
{
|
||||
// LassoSamlp2Response *response;
|
||||
LassoSaml2Assertion *assertion;
|
||||
GList *statementList, *attributeList;
|
||||
LassoSaml2AttributeStatement *statement;
|
||||
LassoSaml2Attribute *attribute;
|
||||
LassoSaml2AttributeValue *value;
|
||||
LassoMiscTextNode *textNode;
|
||||
LassoSaml2NameID *nameIdentifier;
|
||||
|
||||
NSLog (@"lassoLogin: class = %s", g_type_name_from_instance (lassoLogin));
|
||||
|
||||
assertion = LASSO_SAML2_ASSERTION (lasso_login_get_assertion (lassoLogin));
|
||||
if (assertion)
|
||||
{
|
||||
/* deduce user login */
|
||||
[login release];
|
||||
login = nil;
|
||||
|
||||
statementList = assertion->AttributeStatement;
|
||||
while (!login && statementList)
|
||||
{
|
||||
statement = LASSO_SAML2_ATTRIBUTE_STATEMENT (statementList->data);
|
||||
attributeList = statement->Attribute;
|
||||
while (!login && attributeList)
|
||||
{
|
||||
attribute = LASSO_SAML2_ATTRIBUTE (attributeList->data);
|
||||
if (strcmp (attribute->Name, "uid") == 0)
|
||||
{
|
||||
value = LASSO_SAML2_ATTRIBUTE_VALUE (attribute->AttributeValue->data);
|
||||
textNode = value->any->data;
|
||||
login = [NSString stringWithUTF8String: textNode->content];
|
||||
[login retain];
|
||||
}
|
||||
else
|
||||
attributeList = attributeList->next;
|
||||
}
|
||||
statementList = statementList->next;
|
||||
}
|
||||
}
|
||||
|
||||
nameIdentifier
|
||||
= LASSO_SAML2_NAME_ID (LASSO_PROFILE (lassoLogin)->nameIdentifier);
|
||||
if (nameIdentifier)
|
||||
{
|
||||
/* deduce session id */
|
||||
[identifier release];
|
||||
identifier = [NSString stringWithUTF8String: nameIdentifier->content];
|
||||
[identifier retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) _initWithDump: (NSDictionary *) saml2Dump
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
// lasso_error_t rc;
|
||||
LassoServer *server;
|
||||
LassoProfile *profile;
|
||||
const gchar *dump;
|
||||
|
||||
if ((self = [self init]))
|
||||
{
|
||||
server = LassoServerInContext (context);
|
||||
lassoLogin = lasso_login_new (server);
|
||||
if (saml2Dump)
|
||||
{
|
||||
profile = LASSO_PROFILE (lassoLogin);
|
||||
ASSIGN (login, [saml2Dump objectForKey: @"login"]);
|
||||
ASSIGN (identifier, [saml2Dump objectForKey: @"identifier"]);
|
||||
dump = [[saml2Dump objectForKey: @"identity"] UTF8String];
|
||||
if (dump)
|
||||
lasso_profile_set_identity_from_dump (profile, dump);
|
||||
dump = [[saml2Dump objectForKey: @"session"] UTF8String];
|
||||
if (dump)
|
||||
lasso_profile_set_session_from_dump (profile, dump);
|
||||
lasso_login_accept_sso (lassoLogin);
|
||||
// if (rc)
|
||||
// [NSException raiseSAML2Exception: rc];
|
||||
[self _updateDataFromLogin];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (lassoLogin)
|
||||
g_object_unref (lassoLogin);
|
||||
[login release];
|
||||
[identifier release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (SOGoSAML2Session *) _SAML2SessionWithDump: (NSDictionary *) saml2Dump
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
SOGoSAML2Session *newSession;
|
||||
|
||||
newSession = [[self alloc] _initWithDump: saml2Dump inContext: context];
|
||||
[newSession autorelease];
|
||||
|
||||
return newSession;
|
||||
}
|
||||
|
||||
+ (SOGoSAML2Session *) SAML2SessionInContext: (WOContext *) context
|
||||
{
|
||||
return [self _SAML2SessionWithDump: nil inContext: context];
|
||||
}
|
||||
|
||||
+ (SOGoSAML2Session *) SAML2SessionWithIdentifier: (NSString *) identifier
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
SOGoSAML2Session *session = nil;
|
||||
NSDictionary *saml2Dump;
|
||||
|
||||
if (identifier)
|
||||
{
|
||||
saml2Dump = [[SOGoCache sharedCache]
|
||||
saml2LoginDumpsForIdentifier: identifier];
|
||||
if (saml2Dump)
|
||||
session = [self _SAML2SessionWithDump: saml2Dump
|
||||
inContext: context];
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
- (NSString *) login
|
||||
{
|
||||
return login;
|
||||
}
|
||||
|
||||
- (NSString *) identifier
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
|
||||
- (void) processAuthnResponse: (NSString *) authnResponse
|
||||
{
|
||||
lasso_error_t rc;
|
||||
gchar *responseData, *dump;
|
||||
LassoProfile *profile;
|
||||
LassoIdentity *identity;
|
||||
LassoSession *session;
|
||||
NSString *nsDump;
|
||||
NSMutableDictionary *saml2Dump;
|
||||
|
||||
responseData = strdup ([authnResponse UTF8String]);
|
||||
|
||||
rc = lasso_login_process_authn_response_msg (lassoLogin, responseData);
|
||||
if (rc)
|
||||
[NSException raiseSAML2Exception: rc];
|
||||
|
||||
rc = lasso_login_accept_sso (lassoLogin);
|
||||
if (rc)
|
||||
[NSException raiseSAML2Exception: rc];
|
||||
|
||||
[self _updateDataFromLogin];
|
||||
|
||||
saml2Dump = [NSMutableDictionary dictionary];
|
||||
[saml2Dump setObject: login forKey: @"login"];
|
||||
[saml2Dump setObject: identifier forKey: @"identifier"];
|
||||
|
||||
profile = LASSO_PROFILE (lassoLogin);
|
||||
|
||||
session = lasso_profile_get_session (profile);
|
||||
if (session)
|
||||
{
|
||||
dump = lasso_session_dump (session);
|
||||
nsDump = [NSString stringWithUTF8String: dump];
|
||||
[saml2Dump setObject: nsDump forKey: @"session"];
|
||||
lasso_session_destroy (session);
|
||||
}
|
||||
|
||||
identity = lasso_profile_get_identity (profile);
|
||||
if (identity)
|
||||
{
|
||||
dump = lasso_identity_dump (identity);
|
||||
nsDump = [NSString stringWithUTF8String: dump];
|
||||
[saml2Dump setObject: nsDump forKey: @"identity"];
|
||||
lasso_identity_destroy (identity);
|
||||
}
|
||||
|
||||
[[SOGoCache sharedCache] setSaml2LoginDumps: saml2Dump
|
||||
forIdentifier: identifier];
|
||||
free (responseData);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
login: (NSString **) theLogin
|
||||
domain: (NSString **) theDomain
|
||||
password: (NSString **) thePassword;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "SOGoCache.h"
|
||||
|
||||
#import <NGObjWeb/WOCookie.h>
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSData.h>
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
|
||||
@class NSString;
|
||||
|
||||
@class WOContext;
|
||||
@class WOCookie;
|
||||
|
||||
@class SOGoUser;
|
||||
|
||||
@interface SOGoWebAuthenticator : SoCookieAuthenticator <SOGoAuthenticator>
|
||||
|
@ -45,6 +48,10 @@
|
|||
expire: (int *) _expire
|
||||
grace: (int *) _grace;
|
||||
|
||||
- (WOCookie *) cookieWithUsername: (NSString *) username
|
||||
andPassword: (NSString *) password
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* _SOGOWEBAUTHENTICATOR_H_ */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#import <NGObjWeb/WOCookie.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
|
@ -47,7 +48,9 @@
|
|||
#import "SOGoSystemDefaults.h"
|
||||
#import "SOGoUser.h"
|
||||
#import "SOGoUserManager.h"
|
||||
|
||||
#if defined(SAML2_CONFIG)
|
||||
#import "SOGoSAML2Session.h"
|
||||
#endif
|
||||
#import "SOGoWebAuthenticator.h"
|
||||
|
||||
@implementation SOGoWebAuthenticator
|
||||
|
@ -107,11 +110,13 @@
|
|||
{
|
||||
SOGoCASSession *session;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *authenticationType;
|
||||
BOOL rc;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
||||
authenticationType = [sd authenticationType];
|
||||
if ([authenticationType isEqualToString: @"cas"])
|
||||
{
|
||||
session = [SOGoCASSession CASSessionWithIdentifier: _pwd fromProxy: NO];
|
||||
if (session)
|
||||
|
@ -119,6 +124,18 @@
|
|||
else
|
||||
rc = NO;
|
||||
}
|
||||
#if defined(SAML2_CONFIG)
|
||||
else if ([authenticationType isEqualToString: @"saml2"])
|
||||
{
|
||||
SOGoSAML2Session *saml2Session;
|
||||
WOContext *context;
|
||||
|
||||
context = [[WOApplication application] context];
|
||||
saml2Session = [SOGoSAML2Session SAML2SessionWithIdentifier: _pwd
|
||||
inContext: context];
|
||||
rc = [[saml2Session login] isEqualToString: _login];
|
||||
}
|
||||
#endif /* SAML2_CONFIG */
|
||||
else
|
||||
rc = [[SOGoUserManager sharedUserManager] checkLogin: _login
|
||||
password: _pwd
|
||||
|
@ -314,4 +331,44 @@
|
|||
[response addCookie: authCookie];
|
||||
}
|
||||
|
||||
- (WOCookie *) cookieWithUsername: (NSString *) username
|
||||
andPassword: (NSString *) password
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
WOCookie *authCookie;
|
||||
NSString *cookieValue, *cookieString, *appName, *sessionKey, *userKey, *securedPassword;
|
||||
|
||||
//
|
||||
// We create a new cookie - thus we create a new session
|
||||
// associated to the user. For security, we generate:
|
||||
//
|
||||
// A- a session key
|
||||
// B- a user key
|
||||
//
|
||||
// In memcached, the session key will be associated to the user's password
|
||||
// which will be XOR'ed with the user key.
|
||||
//
|
||||
sessionKey = [SOGoSession generateKeyForLength: 16];
|
||||
userKey = [SOGoSession generateKeyForLength: 64];
|
||||
|
||||
NSString *value = [NSString stringWithFormat: @"%@:%@", username, password];
|
||||
securedPassword = [SOGoSession securedValue: value usingKey: userKey];
|
||||
|
||||
|
||||
[SOGoSession setValue: securedPassword forSessionKey: sessionKey];
|
||||
|
||||
//cookieString = [NSString stringWithFormat: @"%@:%@",
|
||||
// username, password];
|
||||
cookieString = [NSString stringWithFormat: @"%@:%@",
|
||||
userKey, sessionKey];
|
||||
cookieValue = [NSString stringWithFormat: @"basic %@",
|
||||
[cookieString stringByEncodingBase64]];
|
||||
authCookie = [WOCookie cookieWithName: [self cookieNameInContext: context]
|
||||
value: cookieValue];
|
||||
appName = [[context request] applicationName];
|
||||
[authCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
||||
|
||||
return authCookie;
|
||||
}
|
||||
|
||||
@end /* SOGoWebAuthenticator */
|
||||
|
|
|
@ -485,13 +485,17 @@
|
|||
BOOL canLogoff;
|
||||
id auth;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *authType;
|
||||
|
||||
auth = [[self clientObject] authenticatorInContext: context];
|
||||
if ([auth respondsToSelector: @selector (cookieNameInContext:)])
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
||||
authType = [sd authenticationType];
|
||||
if ([authType isEqualToString: @"cas"])
|
||||
canLogoff = [sd CASLogoutEnabled];
|
||||
else if ([authType isEqualToString: @"saml2"])
|
||||
canLogoff = [sd SAML2LogoutEnabled];
|
||||
else
|
||||
canLogoff = [[auth cookieNameInContext: context] length] > 0;
|
||||
}
|
||||
|
|
|
@ -4,3 +4,7 @@ ADDITIONAL_CPPFLAGS += \
|
|||
-DSOGO_MAJOR_VERSION=$(MAJOR_VERSION) \
|
||||
-DSOGO_MINOR_VERSION=$(MINOR_VERSION) \
|
||||
-DSOGO_SUBMINOR_VERSION=$(SUBMINOR_VERSION)
|
||||
|
||||
ifeq ($(HAS_LIBRARY_lasso), yes)
|
||||
ADDITIONAL_CPPFLAGS += $(LASSO_CFLAGS)
|
||||
endif
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/SOGoCASSession.h>
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
#if defined(SAML2_CONFIG)
|
||||
#import <SOGo/SOGoSAML2Session.h>
|
||||
#endif /* SAML2_ENABLE */
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
|
@ -100,46 +103,6 @@
|
|||
return ([[self cookieUsername] length]);
|
||||
}
|
||||
|
||||
- (WOCookie *) _cookieWithUsername: (NSString *) username
|
||||
andPassword: (NSString *) password
|
||||
forAuthenticator: (SOGoWebAuthenticator *) auth
|
||||
{
|
||||
WOCookie *authCookie;
|
||||
NSString *cookieValue, *cookieString, *appName, *sessionKey, *userKey, *securedPassword;
|
||||
|
||||
//
|
||||
// We create a new cookie - thus we create a new session
|
||||
// associated to the user. For security, we generate:
|
||||
//
|
||||
// A- a session key
|
||||
// B- a user key
|
||||
//
|
||||
// In memcached, the session key will be associated to the user's password
|
||||
// which will be XOR'ed with the user key.
|
||||
//
|
||||
sessionKey = [SOGoSession generateKeyForLength: 16];
|
||||
userKey = [SOGoSession generateKeyForLength: 64];
|
||||
|
||||
NSString *value = [NSString stringWithFormat: @"%@:%@", username, password];
|
||||
securedPassword = [SOGoSession securedValue: value usingKey: userKey];
|
||||
|
||||
|
||||
[SOGoSession setValue: securedPassword forSessionKey: sessionKey];
|
||||
|
||||
//cookieString = [NSString stringWithFormat: @"%@:%@",
|
||||
// username, password];
|
||||
cookieString = [NSString stringWithFormat: @"%@:%@",
|
||||
userKey, sessionKey];
|
||||
cookieValue = [NSString stringWithFormat: @"basic %@",
|
||||
[cookieString stringByEncodingBase64]];
|
||||
authCookie = [WOCookie cookieWithName: [auth cookieNameInContext: context]
|
||||
value: cookieValue];
|
||||
appName = [[context request] applicationName];
|
||||
[authCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
||||
|
||||
return authCookie;
|
||||
}
|
||||
|
||||
- (WOCookie *) _cookieWithUsername: (NSString *) username
|
||||
{
|
||||
WOCookie *loginCookie;
|
||||
|
@ -172,7 +135,8 @@
|
|||
return loginCookie;
|
||||
}
|
||||
|
||||
- (WOCookie *) _casLocationCookie: (BOOL) cookieReset
|
||||
- (WOCookie *) _authLocationCookie: (BOOL) cookieReset
|
||||
withName: (NSString *) cookieName
|
||||
{
|
||||
WOCookie *locationCookie;
|
||||
NSString *appName;
|
||||
|
@ -180,7 +144,7 @@
|
|||
NSCalendarDate *date;
|
||||
|
||||
rq = [context request];
|
||||
locationCookie = [WOCookie cookieWithName: @"cas-location" value: [rq uri]];
|
||||
locationCookie = [WOCookie cookieWithName: cookieName value: [rq uri]];
|
||||
appName = [rq applicationName];
|
||||
[locationCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
||||
if (cookieReset)
|
||||
|
@ -261,9 +225,9 @@
|
|||
username = [NSString stringWithFormat: @"%@@%@", username, domain];
|
||||
}
|
||||
|
||||
authCookie = [self _cookieWithUsername: username
|
||||
andPassword: password
|
||||
forAuthenticator: auth];
|
||||
authCookie = [auth cookieWithUsername: username
|
||||
andPassword: password
|
||||
inContext: context];
|
||||
[response addCookie: authCookie];
|
||||
|
||||
supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||
|
@ -357,14 +321,15 @@
|
|||
{
|
||||
auth = [[WOApplication application]
|
||||
authenticatorInContext: context];
|
||||
casCookie = [self _cookieWithUsername: login
|
||||
andPassword: [casSession identifier]
|
||||
forAuthenticator: auth];
|
||||
casCookie = [auth cookieWithUsername: login
|
||||
andPassword: [casSession identifier]
|
||||
inContext: context];
|
||||
[casSession updateCache];
|
||||
newLocation = [rq cookieValueForKey: @"cas-location"];
|
||||
/* login callback, we expire the "cas-location" cookie, created
|
||||
below */
|
||||
casLocationCookie = [self _casLocationCookie: YES];
|
||||
casLocationCookie = [self _authLocationCookie: YES
|
||||
withName: @"cas-location"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -388,7 +353,8 @@
|
|||
newLocation
|
||||
= [SOGoCASSession CASURLWithAction: @"login"
|
||||
andParameters: [self _casRedirectKeys]];
|
||||
casLocationCookie = [self _casLocationCookie: NO];
|
||||
casLocationCookie = [self _authLocationCookie: NO
|
||||
withName: @"cas-location"];
|
||||
}
|
||||
response = [self redirectToLocation: newLocation];
|
||||
if (casCookie)
|
||||
|
@ -399,6 +365,51 @@
|
|||
return response;
|
||||
}
|
||||
|
||||
#if defined(SAML2_CONFIG)
|
||||
- (id <WOActionResults>) _saml2DefaultAction
|
||||
{
|
||||
WOResponse *response;
|
||||
NSString *login, *newLocation, *oldLocation;
|
||||
WOCookie *saml2LocationCookie;
|
||||
WORequest *rq;
|
||||
|
||||
saml2LocationCookie = nil;
|
||||
|
||||
newLocation = nil;
|
||||
|
||||
login = [[context activeUser] login];
|
||||
if ([login isEqualToString: @"anonymous"])
|
||||
login = nil;
|
||||
|
||||
if (login)
|
||||
{
|
||||
rq = [context request];
|
||||
newLocation = [rq cookieValueForKey: @"saml2-location"];
|
||||
if (newLocation)
|
||||
saml2LocationCookie = [self _authLocationCookie: YES
|
||||
withName: @"saml2-location"];
|
||||
else
|
||||
{
|
||||
oldLocation = [[self clientObject] baseURLInContext: context];
|
||||
newLocation = [NSString stringWithFormat: @"%@%@",
|
||||
oldLocation, [login stringByEscapingURL]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newLocation = [SOGoSAML2Session authenticationURLInContext: context];
|
||||
saml2LocationCookie = [self _authLocationCookie: NO
|
||||
withName: @"saml2-location"];
|
||||
}
|
||||
|
||||
response = [self redirectToLocation: newLocation];
|
||||
if (saml2LocationCookie)
|
||||
[response addCookie: saml2LocationCookie];
|
||||
|
||||
return response;
|
||||
}
|
||||
#endif /* SAML2_CONFIG */
|
||||
|
||||
- (id <WOActionResults>) _standardDefaultAction
|
||||
{
|
||||
NSObject <WOActionResults> *response;
|
||||
|
@ -433,13 +444,21 @@
|
|||
|
||||
- (id <WOActionResults>) defaultAction
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *authenticationType;
|
||||
id <WOActionResults> result;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
authenticationType = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||
authenticationType];
|
||||
if ([authenticationType isEqualToString: @"cas"])
|
||||
result = [self _casDefaultAction];
|
||||
#if defined(SAML2_CONFIG)
|
||||
else if ([authenticationType isEqualToString: @"saml2"])
|
||||
result = [self _saml2DefaultAction];
|
||||
#endif /* SAML2_CONFIG */
|
||||
else
|
||||
result = [self _standardDefaultAction];
|
||||
|
||||
return ([[sd authenticationType] isEqualToString: @"cas"]
|
||||
? [self _casDefaultAction]
|
||||
: [self _standardDefaultAction]);
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) isPublicInContext: (WOContext *) localContext
|
||||
|
@ -553,9 +572,9 @@
|
|||
}
|
||||
|
||||
response = [self responseWith204];
|
||||
authCookie = [self _cookieWithUsername: username
|
||||
andPassword: newPassword
|
||||
forAuthenticator: auth];
|
||||
authCookie = [auth cookieWithUsername: username
|
||||
andPassword: newPassword
|
||||
inContext: context];
|
||||
[response addCookie: authCookie];
|
||||
}
|
||||
else
|
||||
|
|
|
@ -20,11 +20,22 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGObjWeb/SoApplication.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/SoObject.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOCookie.h>
|
||||
#import <NGObjWeb/WODirectAction.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <SOGo/SOGoSAML2Session.h>
|
||||
#import <SOGo/SOGoWebAuthenticator.h>
|
||||
|
||||
@interface SOGoSAML2Actions : WODirectAction
|
||||
@end
|
||||
|
@ -47,4 +58,60 @@
|
|||
return response;
|
||||
}
|
||||
|
||||
- (WOCookie *) _authLocationResetCookieWithName: (NSString *) cookieName
|
||||
{
|
||||
WOCookie *locationCookie;
|
||||
NSString *appName;
|
||||
WORequest *rq;
|
||||
NSCalendarDate *date;
|
||||
|
||||
rq = [context request];
|
||||
locationCookie = [WOCookie cookieWithName: cookieName value: [rq uri]];
|
||||
appName = [rq applicationName];
|
||||
[locationCookie setPath: [NSString stringWithFormat: @"/%@/", appName]];
|
||||
date = [NSCalendarDate calendarDate];
|
||||
[date setTimeZone: [NSTimeZone timeZoneWithAbbreviation: @"GMT"]];
|
||||
[locationCookie setExpires: [date yesterday]];
|
||||
|
||||
return locationCookie;
|
||||
}
|
||||
|
||||
- (WOResponse *) saml2SignOnPOSTAction
|
||||
{
|
||||
WORequest *rq;
|
||||
WOResponse *response;
|
||||
SoApplication *application;
|
||||
SOGoSAML2Session *newSession;
|
||||
WOCookie *authCookie;
|
||||
NSString *login, *oldLocation, *newLocation;
|
||||
SOGoWebAuthenticator *auth;
|
||||
|
||||
rq = [context request];
|
||||
if ([[rq method] isEqualToString: @"POST"])
|
||||
{
|
||||
newSession = [SOGoSAML2Session SAML2SessionInContext: context];
|
||||
[newSession processAuthnResponse: [rq formValueForKey: @"SAMLResponse"]];
|
||||
login = [newSession login];
|
||||
|
||||
application = [SoApplication application];
|
||||
auth = [application authenticatorInContext: context];
|
||||
authCookie = [auth cookieWithUsername: login
|
||||
andPassword: [newSession identifier]
|
||||
inContext: context];
|
||||
|
||||
oldLocation = [[context clientObject] baseURLInContext: context];
|
||||
newLocation = [NSString stringWithFormat: @"%@/%@",
|
||||
oldLocation, [login stringByEscapingURL]];
|
||||
|
||||
response = [context response];
|
||||
[response setStatus: 302];
|
||||
[response setHeader: @"text/plain; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
[response setHeader: newLocation forKey: @"location"];
|
||||
[response addCookie: authCookie];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -124,21 +124,36 @@
|
|||
actionClass = "SOGoSAML2Actions";
|
||||
actionName = "saml2Metadata";
|
||||
};
|
||||
/* crash = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
actionName = "crash";
|
||||
};
|
||||
exception = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
actionName = "exception";
|
||||
};
|
||||
raisedException = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
actionName = "raisedException";
|
||||
}; */
|
||||
saml2-signon-post = {
|
||||
protectedBy = "<public>";
|
||||
actionClass = "SOGoSAML2Actions";
|
||||
actionName = "saml2SignOnPOST";
|
||||
};
|
||||
/* saml2-signon-redirect = {
|
||||
protectedBy = "<public>";
|
||||
actionClass = "SOGoSAML2Actions";
|
||||
actionName = "saml2SignOnRedirect";
|
||||
};
|
||||
saml2-signon-soap = {
|
||||
protectedBy = "<public>";
|
||||
actionClass = "SOGoSAML2Actions";
|
||||
actionName = "saml2SignOnSOAP";
|
||||
};
|
||||
crash = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
actionName = "crash";
|
||||
};
|
||||
exception = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
actionName = "exception";
|
||||
};
|
||||
raisedException = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
actionName = "raisedException";
|
||||
}; */
|
||||
connect = {
|
||||
protectedBy = "<public>";
|
||||
pageName = "SOGoRootPage";
|
||||
|
|
Loading…
Reference in New Issue