void WsmResponseEncoder::_encodeWsInvokeResponse( WsInvokeResponse* response) { SoapResponse* soapResponse = new SoapResponse(response); Buffer body; WsmWriter::appendInvokeOutputElement( body, response->resourceUri, response->className, response->methodName, response->instance, PEGASUS_INVOKE_NS); if (soapResponse->appendBodyContent(body)) { _sendResponse(soapResponse); delete soapResponse; } else { delete soapResponse; _sendUnreportableSuccess(response); } }
void WsmResponseEncoder::_sendUnreportableSuccess(WsmResponse* response) { // DSP0226 R6.2-2: If the mustUnderstand attribute is set to // "true", the service shall comply with the request. If the // response would exceed the maximum size, the service should // return a wsman:EncodingLimit fault. Because a service might // execute the operation prior to knowing the response size, the // service should undo any effects of the operation before // issuing the fault. If the operation cannot be reversed (such // as a destructive wxf:Put or wxf:Delete, or a wxf:Create), the // service shall indicate that the operation succeeded in the // wsman:EncodingLimit fault with the following detail code: // http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/ // UnreportableSuccess WsmFault fault(WsmFault::wsman_EncodingLimit, MessageLoaderParms( "WsmServer.WsmResponseEncoder.UNREPORTABLE_SUCCESS", "Success response could not be encoded within " "requested envelope size limits."), WSMAN_FAULTDETAIL_UNREPORTABLESUCCESS); WsmFaultResponse faultResponse( response->getRelatesTo(), response->getQueueId(), response->getHttpMethod(), response->getHttpCloseConnect(), response->getOmitXMLProcessingInstruction(), fault); SoapResponse soapResponse(&faultResponse); _sendResponse(&soapResponse); }
void WsmResponseEncoder::_encodeWxfGetResponse(WxfGetResponse* response) { SoapResponse soapResponse(response); Buffer body; WsmWriter::appendInstanceElement(body, response->getResourceUri(), response->getInstance(), PEGASUS_INSTANCE_NS, false); if (soapResponse.appendBodyContent(body)) { _sendResponse(&soapResponse); } else { _sendUnreportableSuccess(response); } }
void WsmResponseEncoder::_encodeWxfPutResponse(WxfPutResponse* response) { SoapResponse soapResponse(response); Buffer headers; // DSP0226 R6.5-1: A service receiving a message that contains the // wsman:RequestEPR header block should return a response that contains // a wsman:RequestedEPR header block. This block contains the most recent // EPR of the resource being accessed or a status code if the service // cannot determine or return the EPR. This EPR reflects any identity // changes that may have occurred as a result of the current operation, as // set forth in the following behavior. The header block in the // corresponding response message has the following format: // <wsman:RequestedEPR...> // [ <wsa:EndpointReference> // wsa:EndpointReferenceType // </wsa:EndpointReference> | // <wsman:EPRInvalid/> | // <wsman:EPRUnknown/> ] // </wsman:RequestedEPR> if (response->getRequestedEPR()) { WsmWriter::appendStartTag( headers, WsmNamespaces::WS_MAN, STRLIT("RequestedEPR")); WsmWriter::appendStartTag( headers, WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference")); WsmWriter::appendEPRElement(headers, response->getEPR()); WsmWriter::appendEndTag( headers, WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference")); WsmWriter::appendEndTag( headers, WsmNamespaces::WS_MAN, STRLIT("RequestedEPR")); } if (soapResponse.appendHeader(headers)) { _sendResponse(&soapResponse); } else { _sendUnreportableSuccess(response); } }
void HTTPAuthenticatorDelegator::_sendChallenge( Uint32 queueId, const String& authResponse, Boolean closeConnect) { PEG_METHOD_ENTER(TRC_HTTP, "HTTPAuthenticatorDelegator::_sendChallenge"); // // build unauthorized (401) response message // Buffer message; XmlWriter::appendUnauthorizedResponseHeader(message, authResponse); _sendResponse(queueId, message, false); PEG_METHOD_EXIT(); }
void HTTPAuthenticatorDelegator::_sendSuccess( Uint32 queueId, const String& authResponse, Boolean closeConnect) { PEG_METHOD_ENTER(TRC_HTTP, "HTTPAuthenticatorDelegator::_sendSuccess"); // // build OK (200) response message // Array<Sint8> message; XmlWriter::appendOKResponseHeader(message, authResponse); _sendResponse(queueId, message); PEG_METHOD_EXIT(); }
void WsmResponseEncoder::_encodeWxfCreateResponse(WxfCreateResponse* response) { SoapResponse soapResponse(response); Buffer body; WsmWriter::appendStartTag( body, WsmNamespaces::WS_TRANSFER, STRLIT("ResourceCreated")); WsmWriter::appendEPRElement(body, response->getEPR()); WsmWriter::appendEndTag( body, WsmNamespaces::WS_TRANSFER, STRLIT("ResourceCreated")); if (soapResponse.appendBodyContent(body)) { _sendResponse(&soapResponse); } else { _sendUnreportableSuccess(response); } }
void HTTPAuthenticatorDelegator::_sendHttpError( Uint32 queueId, const String& status, const String& cimError, const String& pegasusError, Boolean closeConnect) { PEG_METHOD_ENTER(TRC_HTTP, "HTTPAuthenticatorDelegator::_sendHttpError"); // // build error response message // Buffer message; message = XmlWriter::formatHttpErrorRspMessage( status, cimError, pegasusError); _sendResponse(queueId, message, false); PEG_METHOD_EXIT(); }
void HTTPAuthenticatorDelegator::handleHTTPMessage( HTTPMessage* httpMessage, Boolean & deleteMessage) { PEG_METHOD_ENTER(TRC_HTTP, "HTTPAuthenticatorDelegator::handleHTTPMessage"); Boolean authenticated = false; deleteMessage = true; // ATTN-RK-P3-20020408: This check probably shouldn't be necessary, but // we're getting an empty message when the client closes the connection if (httpMessage->message.size() == 0) { // The message is empty; just drop it PEG_METHOD_EXIT(); return; } // // get the configured authentication flag // // WMI MAPPER SPECIFIC: AUTHENTICATION ALWAYS ENABLED: Boolean enableAuthentication = true; /* NORMAL METHOD OF LOOKING UP AUTHENTICATION CONFIGURATION: Boolean enableAuthentication = ConfigManager::parseBooleanValue( ConfigManager::getInstance()->getCurrentValue("enableAuthentication")); */ // // Save queueId: // Uint32 queueId = httpMessage->queueId; // // Parse the HTTP message: // String startLine; Array<HTTPHeader> headers; Uint32 contentLength; httpMessage->parse(startLine, headers, contentLength); // // Parse the request line: // String methodName; String requestUri; String httpVersion; HttpMethod httpMethod = HTTP_METHOD__POST; HTTPMessage::parseRequestLine( startLine, methodName, requestUri, httpVersion); // // Set HTTP method for the request // if (methodName == "M-POST") { httpMethod = HTTP_METHOD_M_POST; } if (methodName != "M-POST" && methodName != "POST") { // Only POST and M-POST are implemented by this server _sendHttpError(queueId, HTTP_STATUS_NOTIMPLEMENTED); } else if ((httpMethod == HTTP_METHOD_M_POST) && (httpVersion == "HTTP/1.0")) { // // M-POST method is not valid with version 1.0 // _sendHttpError(queueId, HTTP_STATUS_BADREQUEST); } else { // // Process M-POST and POST messages: // PEG_TRACE_CSTRING( TRC_HTTP, Tracer::LEVEL3, "HTTPAuthenticatorDelegator - M-POST/POST processing start"); // // Search for Authorization header: // String authorization; // // Do not require authentication for indication delivery // String cimExport; if (enableAuthentication && HTTPMessage::lookupHeader( headers, "CIMExport", cimExport, true)) { enableAuthentication = false; } if ( HTTPMessage::lookupHeader( headers, "PegasusAuthorization", authorization, false) && enableAuthentication ) { try { // // Do pegasus/local authentication // authenticated = _authenticationManager->performPegasusAuthentication( authorization, httpMessage->authInfo); if (!authenticated) { String authChallenge; String authResp; authResp = _authenticationManager->getPegasusAuthResponseHeader( authorization, httpMessage->authInfo); if (!String::equal(authResp, String::EMPTY)) { _sendChallenge(queueId, authResp, false); } else { _sendHttpError(queueId, HTTP_STATUS_BADREQUEST, String::EMPTY, "Authorization header error"); } PEG_METHOD_EXIT(); return; } } catch (CannotOpenFile &cof) { _sendHttpError(queueId, HTTP_STATUS_INTERNALSERVERERROR); PEG_METHOD_EXIT(); return; } } if ( HTTPMessage::lookupHeader( headers, "Authorization", authorization, false) && enableAuthentication ) { #ifdef PEGASUS_KERBEROS_AUTHENTICATION // The presence of a Security Association indicates that Kerberos // is being used. CIMKerberosSecurityAssociation *sa = httpMessage->authInfo->getSecurityAssociation(); if (sa) { sa->setClientSentAuthorization(true); } #endif // // Do http authentication if not authenticated already // if (!authenticated) { authenticated = _authenticationManager->performHttpAuthentication( authorization, httpMessage->authInfo); if (!authenticated) { //ATTN: the number of challenges get sent for a // request on a connection can be pre-set. #ifdef PEGASUS_KERBEROS_AUTHENTICATION // Kerberos authentication needs access to the // AuthenticationInfo object for this session in order // to set up the reference to the // CIMKerberosSecurityAssociation object for this session. String authResp = _authenticationManager->getHttpAuthResponseHeader( httpMessage->authInfo); #else String authResp = _authenticationManager->getHttpAuthResponseHeader(); #endif if (!String::equal(authResp, String::EMPTY)) { _sendChallenge(queueId, authResp, false); } else { _sendHttpError(queueId, HTTP_STATUS_BADREQUEST, String::EMPTY, "Authorization header error"); } PEG_METHOD_EXIT(); return; } } // first not authenticated check } // "Authorization" header check #ifdef PEGASUS_KERBEROS_AUTHENTICATION // The presence of a Security Association indicates that Kerberos is // being used. CIMKerberosSecurityAssociation *sa = httpMessage->authInfo->getSecurityAssociation(); // This will process a request with no content. if (sa && authenticated) { if (sa->getServerToken().size()) { // This will handle the scenario where client did not send // data (content) but is authenticated. After the client // receives the success it should will send the request. // For mutual authentication the client may choose not to // send request data until the context is fully established. // Note: if mutual authentication wass not requested by the // client then no server token will be available. if (contentLength == 0) { String authResp = _authenticationManager->getHttpAuthResponseHeader( httpMessage->authInfo); if (!String::equal(authResp, String::EMPTY)) { _sendSuccess(queueId, authResp); } else { _sendHttpError(queueId, HTTP_STATUS_BADREQUEST, String::EMPTY, "Authorization header error"); } PEG_METHOD_EXIT(); return; } } } // This will process a request without an authorization record. if (sa && !authenticated) { // Not authenticated can result from the client not sending an // authorization record due to a previous authentication. In // this scenario the client was previous authenticated but // chose not to send an authorization record. The Security // Association maintains state so a request will not be // processed unless the Security association thinks the client // is authenticated. // This will handle the scenario where the client was // authenticated in the previous request but choose not to // send an authorization record. if (sa->getClientAuthenticated()) { authenticated = true; } } // The following is processing to unwrap (unencrypt) the message // received from the client when using kerberos authentication. // For Kerberos there should always be an "Authorization" record // sent with the request so the authenticated flag in the method // should always be checked to verify that the client is actually // authenticated. If no "Authoriztion" was sent then the client // can't be authenticated. The "Authorization" record was // processed above and if the "Authorization" record was // successfully processed then the client is authenticated. if (sa && authenticated) { Uint32 rc; // return code for the wrap Array<Sint8> final_buffer; final_buffer.clear(); Array<Sint8> header_buffer; header_buffer.clear(); Array<Sint8> inWrappedMessage; inWrappedMessage.clear(); Array<Sint8> outUnwrappedMessage; outUnwrappedMessage.clear(); // The message needs to be parsed in order to distinguish // between the headers and content. The message was parsed // earlier in this method so we can use the contentLength set // during that parse. When parsing the code breaks out of the // loop as soon as it finds the double separator that // terminates the headers so the headers and content can be // easily separated. // Extract the unwrapped headers for (Uint32 i = 0; i < httpMessage->message.size() - contentLength; i++) { header_buffer.append(httpMessage->message[i]); } // Extract the wrapped content for (Uint32 i = httpMessage->message.size() - contentLength; i < httpMessage->message.size(); i++) { inWrappedMessage.append(httpMessage->message[i]); } rc = sa->unwrap_message(inWrappedMessage, outUnwrappedMessage); // ASCII if (rc) { // clear out the outUnwrappedMessage; if unwrapping is required // and it fails we need to send back a bad request. A message // left in an wrapped state will be a severe failue later. // Reason for unwrap failing may be due to a problem with the // credentials or context or some other failure may have // occurred. outUnwrappedMessage.clear(); // build a bad request. We do not want to risk sending back // data that can't be authenticated. final_buffer = XmlWriter::formatHttpErrorRspMessage(HTTP_STATUS_BADREQUEST); //remove the last separater; the authentication record still // needs to be added. final_buffer.remove(final_buffer.size()); // "\n" final_buffer.remove(final_buffer.size()); // "\r" // Build the WWW_Authenticate record with token. String authResp = _authenticationManager->getHttpAuthResponseHeader( httpMessage->authInfo); // error occurred on wrap so the final_buffer needs to be built // differently final_buffer << authResp; // add double separaters to end final_buffer << "\r\n"; final_buffer << "\r\n"; _sendResponse(queueId, final_buffer); PEG_METHOD_EXIT(); return; } // If outUnwrappedMessage does not have any content data this // is a result of no data available. This could be a result // of the client not sending any content data. This is not // unique to Kerberos so this will not be handled here but it // will be handled when the content is processed. Or, the // client did not wrap message...this is okay. If the unwrap // resulted in no data when there should have been data then // this should have been caught above when the unwrap returned // a bad return code if (final_buffer.size() == 0) { // if outUnwrappedMessage is empty that indicates client did // not wrap the message. The original message will be used. if (outUnwrappedMessage.size()) { final_buffer.appendArray(header_buffer); final_buffer.appendArray(outUnwrappedMessage); // add back char that was appended earlier final_buffer.append('\0'); // Note: if additional characters added // in future add back here } } else { // The final buffer should not have any data at this point. // If it does end the server because something bad happened. PEG_TRACE_CSTRING( TRC_HTTP, Tracer::LEVEL2, "HTTPAuthenticatorDelegator - the final buffer should " "not have data"); PEGASUS_ASSERT(0); } // replace the existing httpMessage with the headers and // unwrapped message // If the final buffer has not been set then the original // httpMessage will be used. if (final_buffer.size()) { httpMessage->message.clear(); httpMessage->message = final_buffer; } } // if not kerberos and client not authenticated #endif if ( authenticated || !enableAuthentication ) { // // Search for "CIMOperation" header: // String cimOperation; if (HTTPMessage::lookupHeader( headers, "CIMOperation", cimOperation, true)) { PEG_TRACE(( TRC_HTTP, Tracer::LEVEL3, "HTTPAuthenticatorDelegator - CIMOperation: %s ", (const char*) cimOperation.getCString())); MessageQueue* queue = MessageQueue::lookup(_cimOperationMessageQueueId); if (queue) { httpMessage->dest = queue->getQueueId(); try { queue->enqueue(httpMessage); } catch(exception & e) { delete httpMessage; _sendHttpError(queueId, HTTP_STATUS_REQUEST_TOO_LARGE); PEG_METHOD_EXIT(); deleteMessage = false; return; } deleteMessage = false; } } else if (HTTPMessage::lookupHeader( headers, "CIMExport", cimOperation, true)) { PEG_TRACE(( TRC_HTTP, Tracer::LEVEL3, "HTTPAuthenticatorDelegator - CIMExport: $0 ", (const char*) cimOperation.getCString())); MessageQueue* queue = MessageQueue::lookup(_cimExportMessageQueueId); if (queue) { httpMessage->dest = queue->getQueueId(); queue->enqueue(httpMessage); deleteMessage = false; } } else { // We don't recognize this request message type // The Specification for CIM Operations over HTTP reads: // // 3.3.4. CIMOperation // // If a CIM Server receives a CIM Operation request without // this [CIMOperation] header, it MUST NOT process it as if // it were a CIM Operation Request. The status code // returned by the CIM Server in response to such a request // is outside of the scope of this specification. // // 3.3.5. CIMExport // // If a CIM Listener receives a CIM Export request without // this [CIMExport] header, it MUST NOT process it. The // status code returned by the CIM Listener in response to // such a request is outside of the scope of this // specification. // // The author has chosen to send a 400 Bad Request error, but // without the CIMError header since this request must not be // processed as a CIM request. _sendHttpError(queueId, HTTP_STATUS_BADREQUEST); PEG_METHOD_EXIT(); return; } // bad request } // authenticated and enableAuthentication check else { // client not authenticated; send challenge #ifdef PEGASUS_KERBEROS_AUTHENTICATION String authResp = _authenticationManager->getHttpAuthResponseHeader( httpMessage->authInfo); #else String authResp = _authenticationManager->getHttpAuthResponseHeader(); #endif if (!String::equal(authResp, String::EMPTY)) { _sendChallenge(queueId, authResp, false); } else { _sendHttpError(queueId, HTTP_STATUS_BADREQUEST, String::EMPTY, "Authorization header error"); } } } // M-POST and POST processing PEG_METHOD_EXIT(); }
void WsmResponseEncoder::_encodeSoapFaultResponse(SoapFaultResponse* response) { SoapResponse soapResponse(response); _sendResponse(&soapResponse); }
void WsmResponseEncoder::_encodeWsenReleaseResponse( WsenReleaseResponse* response) { SoapResponse soapResponse(response); _sendResponse(&soapResponse); }
void WsmResponseEncoder::_encodeWxfDeleteResponse(WxfDeleteResponse* response) { SoapResponse soapResponse(response); _sendResponse(&soapResponse); }