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