Add support for CAS LogoutRequests

Fixes #2346
This changes the serviceURL sent by SOGo to the CAS server:
  /SOGo/so/ -> /SOGo/so/index
pull/12/head
Jean Raby 2013-06-20 14:32:14 -04:00
parent d28482557f
commit 41ed498d65
7 changed files with 118 additions and 4 deletions

1
NEWS
View File

@ -20,6 +20,7 @@ Bug fixes
- fixed public access when SOGoTrustProxyAuthentication is used (#2237)
- fixed access right issues with import feature (#2294)
- fixed IMAP ACL issue when SOGoForceExternalLoginWithEmail is used (#2313)
- fixed handling of CAS logoutRequest (#2346)
- OpenChange stability fixes
2.0.5a (2013-04-17)

View File

@ -140,7 +140,8 @@ SOGo_OBJC_FILES = \
SOGo_RESOURCE_FILES = \
SOGoDefaults.plist \
DAVReportMap.plist
DAVReportMap.plist \
CASLogoutRequestMap.plist
ifeq ($(saml2_config), yes)
SOGo_HEADER_FILES += SOGoSAML2Session.h SOGoSAML2Exceptions.h

View File

@ -51,6 +51,8 @@
+ (SOGoCASSession *) CASSessionWithIdentifier: (NSString *) newIdentifier
fromProxy: (BOOL) fromProxy;
+ (void) handleLogoutRequest: (NSString *) logoutRequest;
- (NSString *) identifier;
- (NSString *) ticket;
@ -65,4 +67,13 @@
@end
@interface CASLogoutRequest : NSObject
{
NSString *sessionIndex;
}
- (NSString *) sessionIndex;
@end
#endif /* SOGOCASSESSION_H */

View File

@ -20,6 +20,7 @@
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSBundle.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSURL.h>
@ -35,6 +36,11 @@
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SaxObjC/SaxObjC.h>
#import <SaxObjC/SaxMethodCallHandler.h>
#import <SaxObjC/SaxObjectDecoder.h>
#import <SaxObjC/SaxXMLReaderFactory.h>
#import "NSDictionary+Utilities.h"
#import "NSString+Utilities.h"
#import "SOGoCache.h"
@ -106,6 +112,43 @@
return session;
}
+ (void) handleLogoutRequest: (NSString *) logoutRequest
{
CASLogoutRequest *rq;
SOGoCache *cache;
NSBundle *bundle;
NSDictionary *root;
NSString *mapFile, *sessionIndex;
bundle = [NSBundle bundleForClass: [self class]];
mapFile = [bundle pathForResource: @"CASLogoutRequestMap" ofType: @"plist"];
if (![mapFile length])
{
[self errorWithFormat: @"mapFile not found (CASLogoutRequest.plist)"];
return;
}
id<NSObject,SaxXMLReader> parser = nil;
SaxObjectDecoder *sax = nil;
parser = [[SaxXMLReaderFactory standardXMLReaderFactory]
createXMLReaderForMimeType:@"text/xml"];
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath: mapFile];
[sax autorelease];
[parser setContentHandler:sax];
[parser setErrorHandler:sax];
[parser parseFromSource: logoutRequest];
rq = [sax rootObject];
sessionIndex = [rq sessionIndex];
if ([sessionIndex length])
{
cache = [SOGoCache sharedCache];
[cache removeCASSessionWithTicket: sessionIndex];
}
}
- (id) init
{
if ((self = [super init]))
@ -381,7 +424,12 @@
NSString *serviceURL;
soURL = [[WOApplication application] soURL];
serviceURL = [soURL absoluteString];
/* appending 'index' to /SOGo/so/ so that callbacks made by the CAS server
* are not greeted with a 302 generated by sope. The CAS server doesn't
* follow redirects, and we'd end up losing the LogoutRequests
*/
serviceURL = [NSString stringWithFormat: @"%@index", [soURL absoluteString]];
params = [NSDictionary dictionaryWithObjectsAndKeys:
ticket, @"ticket", serviceURL, @"service",
@ -466,3 +514,28 @@
}
@end
@implementation CASLogoutRequest
- (id) init
{
if ((self = [super init]))
{
sessionIndex = nil;
}
return self;
}
- (void) dealloc
{
[sessionIndex release];
[super dealloc];
}
- (NSString *) sessionIndex
{
return sessionIndex;
}
@end

View File

@ -122,6 +122,8 @@
- (void) setCASPGTId: (NSString *) pgtId
forPGTIOU: (NSString *) pgtIou;
- (void) removeCASSessionWithTicket: (NSString *) ticket;
// SAML2 support
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier;
- (void) setSaml2LoginDumps: (NSDictionary *) dump

View File

@ -648,6 +648,17 @@ static memcached_st *handle = NULL;
forKey: [NSString stringWithFormat: @"cas-pgtiou:%@", pgtIou]];
}
- (void) removeCASSessionWithTicket: (NSString *) ticket
{
NSString *key, *session;
if ((session = [self CASSessionWithTicket: ticket]))
{
key = [NSString stringWithFormat: @"cas-ticket:%@", ticket];
[self removeValueForKey: key];
[self debugWithFormat: @"Removed session: %@", session];
}
}
// SAML2 support
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier
{

View File

@ -272,10 +272,13 @@
{
NSDictionary *redirectKeys;
NSURL *soURL;
NSString *serviceURL;
soURL = [[WOApplication application] soURL];
// appending 'index' to /SOGo/so/. Matches serviceURL sent by _pgtUrlFromURL
serviceURL = [NSString stringWithFormat: @"%@index", [soURL absoluteString]];
redirectKeys = [NSDictionary dictionaryWithObject: [soURL absoluteString]
redirectKeys = [NSDictionary dictionaryWithObject: serviceURL
forKey: @"service"];
return redirectKeys;
@ -302,7 +305,7 @@
- (id <WOActionResults>) _casDefaultAction
{
WOResponse *response;
NSString *login, *newLocation, *oldLocation, *ticket;
NSString *login, *logoutRequest, *newLocation, *oldLocation, *ticket;
SOGoCASSession *casSession;
SOGoWebAuthenticator *auth;
WOCookie *casCookie, *casLocationCookie;
@ -340,6 +343,18 @@
withName: @"cas-location"];
}
}
else
{
/* anonymous and no ticket, possibly a logout request from CAS
* See: https://wiki.jasig.org/display/CASUM/Single+Sign+Out
*/
logoutRequest = [rq formValueForKey: @"logoutRequest"];
if ([logoutRequest length])
{
[SOGoCASSession handleLogoutRequest: logoutRequest];
return [self responseWithStatus: 200];
}
}
}
else
ticket = nil;