1 karl 1.34 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.26 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.22 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.26 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.29 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.34 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.2 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 kumpf 1.13 //
|
21 mike 1.2 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 // Author: Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
33 //
|
34 david.dillard 1.27 // Modified By: David Dillard, VERITAS Software Corp.
35 // (david.dillard@veritas.com)
|
36 joyce.j 1.28 // Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for PEP-101
|
37 mike 1.2 //
38 //%/////////////////////////////////////////////////////////////////////////////
39
40 #include <Pegasus/Common/Config.h>
41 #include <Pegasus/Common/System.h>
42 #include <Pegasus/Common/FileSystem.h>
|
43 kumpf 1.4 #include <Pegasus/Common/Base64.h>
|
44 chuck 1.15 #include <Pegasus/Common/Exception.h>
|
45 kumpf 1.18 #include <Pegasus/Common/Constants.h>
|
46 mike 1.2 #include "ClientAuthenticator.h"
47
|
48 chip 1.7 #include <ctype.h>
|
49 kumpf 1.6
|
50 kumpf 1.4 //
|
51 kumpf 1.6 // Constants used to parse the authentication challenge header
|
52 kumpf 1.4 //
|
53 kumpf 1.6 #define CHAR_BLANK ' '
54
55 #define CHAR_QUOTE '"'
56
|
57 kumpf 1.4
|
58 mike 1.2 PEGASUS_USING_STD;
59
60 PEGASUS_NAMESPACE_BEGIN
61
|
62 kumpf 1.4 /**
63 The constant represeting the authentication challenge header.
64 */
65 static const String WWW_AUTHENTICATE = "WWW-Authenticate";
66
67 /**
68 Constant representing the Basic authentication header.
69 */
70 static const String BASIC_AUTH_HEADER = "Authorization: Basic ";
71
72 /**
73 Constant representing the Digest authentication header.
74 */
75 static const String DIGEST_AUTH_HEADER = "Authorization: Digest ";
76
77 /**
78 Constant representing the local authentication header.
79 */
|
80 chip 1.7 static const String LOCAL_AUTH_HEADER =
|
81 kumpf 1.4 "PegasusAuthorization: Local";
82
83 /**
84 Constant representing the local privileged authentication header.
85 */
|
86 chip 1.7 static const String LOCALPRIVILEGED_AUTH_HEADER =
|
87 kumpf 1.4 "PegasusAuthorization: LocalPrivileged";
88
89
90
|
91 kumpf 1.21 ClientAuthenticator::ClientAuthenticator()
|
92 mike 1.2 {
|
93 kumpf 1.24 clear();
|
94 mike 1.2 }
95
96 ClientAuthenticator::~ClientAuthenticator()
97 {
98
99 }
100
|
101 kumpf 1.24 void ClientAuthenticator::clear()
|
102 mike 1.2 {
|
103 kumpf 1.30 _requestMessage.reset();
|
104 kumpf 1.24 _userName = String::EMPTY;
105 _password = String::EMPTY;
106 _realm = String::EMPTY;
107 _challengeReceived = false;
108 _authType = ClientAuthenticator::NONE;
|
109 mike 1.2 }
110
|
111 kumpf 1.4 Boolean ClientAuthenticator::checkResponseHeaderForChallenge(
112 Array<HTTPHeader> headers)
|
113 mike 1.2 {
114 //
115 // Search for "WWW-Authenticate" header:
116 //
117 String authHeader;
|
118 kumpf 1.6 String authType;
119 String authRealm;
|
120 mike 1.2
121 if (!HTTPMessage::lookupHeader(
|
122 kumpf 1.4 headers, WWW_AUTHENTICATE, authHeader, false))
|
123 mike 1.2 {
124 return false;
125 }
126
|
127 kumpf 1.10 if (_challengeReceived)
|
128 kumpf 1.6 {
|
129 kumpf 1.23 // Do not respond to a challenge more than once
130 return false;
|
131 kumpf 1.6 }
|
132 kumpf 1.4 else
133 {
|
134 kumpf 1.10 _challengeReceived = true;
135
136 //
137 // Parse the authentication challenge header
138 //
139 if(!_parseAuthHeader(authHeader, authType, authRealm))
140 {
141 throw InvalidAuthHeader();
142 }
143
144 if ( String::equal(authType, "LocalPrivileged"))
145 {
146 _authType = ClientAuthenticator::LOCALPRIVILEGED;
147 }
148 else if ( String::equal(authType, "Local"))
149 {
150 _authType = ClientAuthenticator::LOCAL;
151 }
152 else if ( String::equal(authType, "Basic"))
153 {
154 _authType = ClientAuthenticator::BASIC;
155 kumpf 1.10 }
156 else if ( String::equal(authType, "Digest"))
157 {
158 _authType = ClientAuthenticator::DIGEST;
159 }
160 else
161 {
162 throw InvalidAuthHeader();
163 }
|
164 kumpf 1.4
|
165 kumpf 1.18 if ( _authType == ClientAuthenticator::LOCAL ||
166 _authType == ClientAuthenticator::LOCALPRIVILEGED )
167 {
168 String filePath = authRealm;
169 FileSystem::translateSlashes(filePath);
170
171 // Check whether the directory is a valid pre-defined directory.
172 //
173 Uint32 index = filePath.reverseFind('/');
174
175 if (index != PEG_NOT_FOUND)
176 {
177 String dirName = filePath.subString(0,index);
178
179 if (!String::equal(dirName, String(PEGASUS_LOCAL_AUTH_DIR)))
180 {
|
181 kumpf 1.23 // Refuse to respond to the challenge when the file is
182 // not in the expected directory
183 return false;
|
184 kumpf 1.18 }
185 }
186 }
187
|
188 kumpf 1.10 _realm = authRealm;
|
189 mike 1.2
|
190 kumpf 1.10 return true;
191 }
|
192 mike 1.2 }
193
194
195 String ClientAuthenticator::buildRequestAuthHeader()
196 {
|
197 kumpf 1.6 String challengeResponse = String::EMPTY;
198
|
199 mike 1.2 switch (_authType)
200 {
|
201 kumpf 1.4 case ClientAuthenticator::BASIC:
202
203 if (_challengeReceived)
204 {
|
205 kumpf 1.6 challengeResponse = BASIC_AUTH_HEADER;
206
|
207 kumpf 1.4 //
208 // build the credentials string using the
209 // user name and password
210 //
211 String userPass = _userName;
212
213 userPass.append(":");
214
215 userPass.append(_password);
216
217 //
218 // copy userPass string content to Uint8 array for encoding
219 //
|
220 mike 1.31 Buffer userPassArray;
|
221 kumpf 1.4
222 Uint32 userPassLength = userPass.size();
223
|
224 kumpf 1.14 userPassArray.reserveCapacity( userPassLength );
|
225 kumpf 1.4 userPassArray.clear();
226
227 for( Uint32 i = 0; i < userPassLength; i++ )
228 {
|
229 david.dillard 1.27 userPassArray.append( (char)userPass[i] );
|
230 kumpf 1.4 }
231
232 //
233 // base64 encode the user name and password
234 //
|
235 mike 1.31 Buffer encodedArray;
|
236 kumpf 1.4
237 encodedArray = Base64::encode( userPassArray );
238
|
239 kumpf 1.6 challengeResponse.append(
|
240 kumpf 1.4 String( encodedArray.getData(), encodedArray.size() ) );
241 }
242 break;
243
|
244 chip 1.7 //
|
245 kumpf 1.4 //ATTN: Implement Digest Auth challenge handling code here
|
246 chip 1.7 //
|
247 kumpf 1.9 case ClientAuthenticator::DIGEST:
|
248 chip 1.7 // if (_challengeReceived)
|
249 mike 1.2 // {
|
250 kumpf 1.6 // challengeResponse = DIGEST_AUTH_HEADER;
|
251 chip 1.7 //
|
252 mike 1.2 // }
|
253 kumpf 1.9 break;
|
254 mike 1.2
255 case ClientAuthenticator::LOCALPRIVILEGED:
256
|
257 kumpf 1.6 challengeResponse = LOCALPRIVILEGED_AUTH_HEADER;
258 challengeResponse.append(" \"");
259
|
260 chip 1.7 if (_userName.size())
|
261 kumpf 1.6 {
262 challengeResponse.append(_userName);
263 }
264 else
|
265 mike 1.2 {
|
266 kumpf 1.4 //
|
267 kumpf 1.6 // Get the privileged user name on the system
|
268 kumpf 1.4 //
|
269 kumpf 1.6 challengeResponse.append(System::getPrivilegedUserName());
270 }
271
272 challengeResponse.append(_buildLocalAuthResponse());
273
274 break;
275
276 case ClientAuthenticator::LOCAL:
|
277 mike 1.2
|
278 kumpf 1.6 challengeResponse = LOCAL_AUTH_HEADER;
279 challengeResponse.append(" \"");
|
280 mike 1.2
|
281 chip 1.7 if (_userName.size())
|
282 kumpf 1.6 {
283 challengeResponse.append(_userName);
284 }
285 else
286 {
|
287 mike 1.2 //
|
288 kumpf 1.6 // Get the current login user name
|
289 mike 1.2 //
|
290 kumpf 1.12 challengeResponse.append(System::getEffectiveUserName());
|
291 mike 1.2 }
|
292 kumpf 1.6
293 challengeResponse.append(_buildLocalAuthResponse());
|
294 mike 1.2
295 break;
296
|
297 kumpf 1.9 case ClientAuthenticator::NONE:
|
298 chip 1.7 //
|
299 kumpf 1.4 // Gets here only when no authType was set.
|
300 chip 1.7 //
|
301 kumpf 1.6 challengeResponse.clear();
|
302 mike 1.2 break;
|
303 kumpf 1.9
304 default:
305 PEGASUS_ASSERT(0);
306 break;
|
307 mike 1.2 }
308
|
309 kumpf 1.6 return (challengeResponse);
|
310 mike 1.2 }
311
312 void ClientAuthenticator::setRequestMessage(Message* message)
313 {
|
314 kumpf 1.30 _requestMessage.reset(message);
|
315 mike 1.2 }
316
317 Message* ClientAuthenticator::getRequestMessage()
318 {
|
319 kumpf 1.30 return _requestMessage.get();
320 }
|
321 chip 1.7
|
322 mateus.baur 1.32 void ClientAuthenticator::clearReconnect()
323 {
|
324 kumpf 1.33 _requestMessage.reset();
|
325 mateus.baur 1.32 _realm = String::EMPTY;
326 _challengeReceived = false;
327 }
328
|
329 kumpf 1.30 Message* ClientAuthenticator::releaseRequestMessage()
330 {
331 return _requestMessage.release();
|
332 mike 1.2 }
333
334 void ClientAuthenticator::setUserName(const String& userName)
335 {
336 _userName = userName;
337 }
338
339 String ClientAuthenticator::getUserName()
340 {
341 return (_userName);
342 }
343
344 void ClientAuthenticator::setPassword(const String& password)
345 {
346 _password = password;
347 }
348
349 void ClientAuthenticator::setAuthType(ClientAuthenticator::AuthType type)
350 {
|
351 kumpf 1.5 PEGASUS_ASSERT( (type == ClientAuthenticator::BASIC) ||
352 (type == ClientAuthenticator::DIGEST) ||
353 (type == ClientAuthenticator::LOCAL) ||
|
354 kumpf 1.9 (type == ClientAuthenticator::LOCALPRIVILEGED) ||
355 (type == ClientAuthenticator::NONE) );
|
356 kumpf 1.5
|
357 mike 1.2 _authType = type;
358 }
359
360 ClientAuthenticator::AuthType ClientAuthenticator::getAuthType()
361 {
362 return (_authType);
363 }
364
365 String ClientAuthenticator::_getFileContent(String filePath)
366 {
367 String challenge = String::EMPTY;
|
368 kumpf 1.18
369 FileSystem::translateSlashes(filePath);
|
370 mike 1.2
371 //
|
372 kumpf 1.4 // Check whether the file exists or not
|
373 mike 1.2 //
|
374 kumpf 1.4 if (!FileSystem::exists(filePath))
375 {
376 throw NoSuchFile(filePath);
377 }
|
378 mike 1.2
379 //
380 // Open the challenge file and read the challenge data
381 //
|
382 david 1.19 #if defined(PEGASUS_OS_OS400)
|
383 david 1.25 ifstream ifs(filePath.getCString(), PEGASUS_STD(_CCSID_T(1208)) );
|
384 david 1.19 #else
|
385 david 1.25 ifstream ifs(filePath.getCString());
|
386 david 1.19 #endif
|
387 mike 1.2 if (!ifs)
388 {
|
389 chip 1.7 //ATTN: Log error message
|
390 mike 1.2 return (challenge);
391 }
392
393 String line;
394
395 while (GetLine(ifs, line))
396 {
397 challenge.append(line);
398 }
399
400 ifs.close();
401
402 return (challenge);
403 }
404
|
405 kumpf 1.6 String ClientAuthenticator::_buildLocalAuthResponse()
406 {
407 String authResponse = String::EMPTY;
408
|
409 chip 1.7 if (_challengeReceived)
|
410 kumpf 1.6 {
411 authResponse.append(":");
412
413 //
414 // Append the file path that is in the realm sent by the server
415 //
416 authResponse.append(_realm);
417
418 authResponse.append(":");
419
420 //
|
421 chip 1.7 // Read and append the challenge file content
|
422 kumpf 1.6 //
423 String fileContent = String::EMPTY;
424 try
425 {
426 fileContent = _getFileContent(_realm);
427 }
|
428 kumpf 1.35 catch(NoSuchFile&)
|
429 kumpf 1.6 {
430 //ATTN-NB-04-20000305: Log error message to log file
431 }
432 authResponse.append(fileContent);
433 }
434 authResponse.append("\"");
435
436 return (authResponse);
437 }
438
439 Boolean ClientAuthenticator::_parseAuthHeader(
|
440 chip 1.7 const String authHeader,
441 String& authType,
|
442 kumpf 1.6 String& authRealm)
443 {
|
444 kumpf 1.17 CString header = authHeader.getCString();
445 const char* pAuthHeader = header;
|
446 kumpf 1.6
447 //
448 // Skip the white spaces in the begining of the header
449 //
450 while (*pAuthHeader && isspace(*pAuthHeader))
451 {
452 *pAuthHeader++;
453 }
454
455 //
456 // Get the authentication type
457 //
458 String type = _getSubStringUptoMarker(&pAuthHeader, CHAR_BLANK);
459
460 if (!type.size())
461 {
462 return false;
463 }
464
465 //
466 // Ignore the start quote
467 kumpf 1.6 //
468 _getSubStringUptoMarker(&pAuthHeader, CHAR_QUOTE);
469
470
471 //
472 // Get the realm ending with a quote
473 //
474 String realm = _getSubStringUptoMarker(&pAuthHeader, CHAR_QUOTE);
475
476 if (!realm.size())
477 {
478 return false;
479 }
480
481 authType = type;
482
483 authRealm = realm;
484
485 return true;
486 }
487
488 kumpf 1.6
489 String ClientAuthenticator::_getSubStringUptoMarker(
|
490 chip 1.7 const char** line,
|
491 kumpf 1.6 char marker)
492 {
493 String result = String::EMPTY;
494
495 //
496 // Look for the marker
497 //
|
498 kumpf 1.8 const char *pos = strchr(*line, marker);
|
499 kumpf 1.6
500 if (pos)
501 {
502 if (*line != NULL)
503 {
504 Uint32 length = pos - *line;
505
506 result.assign(*line, length);
507 }
508
509 while (*pos == marker)
510 {
511 ++pos;
512 }
513
514 *line = pos;
515 }
516 else
517 {
|
518 kumpf 1.16 result.assign(*line);
|
519 kumpf 1.6
520 *line += strlen(*line);
521 }
522
523 return result;
524 }
|
525 mike 1.2
526 PEGASUS_NAMESPACE_END
|