onvif / specs

ONVIF Network Interface Specifications
Other
338 stars 90 forks source link

onvif "ter" namespace url empty resulting in ter:NotAuthorized QNAME exception #402

Closed zebity closed 2 months ago

zebity commented 7 months ago

Issue

I have found when you get authentication failure when using camera with ws-security (ws-usernameToken) rather than http/ DIGEST the resulting "ter:NotAuthorized" return in the SOAP:Fault payload is undefined, and so results in invalid QName in generated CXF java code:

java.lang.RuntimeException: Invalid QName in mapping: ter:NotAuthorized
    at org.apache.cxf.helpers.DOMUtils.createQName(DOMUtils.java:461)
    at org.apache.cxf.binding.soap.interceptor.Soap12FaultInInterceptor.unmarshalFault(Soap12FaultInInterceptor.java:119)
    at org.apache.cxf.binding.soap.interceptor.Soap12FaultInInterceptor.handleMessage(Soap12FaultInInterceptor.java:66)
    at org.apache.cxf.binding.soap.interceptor.Soap12FaultInInterceptor.handleMessage(Soap12FaultInInterceptor.java:52)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
    at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:112)
    at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:70)
    at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:35)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:829)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1760)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1626)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1420)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:717)
    at org.apache.cxf.transport.http.HttpClientHTTPConduit.close(HttpClientHTTPConduit.java:112)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:63)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:528)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:439)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:354)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:312)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:140)
    at jdk.proxy2/jdk.proxy2.$Proxy111.GetDeviceInformation(Unknown Source)
    at onvif_relay.relay.invokers.CheckClockSyncAndAccess.checkAccess(CheckClockSyncAndAccess.java:67)
    at com.ericsson.lift.sensoraasagent.services.DiscoveryService.startDeviceCredentialsCheck(DiscoveryService.java:365)
    at com.ericsson.lift.sensoraasagent.services.DiscoveryService.discoverDevices(DiscoveryService.java:149)
    at jdk.internal.reflect.GeneratedMethodAccessor345.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:352)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:713)
    at com.ericsson.lift.sensoraasagent.services.DiscoveryService$$SpringCGLIB$$0.discoverDevices(<generated>)
    at com.ericsson.lift.sensoraasagent.schedulers.ScheduledTasks.executeAgent(ScheduledTasks.java:38)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:96)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:840)

Diagnosis

I believe this is because the "ter" namesspace ONVIF Core - http://www.onvif.org/ver10/error , points to non-existent schema file.

I believe this should have definition of set of valid error such as "NotAuthorized" to avoid the invalid QName exception which will then allow catch of the correct Java SOAPFaultException (currently this doe not get back the valid QName listl

See this Java code snippet from: https://github.com/zebity/onvif-relay/blob/main/onvif-cxf-relay/src/main/java/onvif_relay/relay/invokers/CheckClockSyncAndAccess.java

try {

        authFault = false;

        callo = JsonRequestResponse.create(call);

        Object[] proxy = onvifop.createSEI(callo, ctrl);

        GetDeviceInformationResponse resp = new GetDeviceInformationResponse();
        Holder<String> man = new Holder<>();
        Holder<String> mod = new Holder<>();
        Holder<String> firm = new Holder<>();
        Holder<String> serial = new Holder<>();
        Holder<String> hard = new Holder<>();
        ((Device)proxy[2]).GetDeviceInformation(man, mod, firm, serial, hard);
        resp.setManufacturer(man.value.toString());
        resp.setModel(mod.value.toString());
        resp.setFirmwareVersion(firm.value.toString());
        resp.setSerialNumber(serial.value.toString());
        resp.setHardwareId(hard.value.toString());
        callo.response = resp;
        res = new Object[3];
        res[0] = ctrl.get("security");
        res[1] = callo.ser();
        res[2] = resp;

      } catch (SOAPFaultException sex) {
        Iterator<QName> it = sex.getFault().getFaultSubcodes();
        if (it.hasNext()) {
          QName err = it.next();
        }
        if (sex.getMessage().contains("NotAuthorized")) {
          authFault = true;
          if (! altAuth) {
            altAuth = true;
            ctrl.put("security", "ws-security");
          } else {
            res = new Object[3];
            res[0] = ctrl.get("security");
            res[1] = callo.ser();
            res[2] = sex.getMessage();
            altAuth = false;
          }
        }
      } catch (WebServiceException wex) {
        // Assume digest with wrong password
        res = new Object[3];
        res[0] = ctrl.get("security");
        res[1] = callo.ser();
        res[2] = "Authorization loop detected: Invalid user/password";
      } catch (Exception ex) {
        ex.printStackTrace();
      }

Resolution

The solution is to reinstate "http://www.onvif.org/ver10/error" content in the source tree with correct QName definitions.

Could people better versed in SOAP/ONVIF please provide feedback.

manoj-47 commented 6 months ago

+1

facing the same error

HansBusch commented 4 months ago

Most probable cause for the failure is that the device doesn't include the namespace definition for prefix 'ter'. Some parser need it to correctly map QNames. Would be helpful to see the fault xml instance diagram.

zebity commented 4 months ago

HI @HansBusch ,

could I clarify what you are saying please.

When you say "the device doesn't include the namespace definition for prefix 'ter'", are you indicating the the Service Endpoint Interface (SEI) should:

This would then mean that responsibility for creation of "ter" namespace would then be via the device and not via the published specification.

I can see this would be a way of ensuring that the onvif specification is locked at a per device level, but this would make communications much more complex for the onvif client.

Also could you clarify what you mean by the "fault xml instance diagram".

My understanding is that the potential SOAP faults returned (and hence QNAMEs) are as per "ONVIF ONVIF Core Specification" section "5.8.2.2 Generic faults".

Thank you for review.

HansBusch commented 4 months ago

Please provide the xml response document to see whether it contains the namespace definition for prefix ter.

HansBusch commented 2 months ago

Close as inactive for more than a month