Skip to content

Commit a2048b4

Browse files
authored
UniFi - Catch controllers running on UniFi OS that don't have a local user configured (#35060)
1 parent 221b075 commit a2048b4

File tree

5 files changed

+64
-1
lines changed

5 files changed

+64
-1
lines changed

homeassistant/components/unifi/config_flow.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@
3232
LOGGER,
3333
)
3434
from .controller import get_controller
35-
from .errors import AlreadyConfigured, AuthenticationRequired, CannotConnect
35+
from .errors import (
36+
AlreadyConfigured,
37+
AuthenticationRequired,
38+
CannotConnect,
39+
NoLocalUser,
40+
)
3641

3742
DEFAULT_PORT = 8443
3843
DEFAULT_SITE_ID = "default"
@@ -129,6 +134,8 @@ async def async_step_site(self, user_input=None):
129134

130135
for site in self.sites.values():
131136
if desc == site["desc"]:
137+
if "role" not in site:
138+
raise NoLocalUser
132139
self.config[CONF_SITE_ID] = site["name"]
133140
break
134141

@@ -147,6 +154,9 @@ async def async_step_site(self, user_input=None):
147154
except AlreadyConfigured:
148155
return self.async_abort(reason="already_configured")
149156

157+
except NoLocalUser:
158+
return self.async_abort(reason="no_local_user")
159+
150160
if len(self.sites) == 1:
151161
self.desc = next(iter(self.sites.values()))["desc"]
152162
return await self.async_step_site(user_input={})

homeassistant/components/unifi/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,9 @@ class LoginRequired(UnifiException):
2222
"""Component got logged out."""
2323

2424

25+
class NoLocalUser(UnifiException):
26+
"""No local user."""
27+
28+
2529
class UserLevel(UnifiException):
2630
"""User level too low."""

homeassistant/components/unifi/strings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
},
2121
"abort": {
2222
"already_configured": "Controller site is already configured",
23+
"no_local_user": "No local user found, configure a local account on controller and try again",
2324
"user_privilege": "User needs to be administrator"
2425
}
2526
},

homeassistant/components/unifi/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"config": {
33
"abort": {
44
"already_configured": "Controller site is already configured",
5+
"no_local_user": "No local user found, configure a local account on controller and try again",
56
"user_privilege": "User needs to be administrator"
67
},
78
"error": {

tests/components/unifi/test_config_flow.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,53 @@ async def test_flow_fails_site_already_configured(hass, aioclient_mock):
185185
)
186186

187187
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
188+
assert result["reason"] == "already_configured"
189+
190+
191+
async def test_flow_fails_site_has_no_local_user(hass, aioclient_mock):
192+
"""Test config flow."""
193+
entry = MockConfigEntry(
194+
domain=UNIFI_DOMAIN, data={"controller": {"host": "1.2.3.4", "site": "site_id"}}
195+
)
196+
entry.add_to_hass(hass)
197+
198+
result = await hass.config_entries.flow.async_init(
199+
UNIFI_DOMAIN, context={"source": "user"}
200+
)
201+
202+
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
203+
assert result["step_id"] == "user"
204+
205+
aioclient_mock.get("https://1.2.3.4:1234", status=302)
206+
207+
aioclient_mock.post(
208+
"https://1.2.3.4:1234/api/login",
209+
json={"data": "login successful", "meta": {"rc": "ok"}},
210+
headers={"content-type": "application/json"},
211+
)
212+
213+
aioclient_mock.get(
214+
"https://1.2.3.4:1234/api/self/sites",
215+
json={
216+
"data": [{"desc": "Site name", "name": "site_id"}],
217+
"meta": {"rc": "ok"},
218+
},
219+
headers={"content-type": "application/json"},
220+
)
221+
222+
result = await hass.config_entries.flow.async_configure(
223+
result["flow_id"],
224+
user_input={
225+
CONF_HOST: "1.2.3.4",
226+
CONF_USERNAME: "username",
227+
CONF_PASSWORD: "password",
228+
CONF_PORT: 1234,
229+
CONF_VERIFY_SSL: True,
230+
},
231+
)
232+
233+
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
234+
assert result["reason"] == "no_local_user"
188235

189236

190237
async def test_flow_fails_user_credentials_faulty(hass, aioclient_mock):

0 commit comments

Comments
 (0)