Add support for CAS LogoutRequests
Fixes #2346 This changes the serviceURL sent by SOGo to the CAS server: /SOGo/so/ -> /SOGo/so/indexpull/12/head
parent
d28482557f
commit
41ed498d65
1
NEWS
1
NEWS
|
@ -20,6 +20,7 @@ Bug fixes
|
||||||
- fixed public access when SOGoTrustProxyAuthentication is used (#2237)
|
- fixed public access when SOGoTrustProxyAuthentication is used (#2237)
|
||||||
- fixed access right issues with import feature (#2294)
|
- fixed access right issues with import feature (#2294)
|
||||||
- fixed IMAP ACL issue when SOGoForceExternalLoginWithEmail is used (#2313)
|
- fixed IMAP ACL issue when SOGoForceExternalLoginWithEmail is used (#2313)
|
||||||
|
- fixed handling of CAS logoutRequest (#2346)
|
||||||
- OpenChange stability fixes
|
- OpenChange stability fixes
|
||||||
|
|
||||||
2.0.5a (2013-04-17)
|
2.0.5a (2013-04-17)
|
||||||
|
|
|
@ -140,7 +140,8 @@ SOGo_OBJC_FILES = \
|
||||||
|
|
||||||
SOGo_RESOURCE_FILES = \
|
SOGo_RESOURCE_FILES = \
|
||||||
SOGoDefaults.plist \
|
SOGoDefaults.plist \
|
||||||
DAVReportMap.plist
|
DAVReportMap.plist \
|
||||||
|
CASLogoutRequestMap.plist
|
||||||
|
|
||||||
ifeq ($(saml2_config), yes)
|
ifeq ($(saml2_config), yes)
|
||||||
SOGo_HEADER_FILES += SOGoSAML2Session.h SOGoSAML2Exceptions.h
|
SOGo_HEADER_FILES += SOGoSAML2Session.h SOGoSAML2Exceptions.h
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
+ (SOGoCASSession *) CASSessionWithIdentifier: (NSString *) newIdentifier
|
+ (SOGoCASSession *) CASSessionWithIdentifier: (NSString *) newIdentifier
|
||||||
fromProxy: (BOOL) fromProxy;
|
fromProxy: (BOOL) fromProxy;
|
||||||
|
|
||||||
|
+ (void) handleLogoutRequest: (NSString *) logoutRequest;
|
||||||
|
|
||||||
- (NSString *) identifier;
|
- (NSString *) identifier;
|
||||||
|
|
||||||
- (NSString *) ticket;
|
- (NSString *) ticket;
|
||||||
|
@ -65,4 +67,13 @@
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface CASLogoutRequest : NSObject
|
||||||
|
{
|
||||||
|
NSString *sessionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) sessionIndex;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
#endif /* SOGOCASSESSION_H */
|
#endif /* SOGOCASSESSION_H */
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/NSBundle.h>
|
||||||
#import <Foundation/NSDictionary.h>
|
#import <Foundation/NSDictionary.h>
|
||||||
#import <Foundation/NSURL.h>
|
#import <Foundation/NSURL.h>
|
||||||
|
|
||||||
|
@ -35,6 +36,11 @@
|
||||||
#import <NGObjWeb/WOResponse.h>
|
#import <NGObjWeb/WOResponse.h>
|
||||||
#import <NGExtensions/NSObject+Logs.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 "NSDictionary+Utilities.h"
|
||||||
#import "NSString+Utilities.h"
|
#import "NSString+Utilities.h"
|
||||||
#import "SOGoCache.h"
|
#import "SOGoCache.h"
|
||||||
|
@ -106,6 +112,43 @@
|
||||||
return session;
|
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
|
- (id) init
|
||||||
{
|
{
|
||||||
if ((self = [super init]))
|
if ((self = [super init]))
|
||||||
|
@ -381,7 +424,12 @@
|
||||||
NSString *serviceURL;
|
NSString *serviceURL;
|
||||||
|
|
||||||
soURL = [[WOApplication application] soURL];
|
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:
|
params = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
ticket, @"ticket", serviceURL, @"service",
|
ticket, @"ticket", serviceURL, @"service",
|
||||||
|
@ -466,3 +514,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CASLogoutRequest
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
if ((self = [super init]))
|
||||||
|
{
|
||||||
|
sessionIndex = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[sessionIndex release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *) sessionIndex
|
||||||
|
{
|
||||||
|
return sessionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
|
@ -122,6 +122,8 @@
|
||||||
- (void) setCASPGTId: (NSString *) pgtId
|
- (void) setCASPGTId: (NSString *) pgtId
|
||||||
forPGTIOU: (NSString *) pgtIou;
|
forPGTIOU: (NSString *) pgtIou;
|
||||||
|
|
||||||
|
- (void) removeCASSessionWithTicket: (NSString *) ticket;
|
||||||
|
|
||||||
// SAML2 support
|
// SAML2 support
|
||||||
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier;
|
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier;
|
||||||
- (void) setSaml2LoginDumps: (NSDictionary *) dump
|
- (void) setSaml2LoginDumps: (NSDictionary *) dump
|
||||||
|
|
|
@ -648,6 +648,17 @@ static memcached_st *handle = NULL;
|
||||||
forKey: [NSString stringWithFormat: @"cas-pgtiou:%@", pgtIou]];
|
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
|
// SAML2 support
|
||||||
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier
|
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier
|
||||||
{
|
{
|
||||||
|
|
|
@ -272,10 +272,13 @@
|
||||||
{
|
{
|
||||||
NSDictionary *redirectKeys;
|
NSDictionary *redirectKeys;
|
||||||
NSURL *soURL;
|
NSURL *soURL;
|
||||||
|
NSString *serviceURL;
|
||||||
|
|
||||||
soURL = [[WOApplication application] soURL];
|
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"];
|
forKey: @"service"];
|
||||||
|
|
||||||
return redirectKeys;
|
return redirectKeys;
|
||||||
|
@ -302,7 +305,7 @@
|
||||||
- (id <WOActionResults>) _casDefaultAction
|
- (id <WOActionResults>) _casDefaultAction
|
||||||
{
|
{
|
||||||
WOResponse *response;
|
WOResponse *response;
|
||||||
NSString *login, *newLocation, *oldLocation, *ticket;
|
NSString *login, *logoutRequest, *newLocation, *oldLocation, *ticket;
|
||||||
SOGoCASSession *casSession;
|
SOGoCASSession *casSession;
|
||||||
SOGoWebAuthenticator *auth;
|
SOGoWebAuthenticator *auth;
|
||||||
WOCookie *casCookie, *casLocationCookie;
|
WOCookie *casCookie, *casLocationCookie;
|
||||||
|
@ -340,6 +343,18 @@
|
||||||
withName: @"cas-location"];
|
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
|
else
|
||||||
ticket = nil;
|
ticket = nil;
|
||||||
|
|
Loading…
Reference in New Issue