lumeohq / onvif-rs

A native Rust ONVIF client library.
MIT License
114 stars 61 forks source link

Add options to use `GetSystemDateAndTime` to fix `Created` field in `UsernameToken` #121

Closed asuper0 closed 7 months ago

asuper0 commented 8 months ago

I found my program can't connect to a camera with error "NotAuthorized", while it was OK some time ago and I did not change my code. Then I try ONVIF Device Manager, it could work.

I finally found that the problem is time difference: camera's time is 20 seconds differ from my pc time. I reset the camera time and the program could work. However, ONVIF Device Manager works well even if I don't change the camera's time.

onvif-time-diff

The picture shows what ONVIF Device Manager do: it use the camera's time, instead of pc time, to create the token.

So, I suggest to add a option that could use a fixed time to create the Created field in UsernameToken.

That could be done by querying with the GetSystemDateAndTime command, and store the difference between camera and PC as Duration. The Duration may be added to the Created field when making the UsernameToken everytime.

SamuelYvon commented 8 months ago

I'm not sure I like the idea; usually cameras and devices should be running at the same time. ONVIF cameras uses NTP to resync and so should your computer. I haven't dug deep into the protocol so it may be fine, but it smells like an attack vector

asuper0 commented 8 months ago

It's possible that time of camera or PC is not correct, depends on the end user.

For example, we have some cameras, configged with NTP. Then the end user use my app to control the cameras, while the time of PC is not correct. The only way to let the app work is force the user to change time of the PC, I think this is not good.

In many use cases, the devices work in LAN, not connect to Internet, and the user don't config NTP. So every device may have different time.

DmitrySamoylov commented 8 months ago

By ONVIF dev guide, the process is following:

Process:

  1. The client obtains the time of the device through GetSystemDateAndTime.
  2. The client compares its time setting to that of the device and synchronizes if necessary. If the difference between the time of the client and the device is too big, the device may refuse the WS-UsernameToken. In this case, the client can synchronize to match the device’s time by using SetSystemDateAndTime or NTP.
  3. ...

It's hard to make it work right without NTP. In that case, the client may set the camera's time with SetSystemDateAndTime. But it may conflict with another client who sets the device time to another value. So the clients need to coordinate, etc. But I guess it's a common problem in networks without NTP.

SamuelYvon commented 8 months ago

So then in that case it's a non-issue; the API code should just be used differently. Do you happen to know what's "too big" of a time difference? Is it specified?

DmitrySamoylov commented 8 months ago

Here they recommend to reject everything with >5min diff:

It is RECOMMENDED that web service producers provide a timestamp “freshness” limitation, and that any UsernameToken with “stale” timestamps be rejected. As a guideline, a value of five minutes can be used as a minimum to detect, and thus reject, replays.

SamuelYvon commented 8 months ago

I still don't believe this is the responsibility of the library to handle. The caller should perform the sync using the library. We could however add a function to handle it all, but I would oppose to it being use automatically.

asuper0 commented 8 months ago

We could however add a function to handle it all, but I would oppose to it being use automatically.

Agreed. The library should give choice to the developer, and the auto-fix-time feature should be disabled by default.

SamuelYvon commented 8 months ago

I can look into adding that. I'll put it on my tab.