1 karl 1.1 //%/////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
4 // 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 //
13 // 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 karl 1.1 //==============================================================================
23 //
24 // Author: Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
25 //
26 // Modified By:
27 //
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 #include <Pegasus/Common/Base64.h>
35 #include <Pegasus/Common/Exception.h>
36 #include "ClientAuthenticator.h"
37
38 #include <ctype.h>
39
40 //
41 // Constants used to parse the authentication challenge header
42 //
43 karl 1.1 #define CHAR_BLANK ' '
44
45 #define CHAR_QUOTE '"'
46
47
48 PEGASUS_USING_STD;
49
50 PEGASUS_NAMESPACE_BEGIN
51
52 /**
53 The constant represeting the authentication challenge header.
54 */
55 static const String WWW_AUTHENTICATE = "WWW-Authenticate";
56
57 /**
58 Constant representing the Basic authentication header.
59 */
60 static const String BASIC_AUTH_HEADER = "Authorization: Basic ";
61
62 /**
63 Constant representing the Digest authentication header.
64 karl 1.1 */
65 static const String DIGEST_AUTH_HEADER = "Authorization: Digest ";
66
67 /**
68 Constant representing the local authentication header.
69 */
70 static const String LOCAL_AUTH_HEADER =
71 "PegasusAuthorization: Local";
72
73 /**
74 Constant representing the local privileged authentication header.
75 */
76 static const String LOCALPRIVILEGED_AUTH_HEADER =
77 "PegasusAuthorization: LocalPrivileged";
78
79
80
81 ClientAuthenticator::ClientAuthenticator(): _challengeReceived(false)
82 {
83 clearRequest(true);
84 }
85 karl 1.1
86 ClientAuthenticator::~ClientAuthenticator()
87 {
88
89 }
90
91 void ClientAuthenticator::clearRequest(Boolean closeConnection)
92 {
93 _requestMessage = 0;
94
95 if (closeConnection)
96 {
97 _userName = String::EMPTY;
98 _password = String::EMPTY;
99 _realm = String::EMPTY;
100 }
101 }
102
103 Boolean ClientAuthenticator::checkResponseHeaderForChallenge(
104 Array<HTTPHeader> headers)
105 {
106 karl 1.1 //
107 // Search for "WWW-Authenticate" header:
108 //
109 String authHeader;
110 String authType;
111 String authRealm;
112
113 if (!HTTPMessage::lookupHeader(
114 headers, WWW_AUTHENTICATE, authHeader, false))
115 {
116 return false;
117 }
118
119 if (_challengeReceived)
120 {
121 throw UnauthorizedAccess();
122 }
123 else
124 {
125 _challengeReceived = true;
126
127 karl 1.1 //
128 // Parse the authentication challenge header
129 //
130 if(!_parseAuthHeader(authHeader, authType, authRealm))
131 {
132 throw InvalidAuthHeader();
133 }
134
135 if ( String::equal(authType, "LocalPrivileged"))
136 {
137 _authType = ClientAuthenticator::LOCALPRIVILEGED;
138 }
139 else if ( String::equal(authType, "Local"))
140 {
141 _authType = ClientAuthenticator::LOCAL;
142 }
143 else if ( String::equal(authType, "Basic"))
144 {
145 _authType = ClientAuthenticator::BASIC;
146 }
147 else if ( String::equal(authType, "Digest"))
148 karl 1.1 {
149 _authType = ClientAuthenticator::DIGEST;
150 }
151 else
152 {
153 throw InvalidAuthHeader();
154 }
155
156 _realm = authRealm;
157
158 return true;
159 }
160 }
161
162
163 String ClientAuthenticator::buildRequestAuthHeader()
164 {
165 String challengeResponse = String::EMPTY;
166
167 switch (_authType)
168 {
169 karl 1.1 case ClientAuthenticator::BASIC:
170
171 if (_challengeReceived)
172 {
173 challengeResponse = BASIC_AUTH_HEADER;
174
175 //
176 // build the credentials string using the
177 // user name and password
178 //
179 String userPass = _userName;
180
181 userPass.append(":");
182
183 userPass.append(_password);
184
185 //
186 // copy userPass string content to Uint8 array for encoding
187 //
188 Array <Uint8> userPassArray;
189
190 karl 1.1 Uint32 userPassLength = userPass.size();
191
192 userPassArray.reserveCapacity( userPassLength );
193 userPassArray.clear();
194
195 for( Uint32 i = 0; i < userPassLength; i++ )
196 {
197 userPassArray.append( (Uint8)userPass[i] );
198 }
199
200 //
201 // base64 encode the user name and password
202 //
203 Array <Sint8> encodedArray;
204
205 encodedArray = Base64::encode( userPassArray );
206
207 challengeResponse.append(
208 String( encodedArray.getData(), encodedArray.size() ) );
209 }
210 break;
211 karl 1.1
212 //
213 //ATTN: Implement Digest Auth challenge handling code here
214 //
215 case ClientAuthenticator::DIGEST:
216 // if (_challengeReceived)
217 // {
218 // challengeResponse = DIGEST_AUTH_HEADER;
219 //
220 // }
221 break;
222
223 case ClientAuthenticator::LOCALPRIVILEGED:
224
225 challengeResponse = LOCALPRIVILEGED_AUTH_HEADER;
226 challengeResponse.append(" \"");
227
228 if (_userName.size())
229 {
230 challengeResponse.append(_userName);
231 }
232 karl 1.1 else
233 {
234 //
235 // Get the privileged user name on the system
236 //
237 challengeResponse.append(System::getPrivilegedUserName());
238 }
239
240 challengeResponse.append(_buildLocalAuthResponse());
241
242 break;
243
244 case ClientAuthenticator::LOCAL:
245
246 challengeResponse = LOCAL_AUTH_HEADER;
247 challengeResponse.append(" \"");
248
249 if (_userName.size())
250 {
251 challengeResponse.append(_userName);
252 }
253 karl 1.1 else
254 {
255 //
256 // Get the current login user name
257 //
258 challengeResponse.append(System::getEffectiveUserName());
259 }
260
261 challengeResponse.append(_buildLocalAuthResponse());
262
263 break;
264
265 case ClientAuthenticator::NONE:
266 //
267 // Gets here only when no authType was set.
268 //
269 challengeResponse.clear();
270 break;
271
272 default:
273 PEGASUS_ASSERT(0);
274 karl 1.1 break;
275 }
276
277 return (challengeResponse);
278 }
279
280 void ClientAuthenticator::setRequestMessage(Message* message)
281 {
282 _requestMessage = message;
283 }
284
285
286 Message* ClientAuthenticator::getRequestMessage()
287 {
288 return _requestMessage;
289
290 }
291
292 void ClientAuthenticator::setUserName(const String& userName)
293 {
294 _userName = userName;
295 karl 1.1 }
296
297 String ClientAuthenticator::getUserName()
298 {
299 return (_userName);
300 }
301
302 void ClientAuthenticator::setPassword(const String& password)
303 {
304 _password = password;
305 }
306
307 void ClientAuthenticator::setAuthType(ClientAuthenticator::AuthType type)
308 {
309 PEGASUS_ASSERT( (type == ClientAuthenticator::BASIC) ||
310 (type == ClientAuthenticator::DIGEST) ||
311 (type == ClientAuthenticator::LOCAL) ||
312 (type == ClientAuthenticator::LOCALPRIVILEGED) ||
313 (type == ClientAuthenticator::NONE) );
314
315 _authType = type;
316 karl 1.1 }
317
318 ClientAuthenticator::AuthType ClientAuthenticator::getAuthType()
319 {
320 return (_authType);
321 }
322
323 String ClientAuthenticator::_getFileContent(String filePath)
324 {
325 String challenge = String::EMPTY;
326
327 //
328 // Check whether the file exists or not
329 //
330 if (!FileSystem::exists(filePath))
331 {
332 throw NoSuchFile(filePath);
333 }
334
335 //
336 // Open the challenge file and read the challenge data
337 karl 1.1 //
338 ifstream ifs(filePath.getCString());
339 if (!ifs)
340 {
341 //ATTN: Log error message
342 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 String ClientAuthenticator::_buildLocalAuthResponse()
358 karl 1.1 {
359 String authResponse = String::EMPTY;
360
361 if (_challengeReceived)
362 {
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 // Read and append the challenge file content
374 //
375 String fileContent = String::EMPTY;
376 try
377 {
378 fileContent = _getFileContent(_realm);
379 karl 1.1 }
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 const String authHeader,
393 String& authType,
394 String& authRealm)
395 {
396 CString header = authHeader.getCString();
397 const char* pAuthHeader = header;
398
399 //
400 karl 1.1 // Skip the white spaces in the begining of the header
401 //
402 while (*pAuthHeader && isspace(*pAuthHeader))
403 {
404 *pAuthHeader++;
405 }
406
407 //
408 // Get the authentication type
409 //
410 String type = _getSubStringUptoMarker(&pAuthHeader, CHAR_BLANK);
411
412 if (!type.size())
413 {
414 return false;
415 }
416
417 //
418 // Ignore the start quote
419 //
420 _getSubStringUptoMarker(&pAuthHeader, CHAR_QUOTE);
421 karl 1.1
422
423 //
424 // Get the realm ending with a quote
425 //
426 String realm = _getSubStringUptoMarker(&pAuthHeader, CHAR_QUOTE);
427
428 if (!realm.size())
429 {
430 return false;
431 }
432
433 authType = type;
434
435 authRealm = realm;
436
437 return true;
438 }
439
440
441 String ClientAuthenticator::_getSubStringUptoMarker(
442 karl 1.1 const char** line,
443 char marker)
444 {
445 String result = String::EMPTY;
446
447 //
448 // Look for the marker
449 //
450 const char *pos = strchr(*line, marker);
451
452 if (pos)
453 {
454 if (*line != NULL)
455 {
456 Uint32 length = pos - *line;
457
458 result.assign(*line, length);
459 }
460
461 while (*pos == marker)
462 {
463 karl 1.1 ++pos;
464 }
465
466 *line = pos;
467 }
468 else
469 {
470 result.assign(*line);
471
472 *line += strlen(*line);
473 }
474
475 return result;
476 }
477
478 PEGASUS_NAMESPACE_END
|