1 karl 1.62 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.42 // 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.27 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.42 // 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.47 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.62 // 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 kumpf 1.18 // 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 mike 1.2 // 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 //
|
21 kumpf 1.18 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 1.2 // 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 kumpf 1.18 // 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 sushma.fernandes 1.60 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
28 mike 1.2 // 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 1.20 // Modified By: Dave Rosckes (rosckes@us.ibm.com)
|
35 kumpf 1.28 // Sushma Fernandes (sushma_fernandes@hp.com)
|
36 h.sterling 1.34 // Heather Sterling, IBM (hsterl@us.ibm.com)
|
37 david.dillard 1.46 // Amit K Arora, IBM (amita@in.ibm.com) for PEP#101
38 // David Dillard, VERITAS Software Corp.
39 // (david.dillard@veritas.com)
|
40 j.alex 1.52 // John Alex, IBM (johnalex@us.ibm.com) - Bug#2290
|
41 mike 1.2 //
42 //%/////////////////////////////////////////////////////////////////////////////
43
|
44 kumpf 1.10 #include <Pegasus/Common/Constants.h>
|
45 mike 1.2 #include <Pegasus/Common/HTTPAcceptor.h>
46 #include <Pegasus/Common/HTTPConnection.h>
47 #include <Pegasus/Common/HTTPMessage.h>
48 #include <Pegasus/Common/XmlWriter.h>
49 #include <Pegasus/Config/ConfigManager.h>
|
50 humberto 1.33 #include <Pegasus/Common/Thread.h>
|
51 mike 1.2 #include "HTTPAuthenticatorDelegator.h"
|
52 humberto 1.33 #include <Pegasus/Common/MessageLoader.h>
|
53 h.sterling 1.43 #include <Pegasus/Common/FileSystem.h>
|
54 kumpf 1.58 #include <Pegasus/Common/LanguageParser.h>
|
55 mday 1.17
|
56 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
57 #include <Pegasus/Common/CIMKerberosSecurityAssociation.h>
58 #endif
|
59 mike 1.2
60 PEGASUS_USING_STD;
61
62 PEGASUS_NAMESPACE_BEGIN
63
|
64 mike 1.56 static const String _HTTP_VERSION_1_0 = "HTTP/1.0";
65
66 static const String _HTTP_METHOD_MPOST = "M-POST";
67 static const String _HTTP_METHOD = "POST";
68
69 static const String _HTTP_HEADER_CIMEXPORT = "CIMExport";
70 static const String _HTTP_HEADER_CONNECTION = "Connection";
71 static const String _HTTP_HEADER_CIMOPERATION = "CIMOperation";
72 static const String _HTTP_HEADER_ACCEPT_LANGUAGE = "Accept-Language";
73 static const String _HTTP_HEADER_CONTENT_LANGUAGE = "Content-Language";
74 static const String _HTTP_HEADER_AUTHORIZATION = "Authorization";
75 static const String _HTTP_HEADER_PEGASUSAUTHORIZATION = "PegasusAuthorization";
76
77 static const String _CONFIG_PARAM_ENABLEAUTHENTICATION = "enableAuthentication";
78
|
79 mike 1.2 HTTPAuthenticatorDelegator::HTTPAuthenticatorDelegator(
80 Uint32 operationMessageQueueId,
|
81 h.sterling 1.43 Uint32 exportMessageQueueId,
82 CIMRepository* repository)
|
83 kumpf 1.14 : Base(PEGASUS_QUEUENAME_HTTPAUTHDELEGATOR,
|
84 kumpf 1.10 MessageQueue::getNextQueueId()),
|
85 mike 1.2 _operationMessageQueueId(operationMessageQueueId),
|
86 h.sterling 1.43 _exportMessageQueueId(exportMessageQueueId),
87 _repository(repository)
|
88 mike 1.2 {
|
89 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
90 "HTTPAuthenticatorDelegator::HTTPAuthenticatorDelegator");
91
|
92 a.arora 1.36 _authenticationManager.reset(new AuthenticationManager());
|
93 kumpf 1.11
94 PEG_METHOD_EXIT();
|
95 mike 1.2 }
96
97 HTTPAuthenticatorDelegator::~HTTPAuthenticatorDelegator()
98 {
|
99 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
100 "HTTPAuthenticatorDelegator::~HTTPAuthenticatorDelegator");
101
102 PEG_METHOD_EXIT();
|
103 mike 1.2 }
104
|
105 kumpf 1.48 void HTTPAuthenticatorDelegator::enqueue(Message* message)
|
106 kumpf 1.24 {
107 handleEnqueue(message);
108 }
109
|
110 mike 1.2 void HTTPAuthenticatorDelegator::_sendResponse(
111 Uint32 queueId,
|
112 mike 1.54 Buffer& message,
|
113 j.alex 1.52 Boolean closeConnect)
|
114 mike 1.2 {
|
115 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
116 "HTTPAuthenticatorDelegator::_sendResponse");
117
|
118 mike 1.2 MessageQueue* queue = MessageQueue::lookup(queueId);
119
120 if (queue)
121 {
122 HTTPMessage* httpMessage = new HTTPMessage(message);
|
123 mday 1.6 httpMessage->dest = queue->getQueueId();
|
124 j.alex 1.52
125 httpMessage->setCloseConnect(closeConnect);
|
126 kumpf 1.24
|
127 mike 1.2 queue->enqueue(httpMessage);
128 }
|
129 kumpf 1.11
130 PEG_METHOD_EXIT();
|
131 mike 1.2 }
132
|
133 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
134 void HTTPAuthenticatorDelegator::_sendSuccess(
135 Uint32 queueId,
|
136 j.alex 1.52 const String& authResponse,
137 Boolean closeConnect)
|
138 gerarda 1.22 {
139 PEG_METHOD_ENTER(TRC_HTTP,
140 "HTTPAuthenticatorDelegator::_sendSuccess");
141
142 //
143 // build OK (200) response message
144 //
145
|
146 mike 1.54 Buffer message;
|
147 gerarda 1.22 XmlWriter::appendOKResponseHeader(message, authResponse);
148
|
149 j.alex 1.52 _sendResponse(queueId, message,closeConnect);
|
150 gerarda 1.22
151 PEG_METHOD_EXIT();
152 }
153 #endif
154
|
155 mike 1.2 void HTTPAuthenticatorDelegator::_sendChallenge(
156 Uint32 queueId,
|
157 j.alex 1.52 const String& authResponse,
158 Boolean closeConnect)
|
159 mike 1.2 {
|
160 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
161 "HTTPAuthenticatorDelegator::_sendChallenge");
162
|
163 mike 1.2 //
164 // build unauthorized (401) response message
165 //
166
|
167 mike 1.54 Buffer message;
|
168 kumpf 1.7 XmlWriter::appendUnauthorizedResponseHeader(message, authResponse);
|
169 mike 1.2
|
170 j.alex 1.52 _sendResponse(queueId, message,closeConnect);
|
171 kumpf 1.11
172 PEG_METHOD_EXIT();
|
173 mike 1.2 }
174
175
|
176 kumpf 1.30 void HTTPAuthenticatorDelegator::_sendHttpError(
|
177 mike 1.2 Uint32 queueId,
|
178 kumpf 1.30 const String& status,
179 const String& cimError,
|
180 j.alex 1.52 const String& pegasusError,
181 Boolean closeConnect)
|
182 mike 1.2 {
|
183 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
|
184 kumpf 1.30 "HTTPAuthenticatorDelegator::_sendHttpError");
|
185 kumpf 1.11
|
186 mike 1.2 //
|
187 kumpf 1.11 // build error response message
|
188 mike 1.2 //
189
|
190 mike 1.54 Buffer message;
|
191 kumpf 1.30 message = XmlWriter::formatHttpErrorRspMessage(
192 status,
193 cimError,
194 pegasusError);
|
195 mike 1.2
|
196 j.alex 1.52 _sendResponse(queueId, message,closeConnect);
|
197 kumpf 1.11
198 PEG_METHOD_EXIT();
|
199 mike 1.2 }
200
|
201 mday 1.5
202 void HTTPAuthenticatorDelegator::handleEnqueue(Message *message)
|
203 mike 1.2 {
|
204 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
205 "HTTPAuthenticatorDelegator::handleEnqueue");
|
206 mike 1.2
|
207 kumpf 1.11 if (!message)
208 {
209 PEG_METHOD_EXIT();
|
210 mike 1.2 return;
|
211 kumpf 1.11 }
|
212 mike 1.2
|
213 kumpf 1.11 // Flag indicating whether the message should be deleted after handling.
214 // This should be set to false by handleHTTPMessage when the message is
215 // passed as is to another queue.
216 Boolean deleteMessage = true;
|
217 mday 1.5
|
218 mike 1.2 if (message->getType() == HTTP_MESSAGE)
219 {
220 handleHTTPMessage((HTTPMessage*)message, deleteMessage);
221 }
222
223 if (deleteMessage)
224 {
|
225 j.alex 1.52 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL3,
226 "Deleting Message in HTTPAuthenticator::handleEnqueue");
227
|
228 mike 1.2 delete message;
229 }
|
230 kumpf 1.11
231 PEG_METHOD_EXIT();
|
232 mday 1.5 }
233
234 void HTTPAuthenticatorDelegator::handleEnqueue()
235 {
|
236 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
237 "HTTPAuthenticatorDelegator::handleEnqueue");
238
|
239 mday 1.5 Message* message = dequeue();
240 if(message)
241 handleEnqueue(message);
|
242 kumpf 1.11
243 PEG_METHOD_EXIT();
|
244 mike 1.2 }
245
246 void HTTPAuthenticatorDelegator::handleHTTPMessage(
247 HTTPMessage* httpMessage,
248 Boolean & deleteMessage)
249 {
|
250 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
251 "HTTPAuthenticatorDelegator::handleHTTPMessage");
252
|
253 mike 1.2 deleteMessage = true;
254
|
255 kumpf 1.13 // ATTN-RK-P3-20020408: This check probably shouldn't be necessary, but
256 // we're getting an empty message when the client closes the connection
257 if (httpMessage->message.size() == 0)
258 {
259 // The message is empty; just drop it
|
260 gerarda 1.23 PEG_METHOD_EXIT();
|
261 kumpf 1.13 return;
262 }
263
|
264 mike 1.2 //
265 // Save queueId:
266 //
267 Uint32 queueId = httpMessage->queueId;
268
269 //
270 // Parse the HTTP message:
271 //
272 String startLine;
273 Array<HTTPHeader> headers;
274 Uint32 contentLength;
|
275 j.alex 1.52 String connectClose;
276 Boolean closeConnect = false;
|
277 mike 1.2
278 httpMessage->parse(startLine, headers, contentLength);
|
279 j.alex 1.52
280 //
281 // Check for Connection: Close
282 //
|
283 mike 1.56 if(HTTPMessage::lookupHeader(
284 headers, _HTTP_HEADER_CONNECTION, connectClose, false))
|
285 j.alex 1.52 {
286 if (String::equalNoCase(connectClose, "Close"))
287 {
288 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL3,
289 "Header in HTTP Message Contains a Connection: Close");
290 closeConnect = true;
291 httpMessage->setCloseConnect(closeConnect);
292 }
293 }
294
|
295 kumpf 1.35 //
|
296 h.sterling 1.34 // Handle authentication:
297 //
298 ConfigManager* configManager = ConfigManager::getInstance();
299 Boolean enableAuthentication = false;
300 Boolean authenticated = false;
301
|
302 david 1.57 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
303 CIMKerberosSecurityAssociation *sa = NULL;
304 // The presence of a Security Association indicates that Kerberos is being used
305 // Reset flag for subsequent calls to indicate that no Authorization
306 // record was sent. If one was sent the flag will be appropriately reset later.
307 // The sa is maintained while the connection is active.
308 sa = httpMessage->authInfo->getSecurityAssociation();
309 if (sa)
310 {
311 sa->setClientSentAuthorization(false);
312 }
313 #endif
314
315
|
316 kumpf 1.65 if (ConfigManager::parseBooleanValue(
317 configManager->getCurrentValue(_CONFIG_PARAM_ENABLEAUTHENTICATION)))
|
318 h.sterling 1.34 {
319 enableAuthentication = true;
|
320 kumpf 1.63 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
|
321 david 1.57 // If we are using Kerberos (sa pointer is set), the client has already authenticated, and the client is NOT attempting to re-authenticate (dermined by an Authorization record being sent), then we want to set the local authenticate flag to true so that the authentication logic is skipped.
322 String authstr = String::EMPTY;
323 if (sa && sa->getClientAuthenticated() &&
324 !HTTPMessage::lookupHeader(headers, "Authorization", authstr, false))
325 {
326 authenticated = true;
327 }
328 if (!sa)
329 {
330 authenticated = httpMessage->authInfo->isAuthenticated();
331 }
332 #else
|
333 h.sterling 1.34 // Client may have already authenticated via SSL.
334 // In this case, no further attempts to authenticate the client are made
335 authenticated = httpMessage->authInfo->isAuthenticated();
|
336 david 1.57 #endif
|
337 kumpf 1.63
338 // Get the user name associated with the certificate (using the
339 // certificate chain, if necessary).
340
341 String certUserName;
|
342 h.sterling 1.34 if (authenticated &&
|
343 denise.eckstein 1.55 (String::equal(httpMessage->authInfo->getAuthType(),
344 AuthenticationInfoRep::AUTH_TYPE_SSL)))
|
345 h.sterling 1.34 {
|
346 kumpf 1.63 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL3, "Client was authenticated via trusted SSL certificate.");
|
347 h.sterling 1.43
|
348 kumpf 1.63 String trustStore = configManager->getCurrentValue("sslTrustStore");
|
349 h.sterling 1.43
|
350 kumpf 1.63 if (FileSystem::isDirectory(ConfigManager::getHomedPath(trustStore)))
351 {
|
352 h.sterling 1.59 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4, "Truststore is a directory, lookup username");
|
353 kumpf 1.63
|
354 h.sterling 1.59 //Get the client certificate chain to determine the correct username mapping.
355 //Starting with the peer certificate, work your way up the chain
356 //towards the root certificate until a match is found in the repository.
357 Array<SSLCertificateInfo*> clientCertificateChain = httpMessage->authInfo->getClientCertificateChain();
358 SSLCertificateInfo* clientCertificate = NULL;
|
359 h.sterling 1.43
|
360 h.sterling 1.59 Tracer::trace(TRC_HTTP, Tracer::LEVEL4, "Client certificate chain length: %d.", clientCertificateChain.size());
361
|
362 sushma.fernandes 1.60 Uint32 loopCount = clientCertificateChain.size() - 1;
363 for (Uint32 i = 0; i <= loopCount ; i++)
|
364 h.sterling 1.59 {
365 clientCertificate = clientCertificateChain[i];
366 if (clientCertificate == NULL)
367 {
|
368 kumpf 1.63 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.BAD_CERTIFICATE",
|
369 h.sterling 1.59 "The certificate used for authentication is not valid.");
|
370 kumpf 1.63 String msg(MessageLoader::getMessage(msgParms));
371 _sendHttpError(
372 queueId,
373 HTTP_STATUS_UNAUTHORIZED,
374 String::EMPTY,
375 msg,
376 closeConnect);
377 PEG_METHOD_EXIT();
378 return;
|
379 h.sterling 1.59 }
380 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4, "Certificate toString " + clientCertificate->toString());
381
382 //get certificate properties
|
383 kumpf 1.63 String issuerName = clientCertificate->getIssuerName();
384 char serialNumber[256];
385 sprintf(serialNumber, "%lu", clientCertificate->getSerialNumber());
|
386 h.sterling 1.59
|
387 sushma.fernandes 1.64 //
388 // The truststore type key property is deprecated. To retain
389 // backward compatibility, add the truststore type property
390 // to the key bindings and set it to cimserver truststore.
391 //
|
392 kumpf 1.63
393 //construct the corresponding PG_SSLCertificate instance
394 Array<CIMKeyBinding> keyBindings;
395 keyBindings.append(CIMKeyBinding("IssuerName", issuerName, CIMKeyBinding::STRING));
396 keyBindings.append(CIMKeyBinding("SerialNumber", serialNumber, CIMKeyBinding::STRING));
|
397 sushma.fernandes 1.64 keyBindings.append(CIMKeyBinding("TruststoreType",
398 PG_SSLCERTIFICATE_TSTYPE_VALUE_SERVER));
|
399 kumpf 1.63
400 CIMObjectPath cimObjectPath("localhost",
401 PEGASUS_NAMESPACENAME_CERTIFICATE,
402 PEGASUS_CLASSNAME_CERTIFICATE,
403 keyBindings);
|
404 h.sterling 1.59
405 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4, "Client Certificate COP: " + cimObjectPath.toString());
|
406 kumpf 1.63
|
407 h.sterling 1.59 CIMInstance cimInstance;
|
408 kumpf 1.63 CIMValue value;
409 Uint32 pos;
410 String userName = String::EMPTY;
411
412 //attempt to get the username registered to the certificate
413 try
414 {
415 cimInstance = _repository->getInstance(PEGASUS_NAMESPACENAME_CERTIFICATE, cimObjectPath);
|
416 h.sterling 1.59
417 pos = cimInstance.findProperty("RegisteredUserName");
|
418 kumpf 1.63
419 if (pos != PEG_NOT_FOUND && !(value = cimInstance.getProperty(pos).getValue()).isNull())
|
420 h.sterling 1.59 {
|
421 kumpf 1.63 value.get(userName);
|
422 h.sterling 1.59
|
423 kumpf 1.63 //
424 // If a user name is specified, our search is complete
425 //
426 if (userName.size())
427 {
428 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL3,
429 "User name for certificate is " + userName);
430 certUserName = userName;
431 break;
432 }
433
434 // No user name is specified; continue up the chain
435 Tracer::trace(TRC_HTTP, Tracer::LEVEL4,
436 "The certificate at level %u has no "
437 "associated username, moving up the chain",
438 i);
439 }
440 else
|
441 h.sterling 1.59 {
|
442 kumpf 1.63 Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::TRACE,
443 "HTTPAuthenticatorDelegator - Bailing, no username is registered to this certificate.");
|
444 h.sterling 1.59 }
|
445 kumpf 1.63 } catch (CIMException& e)
446 {
|
447 h.sterling 1.59 //this certificate did not have a registration associated with it; continue up the chain
448 if (e.getCode() == CIM_ERR_NOT_FOUND)
449 {
450 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4, "No registration for this certificate, try next certificate in chain");
451 continue;
452
453 } else
454 {
|
455 kumpf 1.63 Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::TRACE,
456 "HTTPAuthenticatorDelegator - Bailing, Bailing, the certificate used for authentication is not valid.");
|
457 h.sterling 1.59 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.BAD_CERTIFICATE",
458 "The certificate used for authentication is not valid.");
|
459 kumpf 1.63 String msg(MessageLoader::getMessage(msgParms));
|
460 h.sterling 1.59 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL3, msg);
461 _sendHttpError(
462 queueId,
463 HTTP_STATUS_UNAUTHORIZED,
464 String::EMPTY,
465 msg,
466 closeConnect);
|
467 kumpf 1.63 PEG_METHOD_EXIT();
468 return;
|
469 h.sterling 1.59 }
470
471 } catch (...)
472 {
473 //this scenario can occur if a certificate cached on the server was deleted
474 //openssl would not pick up the deletion but we would pick it up here when we went to look it up
475 //in the repository
|
476 kumpf 1.63 Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::TRACE,
477 "HTTPAuthenticatorDelegator - Bailing, the certificate used for authentication is not valid.");
|
478 h.sterling 1.59 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.BAD_CERTIFICATE",
479 "The certificate used for authentication is not valid.");
|
480 kumpf 1.63 String msg(MessageLoader::getMessage(msgParms));
|
481 h.sterling 1.59 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL3, msg);
482 _sendHttpError(
483 queueId,
484 HTTP_STATUS_UNAUTHORIZED,
485 String::EMPTY,
486 msg,
487 closeConnect);
|
488 kumpf 1.63 PEG_METHOD_EXIT();
489 return;
|
490 h.sterling 1.59 }
491 } //end for clientcertificatechain
492 } //end sslTrustStore directory
493 else
|
494 kumpf 1.63 {
495 //trustStore is a single CA file, lookup username
496 //user was already verified as a valid system user during server startup
497 certUserName =
498 configManager->getCurrentValue("sslTrustStoreUserName");
499 }
500
501 //
502 // Validate user information
503 //
504
505 if (!_authenticationManager->validateUserForHttpAuth(certUserName))
506 {
507 MessageLoaderParms msgParms(
508 "Pegasus.Server.HTTPAuthenticatorDelegator."
509 "BAD_CERTIFICATE_USERNAME",
510 "The username registered to this certificate is not a "
511 "valid user.");
512 _sendHttpError(
513 queueId,
514 HTTP_STATUS_UNAUTHORIZED,
515 kumpf 1.63 String::EMPTY,
516 MessageLoader::getMessage(msgParms),
517 closeConnect);
518 PEG_METHOD_EXIT();
519 return;
520 }
|
521 h.sterling 1.44
|
522 kumpf 1.63 httpMessage->authInfo->setAuthenticatedUser(certUserName);
|
523 h.sterling 1.43
|
524 kumpf 1.63 PEG_TRACE_STRING(
525 TRC_HTTP,
526 Tracer::LEVEL3,
527 "User name for certificate is " + certUserName);
528 Logger::put(
529 Logger::STANDARD_LOG,
530 System::CIMSERVER,
531 Logger::TRACE,
532 "HTTPAuthenticatorDelegator - The trusted client certificate "
533 "is registered to $0.",
534 certUserName);
535 }
536 } //end enableAuthentication
|
537 h.sterling 1.43
|
538 kumpf 1.63 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4, "Exited authentication loop");
|
539 h.sterling 1.43
|
540 h.sterling 1.34
|
541 humberto 1.33 // l10n start
|
542 kumpf 1.61 AcceptLanguageList acceptLanguages;
543 ContentLanguageList contentLanguages;
|
544 humberto 1.33 try
545 {
546 // Get and validate the Accept-Language header, if set
547 String acceptLanguageHeader;
548 if (HTTPMessage::lookupHeader(
549 headers,
|
550 mike 1.56 _HTTP_HEADER_ACCEPT_LANGUAGE,
|
551 humberto 1.33 acceptLanguageHeader,
552 false) == true)
553 {
|
554 kumpf 1.58 acceptLanguages = LanguageParser::parseAcceptLanguageHeader(
555 acceptLanguageHeader);
556 httpMessage->acceptLanguagesDecoded = true;
|
557 humberto 1.33 }
558
559 // Get and validate the Content-Language header, if set
560 String contentLanguageHeader;
561 if (HTTPMessage::lookupHeader(
562 headers,
|
563 mike 1.56 _HTTP_HEADER_CONTENT_LANGUAGE,
|
564 humberto 1.33 contentLanguageHeader,
565 false) == true)
566 {
|
567 kumpf 1.58 contentLanguages = LanguageParser::parseContentLanguageHeader(
568 contentLanguageHeader);
569 httpMessage->contentLanguagesDecoded = true;
|
570 humberto 1.33 }
571 }
572 catch (Exception &e)
573 {
574 Thread::clearLanguages(); // clear any existing languages to force messages to come from the root bundle
575 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.REQUEST_NOT_VALID","request-not-valid");
576 String msg(MessageLoader::getMessage(msgParms));
577
|
578 j.alex 1.52 _sendHttpError(
579 queueId,
580 HTTP_STATUS_BADREQUEST,
581 msg,
582 e.getMessage(),
583 closeConnect);
|
584 humberto 1.33 PEG_METHOD_EXIT();
585 return;
586 }
|
587 kumpf 1.61 Thread::setLanguages(new AcceptLanguageList(acceptLanguages));
|
588 humberto 1.33 httpMessage->acceptLanguages = acceptLanguages;
589 httpMessage->contentLanguages = contentLanguages;
590 // l10n end
591
592
|
593 mike 1.2 //
594 // Parse the request line:
595 //
596 String methodName;
597 String requestUri;
598 String httpVersion;
|
599 kumpf 1.19 HttpMethod httpMethod = HTTP_METHOD__POST;
|
600 mike 1.2
601 HTTPMessage::parseRequestLine(
602 startLine, methodName, requestUri, httpVersion);
603
|
604 kumpf 1.19 //
605 // Set HTTP method for the request
606 //
|
607 mike 1.56 if (methodName == _HTTP_METHOD_MPOST)
|
608 kumpf 1.19 {
609 httpMethod = HTTP_METHOD_M_POST;
610 }
611
|
612 mike 1.56 if (methodName != _HTTP_METHOD_MPOST && methodName != _HTTP_METHOD)
|
613 kumpf 1.11 {
614 // Only POST and M-POST are implemented by this server
|
615 j.alex 1.52 _sendHttpError(
616 queueId,
617 HTTP_STATUS_NOTIMPLEMENTED,
618 String::EMPTY,
619 String::EMPTY,
620 closeConnect);
|
621 kumpf 1.19 }
622 else if ((httpMethod == HTTP_METHOD_M_POST) &&
|
623 mike 1.56 (httpVersion == _HTTP_VERSION_1_0))
|
624 kumpf 1.19 {
625 //
626 // M-POST method is not valid with version 1.0
627 //
|
628 j.alex 1.52 _sendHttpError(
629 queueId,
630 HTTP_STATUS_BADREQUEST,
631 String::EMPTY,
632 String::EMPTY,
633 closeConnect);
|
634 kumpf 1.11 }
635 else
636 {
637 //
638 // Process M-POST and POST messages:
639 //
|
640 mike 1.56
641 PEG_LOGGER_TRACE((
642 Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
643 "HTTPAuthenticatorDelegator - M-POST/POST processing start"));
|
644 mike 1.2
645 httpMessage->message.append('\0');
646
|
647 h.sterling 1.34 if (!authenticated && enableAuthentication)
648 {
|
649 mike 1.2 //
650 // Search for Authorization header:
651 //
652 String authorization = String::EMPTY;
653
|
654 mike 1.56 if ( HTTPMessage::lookupHeader(headers,
655 _HTTP_HEADER_PEGASUSAUTHORIZATION, authorization, false) &&
|
656 kumpf 1.16 enableAuthentication
|
657 mike 1.2 )
658 {
|
659 kumpf 1.28 try
660 {
661 //
662 // Do pegasus/local authentication
663 //
664 authenticated =
665 _authenticationManager->performPegasusAuthentication(
666 authorization,
667 httpMessage->authInfo);
|
668 mike 1.2
|
669 kumpf 1.28 if (!authenticated)
670 {
671 String authChallenge = String::EMPTY;
672 String authResp = String::EMPTY;
|
673 mike 1.2
|
674 kumpf 1.28 authResp = _authenticationManager->getPegasusAuthResponseHeader(
675 authorization,
676 httpMessage->authInfo);
677
678 if (!String::equal(authResp, String::EMPTY))
679 {
|
680 j.alex 1.52 _sendChallenge(queueId, authResp,closeConnect);
|
681 kumpf 1.28 }
682 else
683 {
|
684 humberto 1.33 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.AUTHORIZATION_HEADER_ERROR","Authorization header error");
685 String msg(MessageLoader::getMessage(msgParms));
|
686 j.alex 1.52 _sendHttpError(
687 queueId,
688 HTTP_STATUS_BADREQUEST,
689 String::EMPTY,
690 msg,
691 closeConnect);
|
692 kumpf 1.28 }
|
693 mike 1.2
|
694 kumpf 1.28 PEG_METHOD_EXIT();
695 return;
|
696 mike 1.2 }
|
697 kumpf 1.28 }
|
698 david.dillard 1.41 catch (const CannotOpenFile &)
|
699 kumpf 1.28 {
|
700 j.alex 1.52 _sendHttpError(
701 queueId,
702 HTTP_STATUS_INTERNALSERVERERROR,
703 String::EMPTY,
704 String::EMPTY,
705 closeConnect);
|
706 kumpf 1.11 PEG_METHOD_EXIT();
|
707 mike 1.2 return;
|
708 kumpf 1.28
|
709 mike 1.2 }
710 }
711
|
712 david 1.57
|
713 gerarda 1.31
|
714 mike 1.2 if ( HTTPMessage::lookupHeader(
|
715 mike 1.56 headers, _HTTP_HEADER_AUTHORIZATION, authorization, false) &&
|
716 kumpf 1.16 enableAuthentication
|
717 mike 1.2 )
718 {
719 //
720 // Do http authentication if not authenticated already
721 //
722 if (!authenticated)
723 {
724 authenticated =
725 _authenticationManager->performHttpAuthentication(
726 authorization,
727 httpMessage->authInfo);
728
729 if (!authenticated)
730 {
731 //ATTN: the number of challenges get sent for a
732 // request on a connection can be pre-set.
|
733 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
734 // Kerberos authentication needs access to the AuthenticationInfo
735 // object for this session in order to set up the reference to the
736 // CIMKerberosSecurityAssociation object for this session.
|
737 gerarda 1.23
|
738 gerarda 1.22 String authResp =
739 _authenticationManager->getHttpAuthResponseHeader(httpMessage->authInfo);
740 #else
|
741 mike 1.2 String authResp =
742 _authenticationManager->getHttpAuthResponseHeader();
|
743 gerarda 1.22 #endif
|
744 kumpf 1.8 if (!String::equal(authResp, String::EMPTY))
745 {
|
746 j.alex 1.52 _sendChallenge(queueId, authResp,closeConnect);
|
747 kumpf 1.8 }
748 else
749 {
|
750 humberto 1.33 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.AUTHORIZATION_HEADER_ERROR","Authorization header error");
751 String msg(MessageLoader::getMessage(msgParms));
|
752 j.alex 1.52 _sendHttpError(
753 queueId,
754 HTTP_STATUS_BADREQUEST,
755 String::EMPTY,
756 msg,
757 closeConnect);
|
758 kumpf 1.8 }
|
759 mike 1.2
|
760 kumpf 1.11 PEG_METHOD_EXIT();
|
761 mike 1.2 return;
762 }
|
763 gerarda 1.25 } // first not authenticated check
764 } // "Authorization" header check
|
765 david 1.57 } //end if(!authenticated && enableAuthentication)
|
766 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
|
767 gerarda 1.31 // The pointer to the sa is created in the authenticator so we need to also
768 // assign it here.
769 sa = httpMessage->authInfo->getSecurityAssociation();
770 if (sa)
|
771 gerarda 1.26 {
|
772 gerarda 1.31 Uint32 sendAction = 0; // 0 - continue, 1 = send success, 2 = send response
|
773 gerarda 1.32 // The following is processing to unwrap (decrypt) the request from the
774 // client when using kerberos authentication.
|
775 gerarda 1.31 sa->unwrapRequestMessage(httpMessage->message, contentLength,
776 authenticated, sendAction);
777 if (sendAction) // send success or send response
|
778 gerarda 1.26 {
|
779 gerarda 1.31 if (httpMessage->message.size() == 0)
|
780 gerarda 1.26 {
|
781 humberto 1.33 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.AUTHORIZATION_HEADER_ERROR","Authorization header error");
782 String msg(MessageLoader::getMessage(msgParms));
|
783 j.alex 1.52 _sendHttpError(
784 queueId,
785 HTTP_STATUS_BADREQUEST,
786 String::EMPTY,
787 msg,
788 closeConnect);
|
789 gerarda 1.31 }
|
790 gerarda 1.32 else
|
791 gerarda 1.31 {
|
792 gerarda 1.32 if (sendAction == 1) // Send success
793 {
|
794 j.alex 1.52 _sendSuccess(
795 queueId,
796 String(
797 httpMessage->message.getData(),httpMessage->message.size()),
798 closeConnect);
|
799 gerarda 1.32 }
|
800 gerarda 1.26
|
801 gerarda 1.32 if (sendAction == 2) // Send response
802 {
|
803 j.alex 1.52 _sendResponse(queueId, httpMessage->message,closeConnect);
|
804 gerarda 1.32 }
|
805 gerarda 1.31 }
|
806 gerarda 1.25
807 PEG_METHOD_EXIT();
808 return;
809 }
|
810 gerarda 1.31 }
|
811 gerarda 1.22 #endif
|
812 h.sterling 1.34
|
813 david 1.57
|
814 h.sterling 1.34
|
815 mike 1.2
|
816 kumpf 1.16 if ( authenticated || !enableAuthentication )
|
817 mike 1.2 {
818 //
819 // Search for "CIMOperation" header:
820 //
821 String cimOperation;
822
823 if (HTTPMessage::lookupHeader(
|
824 mike 1.56 headers, _HTTP_HEADER_CIMOPERATION, cimOperation, true))
|
825 mike 1.2 {
|
826 mike 1.56 PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
827 "HTTPAuthenticatorDelegator - CIMOperation: $0 ",cimOperation));
|
828 david 1.21
|
829 mike 1.2 MessageQueue* queue =
830 MessageQueue::lookup(_operationMessageQueueId);
831
832 if (queue)
833 {
|
834 mday 1.6 httpMessage->dest = queue->getQueueId();
835
|
836 kumpf 1.29 try
837 {
838 queue->enqueue(httpMessage);
839 }
|
840 david.dillard 1.41 catch(const bad_alloc &)
|
841 kumpf 1.29 {
842 delete httpMessage;
|
843 j.alex 1.52 _sendHttpError(
844 queueId,
845 HTTP_STATUS_REQUEST_TOO_LARGE,
846 String::EMPTY,
847 String::EMPTY,
848 closeConnect);
|
849 kumpf 1.29 PEG_METHOD_EXIT();
850 deleteMessage = false;
851 return;
852 }
853 deleteMessage = false;
|
854 mike 1.2 }
855 }
856 else if (HTTPMessage::lookupHeader(
|
857 mike 1.56 headers, _HTTP_HEADER_CIMEXPORT, cimOperation, true))
|
858 mike 1.2 {
|
859 david 1.21 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
860 "HTTPAuthenticatorDelegator - CIMExport: $0 ",cimOperation);
861
|
862 mike 1.2 MessageQueue* queue =
863 MessageQueue::lookup(_exportMessageQueueId);
864
865 if (queue)
866 {
|
867 mday 1.6 httpMessage->dest = queue->getQueueId();
868
869 queue->enqueue(httpMessage);
870 deleteMessage = false;
|
871 mike 1.2 }
872 }
873 else
874 {
|
875 kumpf 1.9 // We don't recognize this request message type
876
877 // The Specification for CIM Operations over HTTP reads:
878 //
879 // 3.3.4. CIMOperation
880 //
881 // If a CIM Server receives a CIM Operation request without
882 // this [CIMOperation] header, it MUST NOT process it as if
883 // it were a CIM Operation Request. The status code
884 // returned by the CIM Server in response to such a request
885 // is outside of the scope of this specification.
886 //
887 // 3.3.5. CIMExport
888 //
889 // If a CIM Listener receives a CIM Export request without
890 // this [CIMExport] header, it MUST NOT process it. The
891 // status code returned by the CIM Listener in response to
892 // such a request is outside of the scope of this
893 // specification.
894 //
895 // The author has chosen to send a 400 Bad Request error, but
896 kumpf 1.9 // without the CIMError header since this request must not be
897 // processed as a CIM request.
898
|
899 j.alex 1.52 _sendHttpError(
900 queueId,
901 HTTP_STATUS_BADREQUEST,
902 String::EMPTY,
903 String::EMPTY,
904 closeConnect);
|
905 kumpf 1.11 PEG_METHOD_EXIT();
|
906 mike 1.2 return;
|
907 gerarda 1.25 } // bad request
908 } // authenticated and enableAuthentication check
|
909 mike 1.2 else
|
910 gerarda 1.25 { // client not authenticated; send challenge
|
911 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
912 String authResp =
913 _authenticationManager->getHttpAuthResponseHeader(httpMessage->authInfo);
914 #else
|
915 mike 1.2 String authResp =
916 _authenticationManager->getHttpAuthResponseHeader();
|
917 gerarda 1.22 #endif
|
918 mike 1.2
|
919 kumpf 1.8 if (!String::equal(authResp, String::EMPTY))
920 {
|
921 j.alex 1.52 _sendChallenge(queueId, authResp,closeConnect);
|
922 kumpf 1.8 }
923 else
924 {
|
925 humberto 1.33 MessageLoaderParms msgParms("Pegasus.Server.HTTPAuthenticatorDelegator.AUTHORIZATION_HEADER_ERROR","Authorization header error");
926 String msg(MessageLoader::getMessage(msgParms));
|
927 j.alex 1.52 _sendHttpError(
928 queueId,
929 HTTP_STATUS_BADREQUEST,
930 String::EMPTY,
931 msg,
932 closeConnect);
|
933 kumpf 1.8 }
|
934 mike 1.2 }
|
935 gerarda 1.25 } // M-POST and POST processing
|
936 kumpf 1.11
937 PEG_METHOD_EXIT();
|
938 mike 1.2 }
939
940 PEGASUS_NAMESPACE_END
|