Onvif PullPointProxy PullMessages返回错误401未经授权

时间:2019-05-14 11:43:04

标签: c++ onvif

我正在尝试从ONVIF IP摄像机获取运动检测器事件。我可以获取订阅的主题地址,但是当我尝试从中提取消息时,会收到错误消息:

Error 401 fault detected[no subcode]
"HTTP/1.1 401 Unauthorized"
Detail: <!DOCTYPE html>
<html><head><title>Document Error: Unauthorized</title></head>
<body><h2>Access Error: 401 -- Unauthorized</h2>
<p>Authentication Error: Access Denied! Authorization required.</p>
</body>
</html>

我创建了多个代理,例如DeviceProxy,EventsProxy,PullPointProxy,并为每个请求添加了安全标头和时间戳,但只有PullPointProxy无法授权它们。

void COnvifMotionDetectorWorker::AddSecurity(soap* pProxy, const bool& bAddWsse)
{
    if(bAddWsse)
    {
        soap_wsse_add_Security(pProxy);
    }

    if(SOAP_OK != soap_wsse_add_UsernameTokenDigest(pProxy, "Auth", m_sUsername.c_str(), m_sPassword.c_str()))
    {
        m_Logger.LogMessage(
                    NLogger2::ePriorityLevelError,
                    std::string("Error adding username token"),
                    "COnvifMotionDetectorWorker::AddSecurity()",
                    std::string("DeviceId #") + m_sDeviceId);
    }

    if(SOAP_OK != soap_wsse_add_Timestamp(pProxy, "Time", 10))
    {
        m_Logger.LogMessage(
                    NLogger2::ePriorityLevelError,
                    std::string("Error adding timestamp"),
                    "COnvifMotionDetectorWorker::AddSecurity()",
                    std::string("DeviceId #") + m_sDeviceId);
    }
}
void COnvifMotionDetectorWorker::Body()
{
    DeviceBindingProxy  DeviceProxy;
    AddSecurity(&DeviceProxy, true);

    DeviceProxy.soap_endpoint = m_sDeviceUrl.c_str();

    _tds__GetCapabilities deviceCapabilities;
    deviceCapabilities.Category.push_back(tt__CapabilityCategory__All);
    _tds__GetCapabilitiesResponse  deviceCapabilitiesResponse;

    if(SOAP_OK == DeviceProxy.GetCapabilities(&deviceCapabilities, deviceCapabilitiesResponse))
    {
        if(deviceCapabilitiesResponse.Capabilities->Events != nullptr)
        {
            m_Logger.LogMessage(
                        NLogger2::ePriorityLevelInfo,
                        std::string("Device has event capabilities"),
                        "COnvifMotionDetectorWorker::BeforeBody()",
                        std::string("DeviceId #") + m_sDeviceId);

            PullPointSubscriptionBindingProxy EventsProxy(
                        deviceCapabilitiesResponse.Capabilities->Events->XAddr.c_str());
            EventsProxy.soap_endpoint = deviceCapabilitiesResponse.Capabilities->Events->XAddr.c_str();
            AddSecurity(&EventsProxy, true);

            _tev__GetEventProperties gep;
            _tev__GetEventPropertiesResponse gepr;
            if (EventsProxy.GetEventProperties(&gep, gepr) == SOAP_OK)
            {
                PrintOnvifParameter("Event: TopicNamespaceLocation");
                for (size_t i = 0; i < gepr.TopicNamespaceLocation.size(); i++)
                {
                    PrintOnvifParameter("", gepr.TopicNamespaceLocation.at(i).c_str());
                }
                PrintOnvifParameter("Event: fixedTopicSet", gepr.wsnt__FixedTopicSet ? "Yes" : "No");
                PrintOnvifParameter("Event: Topics:");
                if (gepr.wstop__TopicSet != NULL && gepr.wstop__TopicSet->documentation != NULL && gepr.wstop__TopicSet->documentation->__mixed != NULL)
                {
                    PrintOnvifParameter("", gepr.wstop__TopicSet->documentation->__mixed);
                }
                else
                {
                    PrintOnvifParameter("", "None");
                }
                PrintOnvifParameter("Event: MessageContentFilterDialect");
                for (size_t i = 0; i < gepr.MessageContentFilterDialect.size(); i++)
                {
                    PrintOnvifParameter("", gepr.MessageContentFilterDialect.at(i).c_str());
                }
                PrintOnvifParameter("Event: MessageContentSchemaLocation");
                for (size_t i = 0; i < gepr.MessageContentSchemaLocation.size(); i++)
                {
                    PrintOnvifParameter("", gepr.MessageContentSchemaLocation.at(i).c_str());
                }
                PrintOnvifParameter("Event: ProducerPropertiesFilterDialect");
                for (size_t i = 0; i < gepr.ProducerPropertiesFilterDialect.size(); i++)
                {
                    PrintOnvifParameter("", gepr.ProducerPropertiesFilterDialect.at(i).c_str());
                }
                PrintOnvifParameter("Event: wsnt__TopicExpressionDialect");
                for (size_t i = 0; i < gepr.wsnt__TopicExpressionDialect.size(); i++)
                {
                    PrintOnvifParameter("", gepr.wsnt__TopicExpressionDialect.at(i).c_str());
                }
            }
            else
            {
                EventsProxy.soap_stream_fault(std::cerr);
                PrintOnvifParameter("Error getting event profiles");
            }

            PrintOnvifParameter("Event: Creating pull point:");
            AddSecurity(&EventsProxy, true);

            _tev__CreatePullPointSubscription cpps;
            _tev__CreatePullPointSubscriptionResponse cppr;
            std::string termtime = "PT60S";
            cpps.InitialTerminationTime = &termtime;

            if (EventsProxy.CreatePullPointSubscription(&cpps, cppr) == SOAP_OK)
            {
                PrintOnvifParameter("Event: pull point subscription created:");
                PrintOnvifParameter("termination time", std::to_string(cppr.wsnt__TerminationTime));
                PrintOnvifParameter("SubscriptionReference.Address", cppr.SubscriptionReference.Address);

                if (cppr.SubscriptionReference.__anyAttribute != nullptr)
                {
                    PrintOnvifParameter("__anyAttribute", cppr.SubscriptionReference.__anyAttribute);
                }
                PrintOnvifParameter("SubscriptionReference.__size", std::to_string(cppr.SubscriptionReference.__size));
                for (int i = 0; i < cppr.SubscriptionReference.__size; i++)
                {
                    PrintOnvifParameter("__any", cppr.SubscriptionReference.__any[i]);
                }

                if (cppr.SubscriptionReference.Metadata != nullptr)
                {
                    if (cppr.SubscriptionReference.Metadata->__anyAttribute != nullptr)
                    {
                        PrintOnvifParameter("Metadata->__anyAttribute",
                            cppr.SubscriptionReference.ReferenceParameters->__anyAttribute);
                    }
                    for (int i = 0; i < cppr.SubscriptionReference.Metadata->__size; i++)
                    {
                        PrintOnvifParameter("MetaData__any",
                            cppr.SubscriptionReference.Metadata->__any[i]);
                    }
                }
                if (cppr.SubscriptionReference.ReferenceParameters != nullptr)
                {
                    if (cppr.SubscriptionReference.ReferenceParameters->__anyAttribute != nullptr)
                    {
                        PrintOnvifParameter("ReferenceParameter->__anyAttribute",
                            cppr.SubscriptionReference.ReferenceParameters->__anyAttribute);
                    }
                    PrintOnvifParameter("SubscriptionReference.ReferenceParameters->__size",
                        std::to_string(cppr.SubscriptionReference.ReferenceParameters->__size));
                    for (int i = 0; i < cppr.SubscriptionReference.ReferenceParameters->__size; i++)
                    {
                        PrintOnvifParameter("ReferenceParameter",
                            cppr.SubscriptionReference.ReferenceParameters->__any[i]);
                    }
                }

                // Set up proxy to read from subscription reference
                std::string sSubscriptionAddress = cppr.SubscriptionReference.Address;
                PullPointSubscriptionBindingProxy   PullPointProxy(sSubscriptionAddress.c_str());
                AddSecurity(&PullPointProxy, true);

                while(!m_bExit)
                {
                    _tev__PullMessages  PullMessages;
                    PullMessages.Timeout = "PT10S";
                    PullMessages.MessageLimit = 100;
                    _tev__PullMessagesResponse PullMessagesResponse;

                    int nRetCode = SOAP_OK;
                    if ((nRetCode = PullPointProxy.PullMessages(&PullMessages, PullMessagesResponse)) == SOAP_OK)
                    {
                        for (auto msg : PullMessagesResponse.wsnt__NotificationMessage)
                        {
                            ProcessOnvifMessage(msg->Message.__any);
                        }
                    }
                    else
                    {
                        PullPointProxy.soap_stream_fault(std::cerr);
                        m_Logger.LogMessage(
                                    NLogger2::ePriorityLevelError,
                                    std::string("PullPointProxy.PullMessages() error code is ") + std::to_string(nRetCode),
                                    "COnvifMotionDetectorWorker::Body()",
                                    std::string("DeviceId #") + m_sDeviceId);
                    }

                    // Wait for nothing
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                }
            }
        }
        else
        {
            m_Logger.LogMessage(
                        NLogger2::ePriorityLevelError,
                        std::string("No device events capabilities"),
                        "COnvifMotionDetectorWorker::BeforeBody()",
                        std::string("DeviceId #") + m_sDeviceId);
        }
    }
    else
    {
        m_Logger.LogMessage(
                    NLogger2::ePriorityLevelError,
                    std::string("Error getting device capabilities"),
                    "COnvifMotionDetectorWorker::BeforeBody()",
                    std::string("DeviceId #") + m_sDeviceId);
    }

    // Wait for nothing before ending
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

正在运行的程序的日志为:

PrintOnvifParameter(): Event: TopicNamespaceLocation - 
PrintOnvifParameter():  - http://www.onvif.org/onvif/ver10/topics/topicns.xml
PrintOnvifParameter(): Event: fixedTopicSet - Yes
PrintOnvifParameter(): Event: Topics: - 
PrintOnvifParameter():  - None
PrintOnvifParameter(): Event: MessageContentFilterDialect - 
PrintOnvifParameter():  - http://www.onvif.org/ver10/tev/messageContentFilter/ItemFilter
PrintOnvifParameter(): Event: MessageContentSchemaLocation - 
PrintOnvifParameter():  - http://www.onvif.org/onvif/ver10/schema/onvif.xsd
PrintOnvifParameter(): Event: ProducerPropertiesFilterDialect - 
PrintOnvifParameter(): Event: wsnt__TopicExpressionDialect - 
PrintOnvifParameter():  - http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet
PrintOnvifParameter():  - http://docs.oasis-open.org/wsn/t-1/TopicExpression/Concrete
PrintOnvifParameter(): Event: Creating pull point: - 
PrintOnvifParameter(): Event: pull point subscription created: - 
PrintOnvifParameter(): termination time - 1557833982
PrintOnvifParameter(): SubscriptionReference.Address - http://192.168.1.36/onvif/Events/PullSubManager_2019-05-14T11:38:42Z_1
PrintOnvifParameter(): __anyAttribute - 
PrintOnvifParameter(): SubscriptionReference.__size - 0

请帮助您理解为什么只有PullMessages返回错误以及正确验证需要哪些特定参数?

1 个答案:

答案 0 :(得分:0)

可以向谁考虑...

问题出在WS-Addressing标头中: https://www.w3.org/Submission/ws-addressing/ https://www.genivia.com/doc/wsdd/html/wsa_0.html

我将其添加到我的PullMessage请求中,并得到了摄像头的响应。

代码应为:

// Set up proxy to read from subscription reference
                std::string sSubscriptionAddress = cppr.SubscriptionReference.Address;
                PullPointSubscriptionBindingProxy   PullPointProxy(sSubscriptionAddress.c_str());
                AddSecurity(&PullPointProxy);
                soap_register_plugin(&PullPointProxy, soap_wsa);

                while(!m_bExit)
                {
                    AddSecurity(&PullPointProxy, false);

                    if (SOAP_OK != soap_wsa_request(&PullPointProxy,
                                                    nullptr,
                                                    sSubscriptionAddress.c_str(),
                                                    "http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest") ||
                       (SOAP_OK != soap_wsa_add_ReplyTo(&PullPointProxy,
                                                        "http://www.w3.org/2005/08/addressing/anonymous"))
                       )
                    {
                        PullPointProxy.soap_stream_fault(std::cerr);
                        m_Logger.LogMessage(
                                    NLogger2::ePriorityLevelError,
                                    std::string("soap_wsa_request error"),
                                    "COnvifMotionDetectorWorker::Body()",
                                    std::string("DeviceId #") + m_sDeviceId);
                    }

                    _tev__PullMessages  PullMessages;
                    PullMessages.Timeout = "PT1M";
                    PullMessages.MessageLimit = 1024;
                    _tev__PullMessagesResponse PullMessagesResponse;

                    int nRetCode = SOAP_OK;
                    if ((nRetCode = PullPointProxy.PullMessages(&PullMessages, PullMessagesResponse)) == SOAP_OK)
                    {
                        for (auto msg : PullMessagesResponse.wsnt__NotificationMessage)
                        {
                            ProcessOnvifMessage(msg->Message.__any);
                        }
                    }
                    else
                    {
                        PullPointProxy.soap_stream_fault(std::cerr);
                        m_Logger.LogMessage(
                                    NLogger2::ePriorityLevelError,
                                    std::string("PullPointProxy.PullMessages() error code is ") + std::to_string(nRetCode),
                                    "COnvifMotionDetectorWorker::Body()",
                                    std::string("DeviceId #") + m_sDeviceId);
                    }

                    // Wait for nothing
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                }