HP-RK Changed the MessageQueue::getQueueName() method from virtual to non-virtual...
[tpot/pegasus/.git] / src / Pegasus / Server / HTTPAuthenticatorDelegator.cpp
1 //%/////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001 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 //==============================================================================
23 //
24 // Author:  Nag Boranna,   Hewlett-Packard Company(nagaraja_boranna@hp.com)
25 //
26 // Modified By: 
27 //
28 //%/////////////////////////////////////////////////////////////////////////////
29
30 #include <Pegasus/Common/Constants.h>
31 #include <Pegasus/Common/HTTPAcceptor.h>
32 #include <Pegasus/Common/HTTPConnection.h>
33 #include <Pegasus/Common/HTTPMessage.h>
34 #include <Pegasus/Common/XmlWriter.h>
35 #include <Pegasus/Config/ConfigManager.h>
36 #include "HTTPAuthenticatorDelegator.h"
37
38
39 PEGASUS_USING_STD;
40
41 PEGASUS_NAMESPACE_BEGIN
42
43
44
45 HTTPAuthenticatorDelegator::HTTPAuthenticatorDelegator(
46     Uint32 operationMessageQueueId,
47     Uint32 exportMessageQueueId)
48    : Base(PEGASUS_QUEUENAME_HTTPAUTHDELEGATOR,
49           MessageQueue::getNextQueueId()),
50     _operationMessageQueueId(operationMessageQueueId),
51     _exportMessageQueueId(exportMessageQueueId)
52 {
53     PEG_METHOD_ENTER(TRC_HTTP,
54         "HTTPAuthenticatorDelegator::HTTPAuthenticatorDelegator");
55
56     _authenticationManager = new AuthenticationManager();
57
58     PEG_METHOD_EXIT();
59 }
60
61 HTTPAuthenticatorDelegator::~HTTPAuthenticatorDelegator()
62 {
63     PEG_METHOD_ENTER(TRC_HTTP,
64         "HTTPAuthenticatorDelegator::~HTTPAuthenticatorDelegator");
65
66     delete _authenticationManager;
67
68     PEG_METHOD_EXIT();
69 }
70
71 void HTTPAuthenticatorDelegator::_sendResponse(
72     Uint32 queueId,
73     Array<Sint8>& message)
74 {
75     PEG_METHOD_ENTER(TRC_HTTP,
76         "HTTPAuthenticatorDelegator::_sendResponse");
77
78     MessageQueue* queue = MessageQueue::lookup(queueId);
79
80     if (queue)
81     {
82         HTTPMessage* httpMessage = new HTTPMessage(message);
83         httpMessage->dest = queue->getQueueId();
84         
85         queue->enqueue(httpMessage);
86     }
87
88     PEG_METHOD_EXIT();
89 }
90
91 void HTTPAuthenticatorDelegator::_sendChallenge(
92     Uint32 queueId,
93     const String& authResponse)
94 {
95     PEG_METHOD_ENTER(TRC_HTTP,
96         "HTTPAuthenticatorDelegator::_sendChallenge");
97
98     //
99     // build unauthorized (401) response message
100     //
101
102     Array<Sint8> message;
103     XmlWriter::appendUnauthorizedResponseHeader(message, authResponse);
104
105     _sendResponse(queueId, message);
106
107     PEG_METHOD_EXIT();
108 }
109
110
111 void HTTPAuthenticatorDelegator::_sendError(
112     Uint32 queueId,
113     const String errorMessage)
114 {
115     PEG_METHOD_ENTER(TRC_HTTP,
116         "HTTPAuthenticatorDelegator::_sendError");
117
118     //
119     // build error response message
120     //
121
122     Array<Sint8> message;
123     //
124     //ATTN: Need an ErrorResponseHeader() in XmlWriter
125     //
126     //message = XmlWriter::formatErrorResponseHeader(errorMessage);
127
128     _sendResponse(queueId, message);
129
130     PEG_METHOD_EXIT();
131 }
132
133
134 void HTTPAuthenticatorDelegator::handleEnqueue(Message *message)
135 {
136     PEG_METHOD_ENTER(TRC_HTTP,
137         "HTTPAuthenticatorDelegator::handleEnqueue");
138
139     if (!message)
140     {
141         PEG_METHOD_EXIT();
142         return;
143     }
144
145     // Flag indicating whether the message should be deleted after handling.
146     // This should be set to false by handleHTTPMessage when the message is
147     // passed as is to another queue.
148     Boolean deleteMessage = true;
149    
150     if (message->getType() == HTTP_MESSAGE)
151     {
152         handleHTTPMessage((HTTPMessage*)message, deleteMessage);
153     }
154
155     if (deleteMessage)
156     {
157         delete message;
158     }
159
160     PEG_METHOD_EXIT();
161 }
162
163 void HTTPAuthenticatorDelegator::handleEnqueue()
164 {
165     PEG_METHOD_ENTER(TRC_HTTP,
166         "HTTPAuthenticatorDelegator::handleEnqueue");
167
168     Message* message = dequeue();
169     if(message)
170        handleEnqueue(message);
171
172     PEG_METHOD_EXIT();
173 }
174
175 void HTTPAuthenticatorDelegator::handleHTTPMessage(
176     HTTPMessage* httpMessage,
177     Boolean & deleteMessage)
178 {  
179     PEG_METHOD_ENTER(TRC_HTTP,
180         "HTTPAuthenticatorDelegator::handleHTTPMessage");
181
182     Boolean authenticated = false;
183     deleteMessage = true;
184
185     // ATTN-RK-P3-20020408: This check probably shouldn't be necessary, but
186     // we're getting an empty message when the client closes the connection
187     if (httpMessage->message.size() == 0)
188     {
189         // The message is empty; just drop it
190         return;
191     }
192
193     //
194     // get the configured authentication flag
195     //
196     ConfigManager* configManager = ConfigManager::getInstance();
197
198     Boolean requireAuthentication = false;
199
200     if (String::equal(
201         configManager->getCurrentValue("requireAuthentication"), "true"))
202     {
203         requireAuthentication = true;
204     }
205
206     //
207     // Save queueId:
208     //
209     Uint32 queueId = httpMessage->queueId;
210
211     //
212     // Parse the HTTP message:
213     //
214     String startLine;
215     Array<HTTPHeader> headers;
216     Uint32 contentLength;
217
218     httpMessage->parse(startLine, headers, contentLength);
219     
220     //
221     // Parse the request line:
222     //
223     String methodName;
224     String requestUri;
225     String httpVersion;
226
227     HTTPMessage::parseRequestLine(
228         startLine, methodName, requestUri, httpVersion);
229
230     if (methodName != "M-POST" && methodName != "POST")
231     {
232         // Only POST and M-POST are implemented by this server
233         Array<Sint8> message;
234         message = XmlWriter::formatHttpErrorRspMessage(
235             HTTP_STATUS_NOTIMPLEMENTED);
236         _sendResponse(queueId, message);
237     }
238     else
239     {
240         //
241         // Process M-POST and POST messages:
242         //
243
244         httpMessage->message.append('\0');
245
246         //
247         // Search for Authorization header:
248         //
249         String authorization = String::EMPTY;
250
251         if ( HTTPMessage::lookupHeader(
252              headers, "PegasusAuthorization", authorization, false) &&
253              requireAuthentication
254            )
255         {
256             //
257             // Do pegasus/local authentication
258             //
259             authenticated = 
260                 _authenticationManager->performPegasusAuthentication(
261                     authorization,
262                     httpMessage->authInfo);
263
264             if (!authenticated)
265             {
266                 String authChallenge = String::EMPTY;
267                 String authResp = String::EMPTY;
268
269                 authResp = _authenticationManager->getPegasusAuthResponseHeader(
270                     authorization,
271                     httpMessage->authInfo);
272
273                 if (!String::equal(authResp, String::EMPTY))
274                 {
275                     _sendChallenge(queueId, authResp);
276                 }
277                 else
278                 {
279                     _sendError(queueId, "Invalid Request");
280                 }
281
282                 PEG_METHOD_EXIT();
283                 return;
284             }
285         }
286
287         if ( HTTPMessage::lookupHeader(
288              headers, "Authorization", authorization, false) &&
289              requireAuthentication
290            )
291         {
292             //
293             // Do http authentication if not authenticated already
294             //
295             if (!authenticated)
296             {
297                 authenticated =
298                     _authenticationManager->performHttpAuthentication(
299                         authorization,
300                         httpMessage->authInfo);
301
302                 if (!authenticated)
303                 {
304                     //ATTN: the number of challenges get sent for a 
305                     //      request on a connection can be pre-set.
306
307                     String authResp =
308                         _authenticationManager->getHttpAuthResponseHeader();
309
310                     if (!String::equal(authResp, String::EMPTY))
311                     {
312                         _sendChallenge(queueId, authResp);
313                     }
314                     else
315                     {
316                         _sendError(queueId, "Invalid Request");
317                     }
318
319                     PEG_METHOD_EXIT();
320                     return;
321                 }
322             }
323         }
324
325         if ( authenticated || !requireAuthentication )
326         {
327             //
328             // Search for "CIMOperation" header:
329             //
330             String cimOperation;
331
332             if (HTTPMessage::lookupHeader(
333                 headers, "*CIMOperation", cimOperation, true))
334             {
335                 MessageQueue* queue =
336                     MessageQueue::lookup(_operationMessageQueueId);
337
338                 if (queue)
339                 {
340                    httpMessage->dest = queue->getQueueId();
341                    
342                     queue->enqueue(httpMessage);
343                     deleteMessage = false;
344                 }
345             }
346             else if (HTTPMessage::lookupHeader(
347                 headers, "*CIMExport", cimOperation, true))
348             {
349                 MessageQueue* queue =
350                     MessageQueue::lookup(_exportMessageQueueId);
351
352                 if (queue)
353                 {
354                    httpMessage->dest = queue->getQueueId();
355
356                    queue->enqueue(httpMessage);
357                    deleteMessage = false;
358                 }
359             }
360             else
361             {
362                 // We don't recognize this request message type
363
364                 // The Specification for CIM Operations over HTTP reads:
365                 //
366                 //     3.3.4. CIMOperation
367                 //
368                 //     If a CIM Server receives a CIM Operation request without
369                 //     this [CIMOperation] header, it MUST NOT process it as if
370                 //     it were a CIM Operation Request.  The status code
371                 //     returned by the CIM Server in response to such a request
372                 //     is outside of the scope of this specification.
373                 //
374                 //     3.3.5. CIMExport
375                 //
376                 //     If a CIM Listener receives a CIM Export request without
377                 //     this [CIMExport] header, it MUST NOT process it.  The
378                 //     status code returned by the CIM Listener in response to
379                 //     such a request is outside of the scope of this
380                 //     specification.
381                 //
382                 // The author has chosen to send a 400 Bad Request error, but
383                 // without the CIMError header since this request must not be
384                 // processed as a CIM request.
385
386                 Array<Sint8> message;
387                 message = XmlWriter::formatHttpErrorRspMessage(
388                     HTTP_STATUS_BADREQUEST);
389                 _sendResponse(queueId, message);
390                 PEG_METHOD_EXIT();
391                 return;
392             }
393         }
394         else
395         {
396             String authResp =
397                 _authenticationManager->getHttpAuthResponseHeader();
398
399             if (!String::equal(authResp, String::EMPTY))
400             {
401                 _sendChallenge(queueId, authResp);
402             }
403             else
404             {
405                 _sendError(queueId, "Invalid Request");
406             }
407         }
408     }
409
410     PEG_METHOD_EXIT();
411 }
412
413 PEGASUS_NAMESPACE_END