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