openwisp / openwisp/openwisp-controller

[bug] Changing org shared_secret prevents devices from re-registering after losing stored credentials

Open
#1,396 12 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
773
Forks
315
Avg merge
2d 16h
Merged PRs (30d)
14

Description

Describe the bug

Changing an organization's shared_secret does not affect already-registered devices (they have UUID+KEY stored locally). However, if a device subsequently loses its stored UUID+KEY (factory reset, reflash, manual config clear), it becomes permanently unable to re-register.

The agent computes key = md5(mac_address + "+" + shared_secret) using the new secret; the server looks up by key and doesn't find it (the stored key used the old secret); it falls back to creating a new device, which fails on unique_together constraints for (mac_address, organization).

There is no fallback matching by (mac_address, organization) when key lookup fails, and no mechanism to update existing device keys when shared_secret changes.

Root cause

  1. Deterministic keygenerate_key(): md5("{}+{}".format(mac_address, shared_secret)). Changing shared_secret produces a different key for the same mac address.

  2. Key set once at creationsave(): only generates key if self.key is empty; never updates it later.

  3. Lookup by key onlyDeviceRegisterView.post(): Device.objects.get(key=key) on line 402. If key doesn't match, falls to init_object() (line 421) which creates a new device — which then fails on unique_together.

  4. Unique constraintsunique_together = (mac_address, organization), (hardware_id, organization), plus _validate_unique_name() for (name, organization).

  5. Agent erases shared_secretopenwisp.agent: computes key ~line 195, then post-registration (~lines 294-298) stores UUID+KEY and clears shared_secret. On restarts, if UUID+KEY already exist, registration is skipped (~line 308).

  6. Default settings: CONSISTENT_REGISTRATION=True, REGISTRATION_SELF_CREATION=True, DEVICE_NAME_UNIQUE=True, HARDWARE_ID_ENABLED=False.

Steps To Reproduce

  1. Register a device normally (e.g. mac_address=AA:BB:CC:DD:EE:FF, org shared_secret="old_secret"). Server stores key = md5("AA:BB:CC:DD:EE:FF+old_secret").
  2. Change the org's shared_secret to "new_secret" in the admin interface (Organization → Config Settings).
  3. On the device, clear the stored UUID and KEY and restore shared_secret:
    uci set openwisp.http.uuid=""
    uci set openwisp.http.key=""
    uci set openwisp.http.shared_secret="new_secret"
    uci commit openwisp
    /etc/init.d/openwisp restart
    
    This simulates a device that lost its credentials (e.g. after reflash) while using the current org shared_secret.
  4. The agent boots and attempts registration:
    • Computes key = md5("AA:BB:CC:DD:EE:FF+new_secret") — different from the stored key.
    • Sends POST to /controller/register/ with the new key.
    • Server does Device.objects.get(key=...)DoesNotExist.
    • Server tries to create a new device with same mac_address, name, and organization.
    • Fails with Device with this Name and Organization already exists. or config device with this Mac address and Organization already exists.

Expected behavior

One of:

  1. When key lookup fails during re-registration, the server should fall back to matching by (mac_address, organization). If a device with matching mac and org is found, the server should update the existing device's key to the newly computed one and proceed with registration — rather than attempting to create a duplicate and failing.

  2. The server should update all existing device keys in the organization when shared_secret is changed.

  3. At minimum, prevent changing shared_secret in the admin UI when the organization already has registered devices, or show a clear warning about the consequences.

System Information

Applies to base openwisp-controller (no settings overridden: CONSISTENT_REGISTRATION, DEVICE_NAME_UNIQUE, REGISTRATION_SELF_CREATION all at defaults).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with DeviceRegisterView.post() in openwisp_controller/config/controller/views.py, then read generate_key() and save() in openwisp_controller/config/base/device.py and the referenced unique constraints. Reproduce registration after changing shared_secret and clearing credentials; done means an existing device identified by MAC and organization can re-register without a duplicate-device error, with the intended key behavior covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
backend, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.