1/* SOGoProxyAuthenticator.h - this file is part of SOGo 2 * 3 * Copyright (C) 2009-2013 Inverse inc. 4 * 5 * This file is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2, or (at your option) 8 * any later version. 9 * 10 * This file is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; see the file COPYING. If not, write to 17 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 * Boston, MA 02111-1307, USA. 19 */ 20 21#import <Foundation/NSArray.h> 22#import <Foundation/NSString.h> 23 24#import <NGObjWeb/NSException+HTTP.h> 25#import <NGObjWeb/WOContext.h> 26#import <NGObjWeb/WORequest.h> 27#import <NGObjWeb/WOResponse.h> 28 29#import <NGExtensions/NGBase64Coding.h> 30#import <NGExtensions/NSObject+Logs.h> 31 32#import "SOGoPermissions.h" 33#import "SOGoSystemDefaults.h" 34#import "SOGoUser.h" 35 36#import "SOGoProxyAuthenticator.h" 37 38@implementation SOGoProxyAuthenticator 39 40+ (id) sharedSOGoProxyAuthenticator 41{ 42 static SOGoProxyAuthenticator *auth = nil; 43 44 if (!auth) 45 auth = [self new]; 46 47 return auth; 48} 49 50- (BOOL) checkLogin: (NSString *) _login 51 password: (NSString *) _pwd 52{ 53 return YES; 54} 55 56/* create SOGoUser */ 57 58- (NSString *) checkCredentialsInContext: (WOContext *) context 59{ 60 NSString *remoteUser; 61 62 63 /* If such a header is not provided by the proxy, SOPE will attempt to 64 deduce it from the "Authorization" header. */ 65 remoteUser = [[context request] headerForKey: @"x-webobjects-remote-user"]; 66 67 if ([remoteUser length] == 0 && [[SOGoSystemDefaults sharedSystemDefaults] trustProxyAuthentication]) 68 { 69 remoteUser = @"anonymous"; 70 } 71 72 return remoteUser; 73} 74 75- (WOResponse *) unauthorized: (NSString *) reason 76 inContext: (WOContext *) context 77{ 78 WOResponse *r; 79 80 if (![reason length]) 81 reason = @"Unauthorized"; 82 83 r = [context response]; 84 [r setStatus: 403 /* unauthorized */]; 85 [r setHeader: @"text/plain; charset=utf-8" forKey: @"content-type"]; 86 [r appendContentString: reason]; 87 88 return r; 89} 90 91- (SOGoUser *) userInContext: (WOContext *) context 92{ 93 SOGoUser *user; 94 NSString *login; 95 96 login = [self checkCredentialsInContext: context]; 97 if ([login length]) 98 user = [SOGoUser userWithLogin: login 99 roles: [NSArray arrayWithObject: 100 SoRole_Authenticated]]; 101 else 102 user = nil; 103 104 return user; 105} 106 107#warning the DAV authenticator is pretty similar to this one. We should enable \ 108 the use of the former for Basic auth type through some defaults. 109- (NSString *) passwordInContext: (WOContext *) context 110{ 111 NSString *password, *authType, *authorization, *pair, *pairStart; 112 WORequest *rq; 113 114 password = @""; 115 116 rq = [context request]; 117 authType = [rq headerForKey: @"x-webobjects-auth-type"]; 118 if ([authType isEqualToString: @"Basic"]) 119 { 120 authorization = [rq headerForKey: @"authorization"]; 121 if ([authorization hasPrefix: @"Basic "]) 122 { 123 pair = [[authorization substringFromIndex: 6] 124 stringByDecodingBase64]; 125 pairStart = [NSString stringWithFormat: @"%@:", 126 [self checkCredentialsInContext: context]]; 127 if ([pair hasPrefix: pairStart]) 128 password = [pair substringFromIndex: [pairStart length]]; 129 else 130 [self errorWithFormat: @"the username in the 'authorization'" 131 @" header does not have the expected value"]; 132 } 133 else 134 [self errorWithFormat: 135 @"'authorization' header does not have the expected value"]; 136 } 137 else if (authType) 138 [self errorWithFormat: @"unrecognized authentication type: '%@'", 139 authType]; 140 else 141 [self warnWithFormat: @"no authentication type found, skipped"]; 142 143 return password; 144} 145 146- (NSString *) imapPasswordInContext: (WOContext *) context 147 forURL: (NSURL *) server 148 forceRenew: (BOOL) renew 149{ 150 return (renew ? nil : [self passwordInContext: context]); 151} 152 153- (WOResponse *) preprocessCredentialsInContext: (WOContext *) context 154{ 155 WOResponse *r; 156 157 if ([self userInContext: context]) 158 { 159 [context setObject: [NSArray arrayWithObject: SoRole_Authenticated] 160 forKey: @"SoAuthenticatedRoles"]; 161 r = nil; 162 } 163 else 164 r = [self unauthorized: nil inContext: context]; 165 166 return r; 167} 168 169- (BOOL) renderException: (NSException *) e 170 inContext: (WOContext *) context 171{ 172 BOOL rc; 173 174 if ([e httpStatus] == 401) 175 { 176 [self unauthorized: [e reason] inContext: context]; 177 rc = YES; 178 } 179 else 180 rc = NO; 181 182 return rc; 183} 184 185@end /* SOGoProxyAuthenticator */ 186