1 karl 1.27 //%2003////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.27 // 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 mike 1.2 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
9 kumpf 1.18 // 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 mike 1.2 // 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 kumpf 1.18 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
16 mike 1.2 // 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 kumpf 1.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 mike 1.2 // 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 david 1.20 // Modified By: Dave Rosckes (rosckes@us.ibm.com)
|
29 kumpf 1.28 // Sushma Fernandes (sushma_fernandes@hp.com)
|
30 h.sterling 1.31.2.2 // Heather Sterling, IBM (hsterl@us.ibm.com)
|
31 mike 1.2 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
|
34 kumpf 1.10 #include <Pegasus/Common/Constants.h>
|
35 mike 1.2 #include <Pegasus/Common/HTTPAcceptor.h>
36 #include <Pegasus/Common/HTTPConnection.h>
37 #include <Pegasus/Common/HTTPMessage.h>
38 #include <Pegasus/Common/XmlWriter.h>
39 #include <Pegasus/Config/ConfigManager.h>
40 #include "HTTPAuthenticatorDelegator.h"
|
41 mday 1.17
|
42 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
43 #include <Pegasus/Common/CIMKerberosSecurityAssociation.h>
44 #endif
|
45 mike 1.2
46 PEGASUS_USING_STD;
47
48 PEGASUS_NAMESPACE_BEGIN
49
50
51 HTTPAuthenticatorDelegator::HTTPAuthenticatorDelegator(
52 Uint32 operationMessageQueueId,
53 Uint32 exportMessageQueueId)
|
54 kumpf 1.14 : Base(PEGASUS_QUEUENAME_HTTPAUTHDELEGATOR,
|
55 kumpf 1.10 MessageQueue::getNextQueueId()),
|
56 mike 1.2 _operationMessageQueueId(operationMessageQueueId),
57 _exportMessageQueueId(exportMessageQueueId)
58 {
|
59 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
60 "HTTPAuthenticatorDelegator::HTTPAuthenticatorDelegator");
61
|
62 mike 1.2 _authenticationManager = new AuthenticationManager();
|
63 kumpf 1.11
64 PEG_METHOD_EXIT();
|
65 mike 1.2 }
66
67 HTTPAuthenticatorDelegator::~HTTPAuthenticatorDelegator()
68 {
|
69 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
70 "HTTPAuthenticatorDelegator::~HTTPAuthenticatorDelegator");
71
|
72 mike 1.2 delete _authenticationManager;
73
|
74 kumpf 1.11 PEG_METHOD_EXIT();
|
75 mike 1.2 }
76
|
77 kumpf 1.24 void HTTPAuthenticatorDelegator::enqueue(Message* message) throw(IPCException)
78 {
79 handleEnqueue(message);
80 }
81
|
82 mike 1.2 void HTTPAuthenticatorDelegator::_sendResponse(
83 Uint32 queueId,
84 Array<Sint8>& message)
85 {
|
86 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
87 "HTTPAuthenticatorDelegator::_sendResponse");
88
|
89 mike 1.2 MessageQueue* queue = MessageQueue::lookup(queueId);
90
91 if (queue)
92 {
93 HTTPMessage* httpMessage = new HTTPMessage(message);
|
94 h.sterling 1.31.2.2 httpMessage->dest = queue->getQueueId();
|
95 kumpf 1.24
|
96 mike 1.2 queue->enqueue(httpMessage);
97 }
|
98 kumpf 1.11
99 PEG_METHOD_EXIT();
|
100 mike 1.2 }
101
|
102 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
103 void HTTPAuthenticatorDelegator::_sendSuccess(
104 Uint32 queueId,
105 const String& authResponse)
106 {
107 PEG_METHOD_ENTER(TRC_HTTP,
108 "HTTPAuthenticatorDelegator::_sendSuccess");
109
110 //
111 // build OK (200) response message
112 //
113
114 Array<Sint8> message;
115 XmlWriter::appendOKResponseHeader(message, authResponse);
116
117 _sendResponse(queueId, message);
118
119 PEG_METHOD_EXIT();
120 }
121 #endif
122
|
123 mike 1.2 void HTTPAuthenticatorDelegator::_sendChallenge(
124 Uint32 queueId,
125 const String& authResponse)
126 {
|
127 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
128 "HTTPAuthenticatorDelegator::_sendChallenge");
129
|
130 mike 1.2 //
131 // build unauthorized (401) response message
132 //
133
134 Array<Sint8> message;
|
135 kumpf 1.7 XmlWriter::appendUnauthorizedResponseHeader(message, authResponse);
|
136 mike 1.2
137 _sendResponse(queueId, message);
|
138 kumpf 1.11
139 PEG_METHOD_EXIT();
|
140 mike 1.2 }
141
142
|
143 kumpf 1.30 void HTTPAuthenticatorDelegator::_sendHttpError(
|
144 mike 1.2 Uint32 queueId,
|
145 kumpf 1.30 const String& status,
146 const String& cimError,
147 const String& pegasusError)
|
148 mike 1.2 {
|
149 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
|
150 kumpf 1.30 "HTTPAuthenticatorDelegator::_sendHttpError");
|
151 kumpf 1.11
|
152 mike 1.2 //
|
153 kumpf 1.11 // build error response message
|
154 mike 1.2 //
155
156 Array<Sint8> message;
|
157 kumpf 1.30 message = XmlWriter::formatHttpErrorRspMessage(
158 status,
159 cimError,
160 pegasusError);
|
161 mike 1.2
162 _sendResponse(queueId, message);
|
163 kumpf 1.11
164 PEG_METHOD_EXIT();
|
165 mike 1.2 }
166
|
167 mday 1.5
168 void HTTPAuthenticatorDelegator::handleEnqueue(Message *message)
|
169 mike 1.2 {
|
170 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
171 "HTTPAuthenticatorDelegator::handleEnqueue");
|
172 mike 1.2
|
173 kumpf 1.11 if (!message)
174 {
175 PEG_METHOD_EXIT();
|
176 mike 1.2 return;
|
177 kumpf 1.11 }
|
178 mike 1.2
|
179 kumpf 1.11 // Flag indicating whether the message should be deleted after handling.
180 // This should be set to false by handleHTTPMessage when the message is
181 // passed as is to another queue.
182 Boolean deleteMessage = true;
|
183 mday 1.5
|
184 mike 1.2 if (message->getType() == HTTP_MESSAGE)
185 {
186 handleHTTPMessage((HTTPMessage*)message, deleteMessage);
187 }
188
189 if (deleteMessage)
190 {
191 delete message;
192 }
|
193 kumpf 1.11
194 PEG_METHOD_EXIT();
|
195 mday 1.5 }
196
197 void HTTPAuthenticatorDelegator::handleEnqueue()
198 {
|
199 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
200 "HTTPAuthenticatorDelegator::handleEnqueue");
201
|
202 mday 1.5 Message* message = dequeue();
203 if(message)
204 handleEnqueue(message);
|
205 kumpf 1.11
206 PEG_METHOD_EXIT();
|
207 mike 1.2 }
208
209 void HTTPAuthenticatorDelegator::handleHTTPMessage(
210 HTTPMessage* httpMessage,
211 Boolean & deleteMessage)
212 {
|
213 kumpf 1.11 PEG_METHOD_ENTER(TRC_HTTP,
214 "HTTPAuthenticatorDelegator::handleHTTPMessage");
215
|
216 h.sterling 1.31.2.3 #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION
217 // client may have already authenticated via SSL
|
218 h.sterling 1.31.2.2 Boolean authenticated = httpMessage->authInfo->getAuthStatus();
|
219 h.sterling 1.31.2.3 #else
220 Boolean authenticated = false;
221 #endif
|
222 mike 1.2 deleteMessage = true;
223
|
224 h.sterling 1.31.2.3
|
225 kumpf 1.13 // ATTN-RK-P3-20020408: This check probably shouldn't be necessary, but
226 // we're getting an empty message when the client closes the connection
227 if (httpMessage->message.size() == 0)
228 {
229 // The message is empty; just drop it
|
230 gerarda 1.23 PEG_METHOD_EXIT();
|
231 kumpf 1.13 return;
232 }
233
|
234 mike 1.2 //
235 // get the configured authentication flag
236 //
237 ConfigManager* configManager = ConfigManager::getInstance();
238
|
239 kumpf 1.16 Boolean enableAuthentication = false;
|
240 mike 1.2
241 if (String::equal(
|
242 kumpf 1.16 configManager->getCurrentValue("enableAuthentication"), "true"))
|
243 mike 1.2 {
|
244 kumpf 1.16 enableAuthentication = true;
|
245 mike 1.2 }
246
247 //
248 // Save queueId:
249 //
250 Uint32 queueId = httpMessage->queueId;
251
252 //
253 // Parse the HTTP message:
254 //
255 String startLine;
256 Array<HTTPHeader> headers;
257 Uint32 contentLength;
258
259 httpMessage->parse(startLine, headers, contentLength);
260
261 //
262 // Parse the request line:
263 //
264 String methodName;
265 String requestUri;
266 mike 1.2 String httpVersion;
|
267 kumpf 1.19 HttpMethod httpMethod = HTTP_METHOD__POST;
|
268 mike 1.2
269 HTTPMessage::parseRequestLine(
270 startLine, methodName, requestUri, httpVersion);
271
|
272 kumpf 1.19 //
273 // Set HTTP method for the request
274 //
275 if (methodName == "M-POST")
276 {
277 httpMethod = HTTP_METHOD_M_POST;
278 }
279
|
280 kumpf 1.11 if (methodName != "M-POST" && methodName != "POST")
281 {
282 // Only POST and M-POST are implemented by this server
|
283 kumpf 1.30 _sendHttpError(queueId,
284 HTTP_STATUS_NOTIMPLEMENTED);
|
285 kumpf 1.19 }
286 else if ((httpMethod == HTTP_METHOD_M_POST) &&
287 (httpVersion == "HTTP/1.0"))
288 {
289 //
290 // M-POST method is not valid with version 1.0
291 //
|
292 kumpf 1.30 _sendHttpError(queueId,
293 HTTP_STATUS_BADREQUEST);
|
294 kumpf 1.11 }
295 else
296 {
297 //
298 // Process M-POST and POST messages:
299 //
|
300 h.sterling 1.31.2.2 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
301 "HTTPAuthenticatorDelegator - M-POST/POST processing start");
|
302 mike 1.2
|
303 h.sterling 1.31.2.2 httpMessage->message.append('\0');
|
304 mike 1.2
|
305 h.sterling 1.31.2.3 #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION
|
306 h.sterling 1.31.2.2 if (!authenticated)
307 {
|
308 h.sterling 1.31.2.3 #endif
|
309 mike 1.2 //
310 // Search for Authorization header:
311 //
312 String authorization = String::EMPTY;
313
314 if ( HTTPMessage::lookupHeader(
315 headers, "PegasusAuthorization", authorization, false) &&
|
316 kumpf 1.16 enableAuthentication
|
317 mike 1.2 )
318 {
|
319 kumpf 1.28 try
320 {
321 //
322 // Do pegasus/local authentication
323 //
324 authenticated =
325 _authenticationManager->performPegasusAuthentication(
326 authorization,
327 httpMessage->authInfo);
|
328 mike 1.2
|
329 kumpf 1.28 if (!authenticated)
330 {
331 String authChallenge = String::EMPTY;
332 String authResp = String::EMPTY;
|
333 mike 1.2
|
334 kumpf 1.28 authResp = _authenticationManager->getPegasusAuthResponseHeader(
335 authorization,
336 httpMessage->authInfo);
337
338 if (!String::equal(authResp, String::EMPTY))
339 {
340 _sendChallenge(queueId, authResp);
341 }
342 else
343 {
|
344 kumpf 1.30 _sendHttpError(queueId,
345 HTTP_STATUS_BADREQUEST,
346 String::EMPTY,
347 "Authorization header error");
|
348 kumpf 1.28 }
|
349 mike 1.2
|
350 kumpf 1.28 PEG_METHOD_EXIT();
351 return;
|
352 mike 1.2 }
|
353 kumpf 1.28 }
354 catch (CannotOpenFile &cof)
355 {
|
356 kumpf 1.30 _sendHttpError(queueId,
357 HTTP_STATUS_INTERNALSERVERERROR);
|
358 kumpf 1.11 PEG_METHOD_EXIT();
|
359 mike 1.2 return;
|
360 kumpf 1.28
|
361 mike 1.2 }
362 }
363
|
364 gerarda 1.31 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
|
365 h.sterling 1.31.2.2 // The presence of a Security Association indicates that Kerberos is being used
366 // Reset flag for subsequent calls to indicate that no Authorization
|
367 gerarda 1.31 // record was sent. If one was sent the flag will be appropriately reset later.
|
368 h.sterling 1.31.2.2 // The sa is maintained while the connection is active.
|
369 gerarda 1.31 CIMKerberosSecurityAssociation *sa = httpMessage->authInfo->getSecurityAssociation();
370 if (sa)
371 {
372 sa->setClientSentAuthorization(false);
373 }
|
374 h.sterling 1.31.2.2 #endif
|
375 gerarda 1.31
|
376 mike 1.2 if ( HTTPMessage::lookupHeader(
377 headers, "Authorization", authorization, false) &&
|
378 kumpf 1.16 enableAuthentication
|
379 mike 1.2 )
380 {
381 //
382 // Do http authentication if not authenticated already
383 //
384 if (!authenticated)
385 {
386 authenticated =
387 _authenticationManager->performHttpAuthentication(
388 authorization,
389 httpMessage->authInfo);
390
391 if (!authenticated)
392 {
393 //ATTN: the number of challenges get sent for a
394 // request on a connection can be pre-set.
|
395 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
396 // Kerberos authentication needs access to the AuthenticationInfo
397 // object for this session in order to set up the reference to the
398 // CIMKerberosSecurityAssociation object for this session.
|
399 gerarda 1.23
|
400 gerarda 1.22 String authResp =
401 _authenticationManager->getHttpAuthResponseHeader(httpMessage->authInfo);
402 #else
|
403 mike 1.2 String authResp =
404 _authenticationManager->getHttpAuthResponseHeader();
|
405 gerarda 1.22 #endif
|
406 kumpf 1.8 if (!String::equal(authResp, String::EMPTY))
407 {
408 _sendChallenge(queueId, authResp);
409 }
410 else
411 {
|
412 kumpf 1.30 _sendHttpError(queueId,
413 HTTP_STATUS_BADREQUEST,
414 String::EMPTY,
415 "Authorization header error");
|
416 kumpf 1.8 }
|
417 mike 1.2
|
418 kumpf 1.11 PEG_METHOD_EXIT();
|
419 mike 1.2 return;
420 }
|
421 h.sterling 1.31.2.2 } // first not authenticated check
422 } // "Authorization" header check
|
423 gerarda 1.25
|
424 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
|
425 h.sterling 1.31.2.2 // The pointer to the sa is created in the authenticator so we need to also
426 // assign it here.
427 sa = httpMessage->authInfo->getSecurityAssociation();
428 if (sa)
429 {
430 Uint32 sendAction = 0; // 0 - continue, 1 = send success, 2 = send response
431 // The following is processing to unwrap (decrypt) the request from the
432 // client when using kerberos authentication.
433 sa->unwrapRequestMessage(httpMessage->message, contentLength,
434 authenticated, sendAction);
435 if (sendAction) // send success or send response
436 {
437 if (httpMessage->message.size() == 0)
438 {
439 _sendHttpError(queueId,
440 HTTP_STATUS_BADREQUEST,
441 String::EMPTY,
442 "Authorization header error");
443 }
444 else
445 {
446 h.sterling 1.31.2.2 if (sendAction == 1) // Send success
447 {
448 _sendSuccess(queueId,
449 String(httpMessage->message.getData(), httpMessage->message.size()));
450 }
451
452 if (sendAction == 2) // Send response
453 {
454 _sendResponse(queueId, httpMessage->message);
455 }
456 }
457
458 PEG_METHOD_EXIT();
459 return;
460 }
461 }
|
462 gerarda 1.22 #endif
|
463 mike 1.2
|
464 h.sterling 1.31.2.3 #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION
|
465 h.sterling 1.31.2.2 } //end BIG if(!authenticated)
|
466 h.sterling 1.31.2.3 #endif
|
467 h.sterling 1.31.2.2
|
468 kumpf 1.16 if ( authenticated || !enableAuthentication )
|
469 mike 1.2 {
470 //
471 // Search for "CIMOperation" header:
472 //
473 String cimOperation;
474
475 if (HTTPMessage::lookupHeader(
|
476 kumpf 1.15 headers, "CIMOperation", cimOperation, true))
|
477 mike 1.2 {
|
478 h.sterling 1.31.2.2 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
479 "HTTPAuthenticatorDelegator - CIMOperation: $0 ",cimOperation);
|
480 david 1.21
|
481 mike 1.2 MessageQueue* queue =
482 MessageQueue::lookup(_operationMessageQueueId);
483
484 if (queue)
485 {
|
486 h.sterling 1.31.2.2 httpMessage->dest = queue->getQueueId();
487
488 try
489 {
|
490 kumpf 1.29 queue->enqueue(httpMessage);
|
491 h.sterling 1.31.2.2 }
492 catch(exception & e)
493 {
494 delete httpMessage;
|
495 kumpf 1.30 _sendHttpError(queueId,
496 HTTP_STATUS_REQUEST_TOO_LARGE);
|
497 h.sterling 1.31.2.2 PEG_METHOD_EXIT();
498 deleteMessage = false;
499 return;
500 }
|
501 kumpf 1.29 deleteMessage = false;
|
502 mike 1.2 }
503 }
504 else if (HTTPMessage::lookupHeader(
|
505 kumpf 1.15 headers, "CIMExport", cimOperation, true))
|
506 mike 1.2 {
|
507 h.sterling 1.31.2.2 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
508 "HTTPAuthenticatorDelegator - CIMExport: $0 ",cimOperation);
|
509 david 1.21
|
510 mike 1.2 MessageQueue* queue =
511 MessageQueue::lookup(_exportMessageQueueId);
512
513 if (queue)
514 {
|
515 h.sterling 1.31.2.2 httpMessage->dest = queue->getQueueId();
|
516 mday 1.6
|
517 h.sterling 1.31.2.2 queue->enqueue(httpMessage);
518 deleteMessage = false;
|
519 mike 1.2 }
520 }
521 else
522 {
|
523 kumpf 1.9 // We don't recognize this request message type
524
525 // The Specification for CIM Operations over HTTP reads:
526 //
527 // 3.3.4. CIMOperation
528 //
529 // If a CIM Server receives a CIM Operation request without
530 // this [CIMOperation] header, it MUST NOT process it as if
531 // it were a CIM Operation Request. The status code
532 // returned by the CIM Server in response to such a request
533 // is outside of the scope of this specification.
534 //
535 // 3.3.5. CIMExport
536 //
537 // If a CIM Listener receives a CIM Export request without
538 // this [CIMExport] header, it MUST NOT process it. The
539 // status code returned by the CIM Listener in response to
540 // such a request is outside of the scope of this
541 // specification.
542 //
543 // The author has chosen to send a 400 Bad Request error, but
544 kumpf 1.9 // without the CIMError header since this request must not be
545 // processed as a CIM request.
546
|
547 kumpf 1.30 _sendHttpError(queueId,
548 HTTP_STATUS_BADREQUEST);
|
549 kumpf 1.11 PEG_METHOD_EXIT();
|
550 mike 1.2 return;
|
551 gerarda 1.25 } // bad request
552 } // authenticated and enableAuthentication check
|
553 mike 1.2 else
|
554 gerarda 1.25 { // client not authenticated; send challenge
|
555 gerarda 1.22 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
556 String authResp =
557 _authenticationManager->getHttpAuthResponseHeader(httpMessage->authInfo);
558 #else
|
559 mike 1.2 String authResp =
560 _authenticationManager->getHttpAuthResponseHeader();
|
561 gerarda 1.22 #endif
|
562 mike 1.2
|
563 kumpf 1.8 if (!String::equal(authResp, String::EMPTY))
564 {
565 _sendChallenge(queueId, authResp);
566 }
567 else
568 {
|
569 kumpf 1.30 _sendHttpError(queueId,
570 HTTP_STATUS_BADREQUEST,
571 String::EMPTY,
572 "Authorization header error");
|
573 kumpf 1.8 }
|
574 mike 1.2 }
|
575 gerarda 1.25 } // M-POST and POST processing
|
576 kumpf 1.11
577 PEG_METHOD_EXIT();
|
578 mike 1.2 }
579
580 PEGASUS_NAMESPACE_END
|