From 46dd9792c1972490d11c9aca53d47314a396f5b2 Mon Sep 17 00:00:00 2001 From: Simon Spielmann Date: Thu, 15 Dec 2022 09:18:11 +0100 Subject: [PATCH] [icloud] Rework authentication to reflect changes in iCloud API (#13691) * Implement Authentication (WIP) * Validation Code accepted * Refactor session state * RefreshClient working * Implement session persistence in openhab store * Integration in binding * Remove persistent cookies, which break authentication * Bugfixing * Add code configuration to UI * Improve documentation, error-handling and cleanup * Rework auth order * Rework auth process * Add 2-FA-auth to documentation * Set bridge to online if data refresh works * Case-sensitive rename ICloudAPIResponseException * Include authentication in refresh flow * Fix regression for data not being updated * Fix typo in i18n props * Fix review and checkstyle. * More javadoc, new RetryException * Introduce @NonNullByDefault * Introduce server for RetryException, add NonNullbyDefault, fix warnings * Rework for contribution, e.g. null checks, ... * Fix checkstyle * Move JsonUtils to utilities package * Async initialize bridge handler. * Report Device OFFLINE if Bridge is OFFLINE * Set bridge thing status to UNKOWN in init * Move refresh init into async init * Cancel init task in dispose Also-by: Leo Siepel Signed-off-by: Simon Spielmann --- bundles/org.openhab.binding.icloud/README.md | 22 +- .../internal/FindMyIPhoneServiceManager.java | 79 ++++ .../internal/ICloudApiResponseException.java | 46 +++ .../internal/ICloudBindingConstants.java | 5 +- .../icloud/internal/ICloudConnection.java | 93 ----- .../ICloudDeviceInformationListener.java | 2 +- .../ICloudDeviceInformationParser.java | 36 -- .../icloud/internal/ICloudHandlerFactory.java | 54 +-- .../icloud/internal/ICloudService.java | 329 +++++++++++++++++ .../icloud/internal/ICloudSession.java | 239 +++++++++++++ .../icloud/internal/RetryException.java | 36 ++ .../ICloudAccountThingConfiguration.java | 1 + .../discovery/ICloudDeviceDiscovery.java | 2 +- .../icloud/internal/handler/AuthState.java | 46 +++ .../handler/ICloudAccountBridgeHandler.java | 336 +++++++++++++++--- .../internal/handler/ICloudDeviceHandler.java | 88 +++-- .../response/ICloudAccountDataResponse.java | 2 +- .../json/response/ICloudAccountUserInfo.java | 2 +- .../json/response/ICloudDeviceFeatures.java | 180 ++++++++++ .../response/ICloudDeviceInformation.java | 2 +- .../json/response/ICloudDeviceLocation.java | 2 +- .../json/response/ICloudServerContext.java | 2 +- .../response/ICloudServerContextTimezone.java | 2 +- .../request/ICloudAccountDataRequest.java | 64 ---- .../request/ICloudFindMyDeviceRequest.java | 37 -- .../json/response/ICloudDeviceFeatures.java | 153 -------- .../internal/utilities/CustomCookieStore.java | 90 +++++ .../utilities/ICloudTextTranslator.java | 10 +- .../icloud/internal/utilities/JsonUtils.java | 75 ++++ .../icloud/internal/utilities/ListUtil.java | 61 ++++ .../icloud/internal/utilities/Pair.java | 66 ++++ .../resources/OH-INF/i18n/iCloud.properties | 2 + .../resources/OH-INF/thing/thing-types.xml | 4 + .../openhab/binding/icloud/TestICloud.java | 97 +++++ 34 files changed, 1733 insertions(+), 532 deletions(-) create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/FindMyIPhoneServiceManager.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/ICloudApiResponseException.java delete mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/ICloudConnection.java delete mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/ICloudDeviceInformationParser.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/ICloudService.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/ICloudSession.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/RetryException.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/handler/AuthState.java rename bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/{ => handler/dto}/json/response/ICloudAccountDataResponse.java (95%) rename bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/{ => handler/dto}/json/response/ICloudAccountUserInfo.java (95%) create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/handler/dto/json/response/ICloudDeviceFeatures.java rename bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/{ => handler/dto}/json/response/ICloudDeviceInformation.java (98%) rename bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/{ => handler/dto}/json/response/ICloudDeviceLocation.java (96%) rename bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/{ => handler/dto}/json/response/ICloudServerContext.java (98%) rename bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/{ => handler/dto}/json/response/ICloudServerContextTimezone.java (94%) delete mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/json/request/ICloudAccountDataRequest.java delete mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/json/request/ICloudFindMyDeviceRequest.java delete mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/json/response/ICloudDeviceFeatures.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/utilities/CustomCookieStore.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/utilities/JsonUtils.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/utilities/ListUtil.java create mode 100644 bundles/org.openhab.binding.icloud/src/main/java/org/openhab/binding/icloud/internal/utilities/Pair.java create mode 100644 bundles/org.openhab.binding.icloud/src/test/java/org/openhab/binding/icloud/TestICloud.java diff --git a/bundles/org.openhab.binding.icloud/README.md b/bundles/org.openhab.binding.icloud/README.md index aa2216783a25e..8a8ad621ebd1e 100644 --- a/bundles/org.openhab.binding.icloud/README.md +++ b/bundles/org.openhab.binding.icloud/README.md @@ -29,6 +29,12 @@ The account Thing, more precisely the account Bridge, represents one Apple iClou The account can be connected to multiple Apple devices which are represented as Things below the Bridge, see the example below. You may create multiple account Things for multiple accounts. +If your Apple account has 2-factor-authentication enabled configuration requires two steps. +First start by adding the Apple ID and password to your account thing configuration. +You will receive a notification with a code on one of your Apple devices then. +Add this code to the code parameter of the thing then and wait. +The binding should be reinitialized and perform the authentication. + ### Device Thing A device is identified by the device ID provided by Apple. @@ -62,7 +68,7 @@ The following channels are available (if supported by the device): ### icloud.things ```php -Bridge icloud:account:myaccount [appleId="mail@example.com", password="secure", refreshTimeInMinutes=5] +Bridge icloud:account:myaccount [appleId="mail@example.com", password="secure", code="123456", refreshTimeInMinutes=5] { Thing device myiPhone8 "iPhone 8" @ "World" [deviceId="VIRG9FsrvXfE90ewVBA1H5swtwEQePdXVjHq3Si6pdJY2Cjro8QlreHYVGSUzuWV"] } @@ -76,14 +82,14 @@ The information _@ "World"_ is optional. ```php Group iCloud_Group "iPhone" -String iPhone_BatteryStatus "Battery Status [%s]" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:batteryStatus"} -Number iPhone_BatteryLevel "Battery Level [%d %%]" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:batteryLevel"} -Switch iPhone_FindMyPhone "Trigger Find My iPhone" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:findMyPhone", autoupdate="false"} -Switch iPhone_Refresh "Force iPhone Refresh" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:location", autoupdate="false"} -Location iPhone_Location "Coordinates" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:location"} -Number iPhone_LocationAccuracy "Coordinates Accuracy [%.0f m]" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:locationAccuracy"} +String iPhone_BatteryStatus "Battery Status [%s]" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:batteryStatus"} +Number iPhone_BatteryLevel "Battery Level [%d %%]" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:batteryLevel"} +Switch iPhone_FindMyPhone "Trigger Find My iPhone" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:findMyPhone", autoupdate="false"} +Switch iPhone_Refresh "Force iPhone Refresh" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:location", autoupdate="false"} +Location iPhone_Location "Coordinates" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:location"} +Number iPhone_LocationAccuracy "Coordinates Accuracy [%.0f m]" (iCloud_Group) {channel="icloud:device:myaccount:myiPhone8:locationAccuracy"} DateTime iPhone_LocationLastUpdate "Last Update [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]"