diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java index 739782b18..3c3fe6211 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java @@ -53,6 +53,7 @@ public class UniFiBindingConstants { public static final String PARAMETER_PORT = "port"; public static final String PARAMETER_USERNAME = "username"; public static final String PARAMETER_PASSWORD = "password"; + public static final String PARAMETER_UNIFIOS = "unifios"; public static final String PARAMETER_SITE = "site"; public static final String PARAMETER_CID = "cid"; } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiControllerThingConfig.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiControllerThingConfig.java index 78d80fe72..4f05ba298 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiControllerThingConfig.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiControllerThingConfig.java @@ -33,6 +33,8 @@ public class UniFiControllerThingConfig { private int refresh = 10; + private boolean unifios = false; + public String getHost() { return host; } @@ -53,6 +55,10 @@ public class UniFiControllerThingConfig { return refresh; } + public boolean isUniFiOS() { + return unifios; + } + public boolean isValid() { return StringUtils.isNotBlank(host) && StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password); } @@ -60,6 +66,6 @@ public class UniFiControllerThingConfig { @Override public String toString() { return "UniFiControllerConfig{host = " + host + ", port = " + port + ", username = " + username - + ", password = *****, refresh = " + refresh + "}"; + + ", password = *****, refresh = " + refresh + ", unifios = " + unifios + "}"; } } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiController.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiController.java index 967e2943f..0c47a7a3b 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiController.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiController.java @@ -65,14 +65,21 @@ public class UniFiController { private final String password; + private final boolean unifios; + + private String csrfToken; + private final Gson gson; - public UniFiController(HttpClient httpClient, String host, int port, String username, String password) { + public UniFiController(HttpClient httpClient, String host, int port, String username, String password, + boolean unifios) { this.httpClient = httpClient; this.host = host; this.port = port; this.username = username; this.password = password; + this.unifios = unifios; + this.csrfToken = ""; UniFiSiteInstanceCreator siteInstanceCreator = new UniFiSiteInstanceCreator(this); UniFiDeviceInstanceCreator deviceInstanceCreator = new UniFiDeviceInstanceCreator(this); UniFiClientInstanceCreator clientInstanceCreator = new UniFiClientInstanceCreator(this); @@ -96,8 +103,10 @@ public class UniFiController { } public void login() throws UniFiException { + csrfToken = ""; + UniFiControllerRequest req = newRequest(Void.class); - req.setPath("/api/login"); + req.setPath(unifios ? "/api/auth/login" : "/api/login"); req.setBodyParameter("username", username); req.setBodyParameter("password", password); // scurb: Changed strict = false to make blocking feature work @@ -107,8 +116,9 @@ public class UniFiController { } public void logout() throws UniFiException { + csrfToken = ""; UniFiControllerRequest req = newRequest(Void.class); - req.setPath("/logout"); + req.setPath(unifios ? "/api/auth/logout" : "/logout"); executeRequest(req); } @@ -172,7 +182,7 @@ public class UniFiController { protected void block(UniFiClient client, boolean blocked) throws UniFiException { UniFiControllerRequest req = newRequest(Void.class); - req.setPath("/api/s/" + client.getSite().getName() + "/cmd/stamgr"); + req.setAPIPath("/api/s/" + client.getSite().getName() + "/cmd/stamgr"); req.setBodyParameter("cmd", blocked ? "block-sta" : "unblock-sta"); req.setBodyParameter("mac", client.getMac()); executeRequest(req); @@ -180,7 +190,7 @@ public class UniFiController { protected void reconnect(UniFiClient client) throws UniFiException { UniFiControllerRequest req = newRequest(Void.class); - req.setPath("/api/s/" + client.getSite().getName() + "/cmd/stamgr"); + req.setAPIPath("/api/s/" + client.getSite().getName() + "/cmd/stamgr"); req.setBodyParameter("cmd", "kick-sta"); req.setBodyParameter("mac", client.getMac()); executeRequest(req); @@ -189,13 +199,14 @@ public class UniFiController { // Internal API private UniFiControllerRequest newRequest(Class responseType) { - return new UniFiControllerRequest<>(responseType, gson, httpClient, host, port); + return new UniFiControllerRequest<>(responseType, gson, httpClient, host, port, csrfToken, unifios); } private @Nullable T executeRequest(UniFiControllerRequest request) throws UniFiException { T result; try { result = request.execute(); + csrfToken = request.getCsrfToken(); } catch (UniFiExpiredSessionException e) { login(); result = executeRequest(request); @@ -208,7 +219,7 @@ public class UniFiController { private UniFiSiteCache getSites() throws UniFiException { UniFiControllerRequest req = newRequest(UniFiSite[].class); - req.setPath("/api/self/sites"); + req.setAPIPath("/api/self/sites"); UniFiSite[] sites = executeRequest(req); UniFiSiteCache cache = new UniFiSiteCache(); if (sites != null) { @@ -231,7 +242,7 @@ public class UniFiController { private UniFiDeviceCache getDevices(UniFiSite site) throws UniFiException { UniFiControllerRequest req = newRequest(UniFiDevice[].class); - req.setPath("/api/s/" + site.getName() + "/stat/device"); + req.setAPIPath("/api/s/" + site.getName() + "/stat/device"); UniFiDevice[] devices = executeRequest(req); UniFiDeviceCache cache = new UniFiDeviceCache(); if (devices != null) { @@ -254,7 +265,7 @@ public class UniFiController { private UniFiClientCache getClients(UniFiSite site) throws UniFiException { UniFiControllerRequest req = newRequest(UniFiClient[].class); - req.setPath("/api/s/" + site.getName() + "/stat/sta"); + req.setAPIPath("/api/s/" + site.getName() + "/stat/sta"); UniFiClient[] clients = executeRequest(req); UniFiClientCache cache = new UniFiClientCache(); if (clients != null) { @@ -277,7 +288,7 @@ public class UniFiController { private UniFiClientCache getInsights(UniFiSite site) throws UniFiException { UniFiControllerRequest req = newRequest(UniFiClient[].class); - req.setPath("/api/s/" + site.getName() + "/stat/alluser"); + req.setAPIPath("/api/s/" + site.getName() + "/stat/alluser"); req.setQueryParameter("within", 168); // scurb: Changed to 7 days. UniFiClient[] clients = executeRequest(req); UniFiClientCache cache = new UniFiClientCache(); diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiControllerRequest.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiControllerRequest.java index a3bd6a76a..a56d955f4 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiControllerRequest.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/model/UniFiControllerRequest.java @@ -83,6 +83,10 @@ public class UniFiControllerRequest { private String path = "/"; + private final boolean unifios; + + private String csrfToken; + private Map queryParameters = new HashMap<>(); private Map bodyParameters = new HashMap<>(); @@ -91,12 +95,23 @@ public class UniFiControllerRequest { // Public API - public UniFiControllerRequest(Class resultType, Gson gson, HttpClient httpClient, String host, int port) { + public UniFiControllerRequest(Class resultType, Gson gson, HttpClient httpClient, String host, int port, + String csrfToken, boolean unifios) { this.resultType = resultType; this.gson = gson; this.httpClient = httpClient; this.host = host; this.port = port; + this.csrfToken = csrfToken; + this.unifios = unifios; + } + + public void setAPIPath(String relativePath) { + if (unifios) { + this.path = "/proxy/network" + relativePath; + } else { + this.path = relativePath; + } } public void setPath(String path) { @@ -136,6 +151,11 @@ public class UniFiControllerRequest { if (logger.isTraceEnabled()) { logger.trace("<< {} {} \n{}", status, HttpStatus.getMessage(status), prettyPrintJson(content)); } + + String csrfToken = response.getHeaders().get("X-CSRF-Token"); + if (csrfToken != null && !csrfToken.isEmpty()) { + this.csrfToken = csrfToken; + } break; case HttpStatus.BAD_REQUEST_400: throw new UniFiInvalidCredentialsException("Invalid Credentials"); @@ -184,6 +204,10 @@ public class UniFiControllerRequest { return response; } + public String getCsrfToken() { + return csrfToken; + } + private Request newRequest() { HttpMethod method = bodyParameters.isEmpty() ? HttpMethod.GET : HttpMethod.POST; HttpURI uri = new HttpURI(HttpScheme.HTTPS.asString(), host, port, path); @@ -198,6 +222,10 @@ public class UniFiControllerRequest { StandardCharsets.UTF_8); request = request.content(content); } + + if (!csrfToken.isEmpty()) + request.header("x-csrf-token", this.csrfToken); + return request; } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiControllerThingHandler.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiControllerThingHandler.java index 183cabdba..56376136b 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiControllerThingHandler.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiControllerThingHandler.java @@ -88,7 +88,7 @@ public class UniFiControllerThingHandler extends BaseBridgeHandler { logger.debug("Initializing the UniFi Controller Handler with config = {}", config); try { controller = new UniFiController(httpClient, config.getHost(), config.getPort(), config.getUsername(), - config.getPassword()); + config.getPassword(), config.isUniFiOS()); controller.start(); updateStatus(ONLINE); } catch (UniFiInvalidHostException e) { diff --git a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml index 4ceb58792..7632c4b5a 100644 --- a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml @@ -21,6 +21,10 @@ Port of the UniFi Controller 8443 + + + If the UniFi Controller is running on UniFi OS. + The username to access the UniFi Controller.