Luup Secure Plugins
Micasaverde (Talk | contribs) (→Step by step process of provisioning an external app like a mobile phone) |
Micasaverde (Talk | contribs) |
||
Line 1: | Line 1: | ||
== Overview == | == Overview == | ||
− | MiOS has a secure way of provisioning plugins, which will generally be done for non-free applications. This mechanism can be used equally well for paid-for external apps that communicate with Vera, like a cell phone control, by creating an associated plugin for the app, even if the plugin doesn't do anything. The process of creating the plugin is no different than normal. | + | MiOS has a secure way of provisioning plugins, which will generally be done for non-free applications. This mechanism can be used equally well for paid-for external apps that communicate with Vera, like a cell phone control, by creating an associated plugin for the app, even if the plugin doesn't do anything. The process of creating the plugin is no different than normal. |
+ | |||
+ | Let's say you have a free cell phone app with no restrictions. You still use the same mechanism. Just ask Mios for a plugin ID that is free and unrestricted. It will be empty plugin that does nothing. When you provision your phone, use that plugin in. Provisioning external 3rd party apps, like cell phone controls, is not just for copy protection and financial, it's also done to give the home owner control over what devices are taking control of his system and having a way of restricting that if he wants to. If you try to communicate with a MiOS engine over a local network without being provisioned, you can still do a lot, but certain secure actions, like unlocking doors and disarming alarms won't be processed by the engine if your app isn't provisioned to prevent a security risk. | ||
A provisioned plugin contains 3 fields of data: 'from' and 'to' which are date/time's, and 'limits' which is a free form text field that can be used by the plugin or external app to determine what functionality can be provided. These 3 fields exist both for the plugin itself, and for devices that use the plugin. When registering your app with MiOS you specify what the default values are if a user first installs your plugin without paying for anything. For example, consider that you have a plugin that monitors traffic conditions and costs $3/year to monitor local traffic and $6/year to monitor nation traffic and each homeowner has a 14 day free trial of the plugin, and that the limit code for the trial period is "trial" and for the $3 app is "local" and for the $6 app is "national" or $20 for national lifetime. You would specify with your MiOS Market representative that the default time period is 14 days and the default limit code is "trial". When the user installs the app, the plugin will have provision data where 'from' is the date he installed the plugin, 'to' is 14 days later, and 'limit' is "trial". When the customer pays the $3 or $6 the 'to' field will change to 1 year and the 'limit' will change also, when he pays $20, the 'to' field will become empty. | A provisioned plugin contains 3 fields of data: 'from' and 'to' which are date/time's, and 'limits' which is a free form text field that can be used by the plugin or external app to determine what functionality can be provided. These 3 fields exist both for the plugin itself, and for devices that use the plugin. When registering your app with MiOS you specify what the default values are if a user first installs your plugin without paying for anything. For example, consider that you have a plugin that monitors traffic conditions and costs $3/year to monitor local traffic and $6/year to monitor nation traffic and each homeowner has a 14 day free trial of the plugin, and that the limit code for the trial period is "trial" and for the $3 app is "local" and for the $6 app is "national" or $20 for national lifetime. You would specify with your MiOS Market representative that the default time period is 14 days and the default limit code is "trial". When the user installs the app, the plugin will have provision data where 'from' is the date he installed the plugin, 'to' is 14 days later, and 'limit' is "trial". When the customer pays the $3 or $6 the 'to' field will change to 1 year and the 'limit' will change also, when he pays $20, the 'to' field will become empty. | ||
Line 44: | Line 46: | ||
Plugins which are done in Luup are automatically handled by the MIOS engine and the user interface. Here is a step-by-step example showing how you might handle setup of a mobile phone app. This is just a sample showing one possible implementation. | Plugins which are done in Luup are automatically handled by the MIOS engine and the user interface. Here is a step-by-step example showing how you might handle setup of a mobile phone app. This is just a sample showing one possible implementation. | ||
− | + | 1. Ask the user for his myMiOS username. Let's say it's "john" and then call http://sta1.mios.com/locator.php?username=john and if you don't get a reply because the server or network is down, try the backup server: http://sta2.mios.com/locator.php?username=john | |
+ | |||
+ | This will return a list of all the MiOS engines which you can control, both those which are on the local network that you can control directly, and those that the user "john" can control through the mios.com portal. The return value is a list of serial numbers, internal IP addresses, user names, main port forward server, backup port forward server, as follows: | ||
+ | |||
+ | 10998,192.168.2.10,alfonso,fwd2.mios.com,fwd1.mios.com | ||
+ | 11020,,john,fwd2.mios.com,fwd1.mios.com | ||
+ | 10266,192.168.2.117,,, | ||
+ | 10267,192.168.2.119,john,fwd2.mios.com,fwd1.mios.com | ||
+ | 10267,192.168.2.119,alfonso,fwd2.mios.com,fwd1.mios.com | ||
+ | |||
+ | This means you can control 4 MiOS engines. 10998, 10266 and 10267 are on the local network as evidenced by Internal IP not being blank. 10998 you can control either locally at 192.168.2.10 or through the mios portal with the user 'alfonso'. Note that the user you passed in 'john' cannot control 10998 through the mios portal, but it's shown to you anyway since it's on the same local network as your phone. 11020 is not on your local network, so the IP is blank, but john can control it through the forward servers. 10266 can only be controlled locally with no remote access. 10267 is one john can control either locally or remotely. Since it's on the local network and alfonso is another username that can control it remotely, you are shown it too. | ||
+ | |||
+ | So all your control options are available with locator.php. How you want to present this to the user is up to the developer, but, presumably you could just show the user all 5 rows and let him pick the one he wants. You can leave the username=x off the URL, and in this case the return list will only include those engines on the local network. | ||
+ | |||
+ | Your app should now prompt the user for the password if there is a username associated. For example, 10266 will allow you to provision an app without a username/password since the user, during setup, explicitly decided to bypass the default security settings in the wizard which create a username/password, and he chose to have an unsecure system. The 10266 example is a rare exception since a user who does this is exposing himself to risk in case someone gets on his local area network they can control his door locks, etc. So, generally, users will follow the setup wizard's advice and protect their box with a username/password. This is the only case in which the commands to create a plugin will actually work without a username/password, otherwise they'll return a 'not authorized' error. | ||
+ | |||
+ | Assume you've got a cell phone app that talks to the engine over wi-fi and the homeowner doesn't have internet access. In this case you can discover the engine by doing a upnp scan or asking the user to enter the IP of the engine. He still probably protected his engine with a username/password so you should still prompt him for this, but, allow him to continue with an empty user/pass just in case he did create a wide open system like 10266. | ||
+ | |||
+ | 2a. Assuming that your going to track individual phones, you'll want to create a device for this phone. So you'll need to come up with a unique ID for the phone. It can be whatever the phone provides, such as a mac address, phone number, etc., or, if the phone doesn't provide anything, generate a unique id on your own, perhaps a timestamp, which you should try to install in some persistent memory on the phone so that if your app is uninstalled and reinstalled it will retain the same ID and not get provisioned twice. The id must have normal characters only: A-Z a-z 0-9 space - _ : and to ensure it does not conflict with the ID of another developer's device, preface it with some unique characters for your app, like: ACME_PHONE_CO_2135551212. Then, to create the device, call: | ||
+ | |||
+ | for a local IP: http://ip:3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreateDevice&deviceType=anytype&internalID=ACME_PHONE_CO_2135551212&Description=phoneapp&PluginNum=144&Reload=1&NoDupId=1&AesKey=abc123&username=john&password=johnspassword | ||
+ | |||
+ | for a remote IP over the portal you have to ask the user for his password and call: https://[fwd_server]/username/password/serial_number/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreateDevice&deviceType=anytype&internalID=ACME_PHONE_CO_2135551212&Description=phoneapp&PluginNum=144&Reload=1&NoDupId=1&AesKey=abc123&username=john&password=johnspassword | ||
+ | |||
+ | Note that the URL is exactly the same whether communicating locally or remotely, only the first part changes. This also means that if you're communicating remotely, the username/password will get passed on the URL twice; once in the first set of /'s, which is validated by the portal, and also in the URL which is validated by the engine. | ||
− | + | Note that you have 2 forward servers. The engine will only keep one connection active at a time, and will try to always keep the connection active to the first server and will revert to the second server only if the first one is down, and, if that happens, it will go back to the first server as soon as it comes alive again. So always use the first server and only try the second one if the first fails. If you're using the second server and it fails at any time, go back to the first one. | |
− | + | Note the deviceType is a UPnP device type, and you can simply make one up for your device however you should use the standard upnp naming convention for clarity, like: urn:schemas-acmephone-com:device:AndroidApp:1. The PluginNum is the id of the plugin which you created in the MiOS market, Reload=1 means the MiOS engine will reload after creating the device so it gets initialized, NoDup=1 means that if there's already a device with the ID ACME_PHONE_CO_2135551212 then CreateDevice will return the existing device id rather than create a new one. AesKey can be a Aes128 or Aes256 key which you generate at random and that you want the MiOS engine to use to encrypt communication with you to prevent man in the middle hacks to fake provisioning. If submitting an AesKey, you should use https:// to send this to the MiOS engine, which will store it in an encrypted state. There is no way to retrieve the AesKey again however you can change it by calling CreateDevice again with the same internalID, NoDup=1 and a new key. See the section on security below. This request will return the device id of the newly created device. When the MiOS engine reloads it will download the plugin information and the provision data, like this: http://download1.mios.com/get_plugin_json.php?plugin=144&ap=10266 (ap is the serial number). This will have the default provisioning for now. An icon will appear in the toolbox that allows the user to purchase and configure the plugin. You can also make the request using the myMiOS server. | |
− | 2b. If you did not want to get a device id for the phone, and just want to provision the plugin for this MiOS engine, meaning only the plugin is provisioned and you won't be tracking devices, then just use CreatePlugin instead of CreateDevice: http:// | + | 2b. If you did not want to get a device id for the phone, and just want to provision the plugin for this MiOS engine, meaning only the plugin is provisioned and you won't be tracking devices, then just use CreatePlugin instead of CreateDevice: http[s]://...../data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreatePlugin&PluginNum=144&AesKey=abc123&username=john&password=johnspassword. |
− | 3. Wait until the engine finishing reloading and downloading the plugin and then retrieve the provision data with lu_provision. user_data will contain the timestamp for the plugin which will show when the plugin data last changed so you know when to retrieve lu_provision again if the plugin provisioning has changed. | + | 3. Wait until the engine finishing reloading and downloading the plugin and then you'll see a Provision tag in the user_data for your device with the provision codes. You can also retrieve the provision data by itself with /data_request?id=lu_provision&PluginNum=yyy&DeviceNum=xxx where DeviceNum is optional and only used if you created a device ID for your phone. user_data will contain the timestamp for the plugin which will show when the plugin data last changed so you know when to retrieve lu_provision again if the plugin provisioning has changed. |
− | == | + | == Copy protection == |
− | To prevent users from circumventing the provisioning process the MiOS engine retrieves the plugin data using https and verifies the public key of the mios server. Additionally your | + | To prevent users from circumventing the provisioning process the MiOS engine retrieves the plugin data using https and verifies the public key of the mios server. Additionally if you want to prevent a man in the middle attack where the user tries to circumvent your provision process, you can optionally supply an AesKey which means that lu_provision will always return the provision data encrypted with your key to provide you assurance you're talking to the real MiOS engine. This is the AesKey argument on the CreateDevice and CreatePlugin examples, and is optional. |
Revision as of 21:07, 12 May 2010
Overview
MiOS has a secure way of provisioning plugins, which will generally be done for non-free applications. This mechanism can be used equally well for paid-for external apps that communicate with Vera, like a cell phone control, by creating an associated plugin for the app, even if the plugin doesn't do anything. The process of creating the plugin is no different than normal.
Let's say you have a free cell phone app with no restrictions. You still use the same mechanism. Just ask Mios for a plugin ID that is free and unrestricted. It will be empty plugin that does nothing. When you provision your phone, use that plugin in. Provisioning external 3rd party apps, like cell phone controls, is not just for copy protection and financial, it's also done to give the home owner control over what devices are taking control of his system and having a way of restricting that if he wants to. If you try to communicate with a MiOS engine over a local network without being provisioned, you can still do a lot, but certain secure actions, like unlocking doors and disarming alarms won't be processed by the engine if your app isn't provisioned to prevent a security risk.
A provisioned plugin contains 3 fields of data: 'from' and 'to' which are date/time's, and 'limits' which is a free form text field that can be used by the plugin or external app to determine what functionality can be provided. These 3 fields exist both for the plugin itself, and for devices that use the plugin. When registering your app with MiOS you specify what the default values are if a user first installs your plugin without paying for anything. For example, consider that you have a plugin that monitors traffic conditions and costs $3/year to monitor local traffic and $6/year to monitor nation traffic and each homeowner has a 14 day free trial of the plugin, and that the limit code for the trial period is "trial" and for the $3 app is "local" and for the $6 app is "national" or $20 for national lifetime. You would specify with your MiOS Market representative that the default time period is 14 days and the default limit code is "trial". When the user installs the app, the plugin will have provision data where 'from' is the date he installed the plugin, 'to' is 14 days later, and 'limit' is "trial". When the customer pays the $3 or $6 the 'to' field will change to 1 year and the 'limit' will change also, when he pays $20, the 'to' field will become empty.
Some plugins create devices which may require provisioning of each device in addition to or instead of the provisioning for the main plugin. For example, a cell phone app may have a price of $10 for the first cell phone and $2 for each additional one. In this case, unlike the traffic example which only created a plugin entry, a device entry will be created for each phone and provision from/to/limit fields will exist for each phone as well as each device. Again, there could be a free trial period which uses the 'limit' code, and the first phone could use the 'included' code, and the subsequent phones could have 'extra' limit code. The limit codes are entirely free-form and it's up to you to decide what they mean.
The provisioning process itself is done by automated systems, contact MiOS to setup an account for payment and establish the terms of provisioning.
To retrieve the provisioning status of your plugin request the provisioning info as an lu request, like: http://ip:3480/data_request?id=lu_provision&PluginNum=x&DeviceNum=y. Note DeviceNum is optional, and whether specified or not, you'll receive in json format the all the provisioning info for the plugin and any associated devices. If DeviceNum is specified the encryption key for the device will be used to encrypt the return value, rather than using the key for the plugin itself. Encryption is optional (see section below). The format of lu_provision is:
{ "AllowMultiple": 1, "Title": "Test Secure Plugin", "timestamp": 1270155180, "Provision": { "from": 1270155180, "to": 1272697200, "limits": "trial", "Devices": [ { "from": 1272697200, "to": 1272783600, "limits": "trial", "device_num": "2", "altid": "2135551212" }, { "limits": "", "device_num": "8", "altid": "3105001000" } ] }, "Version": "0.50", "id": 144, }
Note this means the plugin itself has a provision from 1270155180 to 1272697200 (unix timestamp) with limit "trial", and the 2 devices which are associated with the plugin have their own provision data.
Step by step process of provisioning an external app like a mobile phone
Plugins which are done in Luup are automatically handled by the MIOS engine and the user interface. Here is a step-by-step example showing how you might handle setup of a mobile phone app. This is just a sample showing one possible implementation.
1. Ask the user for his myMiOS username. Let's say it's "john" and then call http://sta1.mios.com/locator.php?username=john and if you don't get a reply because the server or network is down, try the backup server: http://sta2.mios.com/locator.php?username=john
This will return a list of all the MiOS engines which you can control, both those which are on the local network that you can control directly, and those that the user "john" can control through the mios.com portal. The return value is a list of serial numbers, internal IP addresses, user names, main port forward server, backup port forward server, as follows:
10998,192.168.2.10,alfonso,fwd2.mios.com,fwd1.mios.com 11020,,john,fwd2.mios.com,fwd1.mios.com 10266,192.168.2.117,,, 10267,192.168.2.119,john,fwd2.mios.com,fwd1.mios.com 10267,192.168.2.119,alfonso,fwd2.mios.com,fwd1.mios.com
This means you can control 4 MiOS engines. 10998, 10266 and 10267 are on the local network as evidenced by Internal IP not being blank. 10998 you can control either locally at 192.168.2.10 or through the mios portal with the user 'alfonso'. Note that the user you passed in 'john' cannot control 10998 through the mios portal, but it's shown to you anyway since it's on the same local network as your phone. 11020 is not on your local network, so the IP is blank, but john can control it through the forward servers. 10266 can only be controlled locally with no remote access. 10267 is one john can control either locally or remotely. Since it's on the local network and alfonso is another username that can control it remotely, you are shown it too.
So all your control options are available with locator.php. How you want to present this to the user is up to the developer, but, presumably you could just show the user all 5 rows and let him pick the one he wants. You can leave the username=x off the URL, and in this case the return list will only include those engines on the local network.
Your app should now prompt the user for the password if there is a username associated. For example, 10266 will allow you to provision an app without a username/password since the user, during setup, explicitly decided to bypass the default security settings in the wizard which create a username/password, and he chose to have an unsecure system. The 10266 example is a rare exception since a user who does this is exposing himself to risk in case someone gets on his local area network they can control his door locks, etc. So, generally, users will follow the setup wizard's advice and protect their box with a username/password. This is the only case in which the commands to create a plugin will actually work without a username/password, otherwise they'll return a 'not authorized' error.
Assume you've got a cell phone app that talks to the engine over wi-fi and the homeowner doesn't have internet access. In this case you can discover the engine by doing a upnp scan or asking the user to enter the IP of the engine. He still probably protected his engine with a username/password so you should still prompt him for this, but, allow him to continue with an empty user/pass just in case he did create a wide open system like 10266.
2a. Assuming that your going to track individual phones, you'll want to create a device for this phone. So you'll need to come up with a unique ID for the phone. It can be whatever the phone provides, such as a mac address, phone number, etc., or, if the phone doesn't provide anything, generate a unique id on your own, perhaps a timestamp, which you should try to install in some persistent memory on the phone so that if your app is uninstalled and reinstalled it will retain the same ID and not get provisioned twice. The id must have normal characters only: A-Z a-z 0-9 space - _ : and to ensure it does not conflict with the ID of another developer's device, preface it with some unique characters for your app, like: ACME_PHONE_CO_2135551212. Then, to create the device, call:
for a remote IP over the portal you have to ask the user for his password and call: https://[fwd_server]/username/password/serial_number/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreateDevice&deviceType=anytype&internalID=ACME_PHONE_CO_2135551212&Description=phoneapp&PluginNum=144&Reload=1&NoDupId=1&AesKey=abc123&username=john&password=johnspassword
Note that the URL is exactly the same whether communicating locally or remotely, only the first part changes. This also means that if you're communicating remotely, the username/password will get passed on the URL twice; once in the first set of /'s, which is validated by the portal, and also in the URL which is validated by the engine.
Note that you have 2 forward servers. The engine will only keep one connection active at a time, and will try to always keep the connection active to the first server and will revert to the second server only if the first one is down, and, if that happens, it will go back to the first server as soon as it comes alive again. So always use the first server and only try the second one if the first fails. If you're using the second server and it fails at any time, go back to the first one.
Note the deviceType is a UPnP device type, and you can simply make one up for your device however you should use the standard upnp naming convention for clarity, like: urn:schemas-acmephone-com:device:AndroidApp:1. The PluginNum is the id of the plugin which you created in the MiOS market, Reload=1 means the MiOS engine will reload after creating the device so it gets initialized, NoDup=1 means that if there's already a device with the ID ACME_PHONE_CO_2135551212 then CreateDevice will return the existing device id rather than create a new one. AesKey can be a Aes128 or Aes256 key which you generate at random and that you want the MiOS engine to use to encrypt communication with you to prevent man in the middle hacks to fake provisioning. If submitting an AesKey, you should use https:// to send this to the MiOS engine, which will store it in an encrypted state. There is no way to retrieve the AesKey again however you can change it by calling CreateDevice again with the same internalID, NoDup=1 and a new key. See the section on security below. This request will return the device id of the newly created device. When the MiOS engine reloads it will download the plugin information and the provision data, like this: http://download1.mios.com/get_plugin_json.php?plugin=144&ap=10266 (ap is the serial number). This will have the default provisioning for now. An icon will appear in the toolbox that allows the user to purchase and configure the plugin. You can also make the request using the myMiOS server.
2b. If you did not want to get a device id for the phone, and just want to provision the plugin for this MiOS engine, meaning only the plugin is provisioned and you won't be tracking devices, then just use CreatePlugin instead of CreateDevice: http[s]://...../data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=CreatePlugin&PluginNum=144&AesKey=abc123&username=john&password=johnspassword.
3. Wait until the engine finishing reloading and downloading the plugin and then you'll see a Provision tag in the user_data for your device with the provision codes. You can also retrieve the provision data by itself with /data_request?id=lu_provision&PluginNum=yyy&DeviceNum=xxx where DeviceNum is optional and only used if you created a device ID for your phone. user_data will contain the timestamp for the plugin which will show when the plugin data last changed so you know when to retrieve lu_provision again if the plugin provisioning has changed.
Copy protection
To prevent users from circumventing the provisioning process the MiOS engine retrieves the plugin data using https and verifies the public key of the mios server. Additionally if you want to prevent a man in the middle attack where the user tries to circumvent your provision process, you can optionally supply an AesKey which means that lu_provision will always return the provision data encrypted with your key to provide you assurance you're talking to the real MiOS engine. This is the AesKey argument on the CreateDevice and CreatePlugin examples, and is optional.